{"id":28517514,"url":"https://github.com/invokable/statusphere","last_synced_at":"2026-05-18T22:05:46.974Z","repository":{"id":271500874,"uuid":"912358877","full_name":"invokable/statusphere","owner":"invokable","description":"Statusphere Laravel edition","archived":false,"fork":false,"pushed_at":"2026-04-29T06:15:52.000Z","size":418,"stargazers_count":1,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-30T06:40:07.856Z","etag":null,"topics":["atproto","bluesky","statusphere"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/invokable.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["invokable"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":null}},"created_at":"2025-01-05T11:03:00.000Z","updated_at":"2026-04-25T22:44:05.000Z","dependencies_parsed_at":"2025-01-08T06:30:54.697Z","dependency_job_id":"d9a1f5c8-25a3-435c-adc1-fec71024f75d","html_url":"https://github.com/invokable/statusphere","commit_stats":null,"previous_names":["puklipo/statusphere","invokable/statusphere"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/invokable/statusphere","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/invokable%2Fstatusphere","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/invokable%2Fstatusphere/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/invokable%2Fstatusphere/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/invokable%2Fstatusphere/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/invokable","download_url":"https://codeload.github.com/invokable/statusphere/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/invokable%2Fstatusphere/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32457110,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T22:27:22.272Z","status":"online","status_checked_at":"2026-04-30T02:00:05.929Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["atproto","bluesky","statusphere"],"created_at":"2025-06-09T05:08:42.184Z","updated_at":"2026-04-30T06:40:11.693Z","avatar_url":"https://github.com/invokable.png","language":"PHP","funding_links":["https://github.com/sponsors/invokable"],"categories":[],"sub_categories":[],"readme":"# Statusphere Laravel edition\n\n\u003ckbd\u003e![statusphere](https://github.com/user-attachments/assets/d3eeee73-9e2b-453b-b58d-d115a841031f)\u003c/kbd\u003e\n\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/invokable/statusphere)\n\n## About\n\nStatusphere is a sample application demonstrating how to use the [Laravel Bluesky package](https://github.com/invokable/laravel-bluesky) to integrate with the Bluesky social network. It follows the official [statusphere](https://github.com/bluesky-social/statusphere-example-app).\n\n\u003e [!CAUTION]\n\u003e The working Live server has been discontinued.\n\u003e This code should still be useful as a reference.\n\n## Technology Stack\n\n- Laravel 12.x\n- Tailwind 4.x\n- Livewire 3.x / Volt 1.6.x\n- laravel-bluesky 1.x\n- No WebSocket/Firehose (Many PHP developers are not familiar with using supervisor, so WebSockets are not used)\n\n## AT Protocol Integration\n\nStatusphere demonstrates key AT Protocol application patterns by implementing a decentralized emoji status system. The application follows the official [statusphere](https://github.com/bluesky-social/statusphere-example-app) using Laravel and the `laravel-bluesky` package.\n\n### OAuth Authentication\n\nUsers authenticate using their Bluesky credentials via OAuth flow:\n\n- **Login Route**: Users enter their Bluesky handle (e.g., `alice.bsky.social`)\n- **OAuth Flow**: Laravel Socialite with Bluesky driver handles the authentication\n- **Session Management**: OAuth tokens are stored in Laravel sessions for API access\n- **User Creation**: User records are created/updated with DID, handle, and profile information\n\nThe authentication is handled in the `/login` and `/callback` routes, which create an `OAuthSession` that provides authenticated access to the user's AT Protocol repository.\n\n### Custom Data Schema\n\nStatusphere publishes emoji status records using a custom AT Protocol schema:\n\n- **Collection**: `com.puklipo.statusphere.status` \n- **Schema**: Records contain `status` (emoji) and `createdAt` (timestamp)\n- **Record Keys**: Uses TID (Timestamp Identifier) for unique, time-ordered keys\n- **Validation**: Laravel validation ensures only valid emojis from the configured list\n\nThe status records are defined in the `Status` class using the `laravel-bluesky` package's `Recordable` interface.\n\n### Publishing Data\n\nWhen users select an emoji status:\n\n1. **Validation**: Emoji is validated against the configured list in `config/statusphere.php`\n2. **OAuth Check**: Session tokens are verified and refreshed if needed  \n3. **Record Creation**: A new status record is created with the selected emoji\n4. **AT Protocol Write**: Record is published to the user's repository using `Bluesky::putRecord()`\n5. **UI Update**: Livewire components update reactively to show the new status\n\nThe publishing flow is implemented in the `create-status` Livewire component, which provides real-time feedback and error handling.\n\n### Fetching User Data\n\nThe application retrieves and displays user information:\n\n- **Profile Data**: Fetches user profiles from their repositories for display names and avatars\n- **Status History**: Retrieves the user's previous status records using `Bluesky::listRecords()`\n- **Real-time Updates**: Livewire provides reactive updates when new statuses are created\n- **Timeline Display**: Shows chronological status updates with user attribution\n\nUser data is accessed through the authenticated OAuth session, allowing read access to the user's AT Protocol repository.\n\n### Event Processing\n\nThe application architecture is designed with consideration for AT Protocol event processing:\n\n- **OAuth-Focused**: The primary implementation uses OAuth-based user interactions\n- **No WebSockets**: As noted in the Technology Stack section, WebSockets/Firehose are intentionally not used\n- **Reference Implementation**: The codebase includes reference patterns for those who wish to implement event processing\n- **Future Extensibility**: The architecture allows for adding Bluesky Firehose integration if needed\n\nNote: The current implementation prioritizes simplicity and accessibility for PHP developers who may not be familiar with WebSocket infrastructure.\n\n### Development Features\n\n- **Local Development**: OAuth posting is disabled locally; use `php artisan bsky:create-status` command instead\n- **Error Handling**: Comprehensive error display for OAuth and API failures  \n- **Validation**: Both client-side and server-side validation of emoji selections\n- **Session Management**: Automatic token refresh and re-authentication when needed\n\n## Getting Started\n\n```bash\ngit clone https://github.com/invokable/statusphere.git\ncd statusphere\ncp .env.example .env\ncomposer install\ncomposer run post-create-project-cmd\nnpm install\nnpm run build\n```\n\n### OAuth Configuration\n\nFor Bluesky OAuth authentication, you need to create a private key. This is required before using any OAuth functionality and is the only configuration needed (no client_id or client_secret registration with Bluesky is required).\n\nGenerate a new private key with:\n\n```bash\nphp artisan bluesky:new-private-key\n```\n\nThe command will output a URL-safe base64 encoded key like this:\n```\nPlease set this private key in .env\n\nBLUESKY_OAUTH_PRIVATE_KEY=\"...url-safe base64 encoded key...\"\n```\n\nCopy and paste this key into your `.env` file:\n\n```\n// .env\n\nBLUESKY_OAUTH_PRIVATE_KEY=\"...\"\n```\n\n### App Password Configuration\n\nDue to OAuth limitations, posting from local environments is not supported with OAuth authentication. Instead, you need to use App Password authentication for local development and testing. Configure your Bluesky account credentials:\n\n```\n// .env\n\nBLUESKY_IDENTIFIER=***.bsky.social\nBLUESKY_APP_PASSWORD=****-****-****-****\n```\n\nFor local development, use the following command to create status updates:\n\n```bash\nphp artisan bsky:create-status\n```\n\nThis command uses App Password authentication to post status updates to your Bluesky account.\n\nFinally, start with the Laravel local server command. You can view it at http://localhost:8000.\n\n```bash\nphp artisan serve\n```\n\n## Advanced Usage\n\nIf you want to create a more official-like implementation, you can also use WebSockets to receive and store data.\nThe laravel-bluesky package supports both Firehose and Jetstream, but Jetstream is easier to use when you only need data from specific collections like in this case.\nNote that this Jetstream is Bluesky's Jetstream, not Laravel's Jetstream with the same name, which can be confusing.\nYou can check what kind of data is received on GitHub:\nhttps://github.com/bluesky-social/jetstream\n\n\nRun the command specifying the collection continuously using Supervisor:\n```shell\nphp artisan bluesky:ws start -C com.puklipo.statusphere.status\n```\n\nWhen data is received, a `JetstreamCommitMessage` event is fired, which can be captured by a Listener and saved to the database:\n\n```shell\nphp artisan make:listener StatusListener\n```\n\n```php:app/Listeners/StatusListener.php\nnamespace App\\Listeners;\n\nuse App\\Record\\Status;\nuse Revolution\\Bluesky\\Events\\Jetstream\\JetstreamCommitMessage;\n\nclass StatusListener\n{\n    /**\n     * Create the event listener.\n     */\n    public function __construct()\n    {\n        //\n    }\n\n    /**\n     * Handle the event.\n     */\n    public function handle(JetstreamCommitMessage $event): void\n    {\n        if ($event-\u003eoperation !== 'create') {\n            return;\n        }\n\n        $collection = data_get($event-\u003emessage, 'commit.collection');\n        if ($collection !== Status::NSID) {\n            return;\n        }\n\n        $did = data_get($event-\u003emessage, 'did');\n        $status = data_get($event-\u003emessage, 'commit.record.status');\n        $createdAt = data_get($event-\u003emessage, 'commit.record.createdAt');\n\n        // Save status to database\n    }\n}\n```\n\nIf you actually use this approach, other parts of the application would need to be modified as well.\nThis is just for explanation purposes in the advanced section, so no further implementation is provided.\n\nWhen deploying to production, terminate with `stop` and configure Supervisor to automatically restart:\n```shell\nphp artisan bluesky:ws stop\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finvokable%2Fstatusphere","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finvokable%2Fstatusphere","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finvokable%2Fstatusphere/lists"}