Maintain local ⭤ remote in sync with automatic AT Protocol parity for Laravel (alpha & unstable)
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add package foundation

+245 -9
+15 -9
composer.json
··· 1 1 { 2 2 "name": "socialdept/atp-parity", 3 - "description": ":package_description", 3 + "description": "AT Protocol record mapping and sync for Laravel Eloquent models", 4 4 "license": "MIT", 5 5 "authors": [ 6 6 { ··· 10 10 } 11 11 ], 12 12 "homepage": "https://github.com/socialdept/atp-parity", 13 - "keywords": ["Laravel", "AtpReplicator"], 13 + "keywords": ["Laravel", "AT Protocol", "Bluesky", "ATP", "Parity", "Sync"], 14 14 "require": { 15 - "illuminate/support": "~9" 15 + "php": "^8.2", 16 + "illuminate/support": "^10.0|^11.0|^12.0", 17 + "illuminate/database": "^10.0|^11.0|^12.0", 18 + "socialdept/atp-schema": "^0.3", 19 + "socialdept/atp-client": "^0.0", 20 + "socialdept/atp-resolver": "^1.1", 21 + "socialdept/atp-signals": "^1.1" 16 22 }, 17 23 "require-dev": { 18 - "../../../vendor/phpunit/phpunit": "~9.0", 19 - "orchestra/testbench": "~7" 24 + "phpunit/phpunit": "^10.0|^11.0", 25 + "orchestra/testbench": "^8.0|^9.0|^10.0" 20 26 }, 21 27 "autoload": { 22 28 "psr-4": { 23 - "SocialDept\\AtpReplicator\\": "src/" 29 + "SocialDept\\AtpParity\\": "src/" 24 30 } 25 31 }, 26 32 "autoload-dev": { 27 33 "psr-4": { 28 - "SocialDept\\AtpReplicator\\Tests\\": "tests" 34 + "SocialDept\\AtpParity\\Tests\\": "tests" 29 35 } 30 36 }, 31 37 "extra": { 32 38 "laravel": { 33 39 "providers": [ 34 - "SocialDept\\AtpReplicator\\AtpReplicatorServiceProvider" 40 + "SocialDept\\AtpParity\\ParityServiceProvider" 35 41 ], 36 42 "aliases": { 37 - "AtpReplicator": "SocialDept\\AtpReplicator\\Facades\\AtpReplicator" 43 + "Parity": "SocialDept\\AtpParity\\Facades\\Parity" 38 44 } 39 45 } 40 46 }
+105
config/parity.php
··· 1 + <?php 2 + 3 + return [ 4 + /* 5 + |-------------------------------------------------------------------------- 6 + | Record Mappers 7 + |-------------------------------------------------------------------------- 8 + | 9 + | List of RecordMapper classes to automatically register. Each mapper 10 + | handles bidirectional conversion between an AT Protocol record DTO 11 + | and an Eloquent model. 12 + | 13 + */ 14 + 'mappers' => [ 15 + // App\AtpMappers\PostMapper::class, 16 + // App\AtpMappers\ProfileMapper::class, 17 + ], 18 + 19 + /* 20 + |-------------------------------------------------------------------------- 21 + | AT Protocol Metadata Columns 22 + |-------------------------------------------------------------------------- 23 + | 24 + | The column names used to store AT Protocol metadata on models. 25 + | 26 + */ 27 + 'columns' => [ 28 + 'uri' => 'atp_uri', 29 + 'cid' => 'atp_cid', 30 + ], 31 + 32 + /* 33 + |-------------------------------------------------------------------------- 34 + | Import Configuration 35 + |-------------------------------------------------------------------------- 36 + | 37 + | Settings for importing historical AT Protocol records to your database. 38 + | 39 + */ 40 + 'import' => [ 41 + // Records per page when listing from PDS 42 + 'page_size' => 100, 43 + 44 + // Delay between pages in milliseconds (rate limiting) 45 + 'page_delay' => 100, 46 + 47 + // Queue name for import jobs 48 + 'queue' => 'default', 49 + 50 + // Database table for storing import state 51 + 'state_table' => 'parity_import_states', 52 + ], 53 + 54 + /* 55 + |-------------------------------------------------------------------------- 56 + | Sync Filtering 57 + |-------------------------------------------------------------------------- 58 + | 59 + | Control which firehose events get synced to your database. 60 + | 61 + */ 62 + 'sync' => [ 63 + // Only sync records from these DIDs (null = all DIDs) 64 + 'dids' => null, 65 + 66 + // Only sync these operations: 'create', 'update', 'delete' (null = all) 67 + 'operations' => null, 68 + 69 + // Custom filter callback: function(SignalEvent $event): bool 70 + // Return true to sync the event, false to skip it 71 + 'filter' => null, 72 + ], 73 + 74 + /* 75 + |-------------------------------------------------------------------------- 76 + | Conflict Resolution 77 + |-------------------------------------------------------------------------- 78 + | 79 + | Strategy for handling conflicts between local and remote changes. 80 + | 81 + */ 82 + 'conflicts' => [ 83 + // Strategy: 'remote', 'local', 'newest', 'manual' 84 + 'strategy' => env('PARITY_CONFLICT_STRATEGY', 'remote'), 85 + 86 + // Database table for pending conflicts (manual resolution) 87 + 'table' => 'parity_conflicts', 88 + 89 + // Notifiable class or callback for conflict notifications 90 + 'notify' => null, 91 + ], 92 + 93 + /* 94 + |-------------------------------------------------------------------------- 95 + | Collection Discovery 96 + |-------------------------------------------------------------------------- 97 + | 98 + | Settings for discovering users with records in specific collections. 99 + | 100 + */ 101 + 'discovery' => [ 102 + // Relay URL for discovery queries 103 + 'relay' => env('ATP_RELAY_URL', 'https://bsky.network'), 104 + ], 105 + ];
+23
src/Facades/Parity.php
··· 1 + <?php 2 + 3 + namespace SocialDept\AtpParity\Facades; 4 + 5 + use Illuminate\Support\Facades\Facade; 6 + use SocialDept\AtpParity\Contracts\RecordMapper; 7 + use SocialDept\AtpParity\MapperRegistry; 8 + 9 + /** 10 + * @method static void register(RecordMapper $mapper) 11 + * @method static RecordMapper|null forRecord(string $recordClass) 12 + * @method static RecordMapper|null forModel(string $modelClass) 13 + * @method static RecordMapper|null forLexicon(string $nsid) 14 + * 15 + * @see MapperRegistry 16 + */ 17 + class Parity extends Facade 18 + { 19 + protected static function getFacadeAccessor(): string 20 + { 21 + return 'parity'; 22 + } 23 + }
+102
src/ParityServiceProvider.php
··· 1 + <?php 2 + 3 + namespace SocialDept\AtpParity; 4 + 5 + use Illuminate\Support\ServiceProvider; 6 + use SocialDept\AtpParity\Commands\DiscoverCommand; 7 + use SocialDept\AtpParity\Commands\ExportCommand; 8 + use SocialDept\AtpParity\Commands\ImportCommand; 9 + use SocialDept\AtpParity\Commands\ImportStatusCommand; 10 + use SocialDept\AtpParity\Discovery\DiscoveryService; 11 + use SocialDept\AtpParity\Export\ExportService; 12 + use SocialDept\AtpParity\Import\ImportService; 13 + use SocialDept\AtpParity\Publish\PublishService; 14 + use SocialDept\AtpParity\Support\RecordHelper; 15 + 16 + class ParityServiceProvider extends ServiceProvider 17 + { 18 + public function boot(): void 19 + { 20 + $this->registerConfiguredMappers(); 21 + 22 + if ($this->app->runningInConsole()) { 23 + $this->bootForConsole(); 24 + } 25 + } 26 + 27 + public function register(): void 28 + { 29 + $this->mergeConfigFrom(__DIR__.'/../config/parity.php', 'parity'); 30 + 31 + $this->app->singleton(MapperRegistry::class); 32 + $this->app->alias(MapperRegistry::class, 'parity'); 33 + 34 + $this->app->singleton(RecordHelper::class, function ($app) { 35 + return new RecordHelper($app->make(MapperRegistry::class)); 36 + }); 37 + 38 + $this->app->singleton(ImportService::class, function ($app) { 39 + return new ImportService($app->make(MapperRegistry::class)); 40 + }); 41 + 42 + $this->app->singleton(PublishService::class, function ($app) { 43 + return new PublishService($app->make(MapperRegistry::class)); 44 + }); 45 + 46 + $this->app->singleton(DiscoveryService::class, function ($app) { 47 + return new DiscoveryService($app->make(ImportService::class)); 48 + }); 49 + 50 + $this->app->singleton(ExportService::class, function ($app) { 51 + return new ExportService( 52 + $app->make(MapperRegistry::class), 53 + $app->make(ImportService::class) 54 + ); 55 + }); 56 + } 57 + 58 + /** 59 + * Register mappers defined in config. 60 + */ 61 + protected function registerConfiguredMappers(): void 62 + { 63 + $registry = $this->app->make(MapperRegistry::class); 64 + 65 + foreach (config('parity.mappers', []) as $mapperClass) { 66 + if (class_exists($mapperClass)) { 67 + $registry->register($this->app->make($mapperClass)); 68 + } 69 + } 70 + } 71 + 72 + protected function bootForConsole(): void 73 + { 74 + $this->publishes([ 75 + __DIR__.'/../config/parity.php' => config_path('parity.php'), 76 + ], 'parity-config'); 77 + 78 + $this->publishes([ 79 + __DIR__.'/../database/migrations' => database_path('migrations'), 80 + ], 'parity-migrations'); 81 + 82 + $this->commands([ 83 + DiscoverCommand::class, 84 + ExportCommand::class, 85 + ImportCommand::class, 86 + ImportStatusCommand::class, 87 + ]); 88 + } 89 + 90 + public function provides(): array 91 + { 92 + return [ 93 + 'parity', 94 + MapperRegistry::class, 95 + RecordHelper::class, 96 + ImportService::class, 97 + PublishService::class, 98 + DiscoveryService::class, 99 + ExportService::class, 100 + ]; 101 + } 102 + }