Parse and validate AT Protocol Lexicons with DTO generation for Laravel
1
fork

Configure Feed

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

Define core contracts and exceptions

+548
+44
src/Contracts/BlobHandler.php
··· 1 + <?php 2 + 3 + namespace SocialDept\Schema\Contracts; 4 + 5 + use Illuminate\Http\UploadedFile; 6 + use SocialDept\Schema\Data\BlobReference; 7 + 8 + interface BlobHandler 9 + { 10 + /** 11 + * Upload blob and create reference. 12 + */ 13 + public function upload(UploadedFile $file): BlobReference; 14 + 15 + /** 16 + * Upload blob from path. 17 + */ 18 + public function uploadFromPath(string $path): BlobReference; 19 + 20 + /** 21 + * Upload blob from content. 22 + */ 23 + public function uploadFromContent(string $content, string $mimeType): BlobReference; 24 + 25 + /** 26 + * Download blob content. 27 + */ 28 + public function download(BlobReference $blob): string; 29 + 30 + /** 31 + * Generate signed URL for blob. 32 + */ 33 + public function url(BlobReference $blob): string; 34 + 35 + /** 36 + * Check if blob exists in storage. 37 + */ 38 + public function exists(BlobReference $blob): bool; 39 + 40 + /** 41 + * Delete blob from storage. 42 + */ 43 + public function delete(BlobReference $blob): bool; 44 + }
+33
src/Contracts/DataGenerator.php
··· 1 + <?php 2 + 3 + namespace SocialDept\Schema\Contracts; 4 + 5 + use SocialDept\Schema\Data\LexiconDocument; 6 + 7 + interface DataGenerator 8 + { 9 + /** 10 + * Generate PHP class files from Lexicon definition. 11 + */ 12 + public function generate(LexiconDocument $schema): string; 13 + 14 + /** 15 + * Generate and write class file to disk. 16 + */ 17 + public function generateAndSave(LexiconDocument $schema, string $outputPath): string; 18 + 19 + /** 20 + * Generate class content without writing to disk. 21 + */ 22 + public function preview(LexiconDocument $schema): string; 23 + 24 + /** 25 + * Set the base namespace for generated classes. 26 + */ 27 + public function setBaseNamespace(string $namespace): void; 28 + 29 + /** 30 + * Set the output path for generated classes. 31 + */ 32 + public function setOutputPath(string $path): void; 33 + }
+28
src/Contracts/LexiconParser.php
··· 1 + <?php 2 + 3 + namespace SocialDept\Schema\Contracts; 4 + 5 + use SocialDept\Schema\Data\LexiconDocument; 6 + 7 + interface LexiconParser 8 + { 9 + /** 10 + * Parse raw Lexicon JSON into structured objects. 11 + */ 12 + public function parse(string $json): LexiconDocument; 13 + 14 + /** 15 + * Parse Lexicon from array data. 16 + */ 17 + public function parseArray(array $data): LexiconDocument; 18 + 19 + /** 20 + * Validate Lexicon schema structure. 21 + */ 22 + public function validate(array $data): bool; 23 + 24 + /** 25 + * Resolve $ref references to other schemas. 26 + */ 27 + public function resolveReference(string $ref, LexiconDocument $context): mixed; 28 + }
+28
src/Contracts/LexiconResolver.php
··· 1 + <?php 2 + 3 + namespace SocialDept\Schema\Contracts; 4 + 5 + use SocialDept\Schema\Data\LexiconDocument; 6 + 7 + interface LexiconResolver 8 + { 9 + /** 10 + * Resolve NSID to Lexicon schema via DNS and XRPC. 11 + */ 12 + public function resolve(string $nsid): LexiconDocument; 13 + 14 + /** 15 + * Perform DNS TXT lookup for _lexicon.{authority}. 16 + */ 17 + public function lookupDns(string $authority): ?string; 18 + 19 + /** 20 + * Retrieve schema via XRPC from PDS. 21 + */ 22 + public function retrieveSchema(string $pdsEndpoint, string $did, string $nsid): array; 23 + 24 + /** 25 + * Check if DNS resolution is enabled. 26 + */ 27 + public function isEnabled(): bool; 28 + }
+30
src/Contracts/LexiconValidator.php
··· 1 + <?php 2 + 3 + namespace SocialDept\Schema\Contracts; 4 + 5 + use SocialDept\Schema\Data\LexiconDocument; 6 + 7 + interface LexiconValidator 8 + { 9 + /** 10 + * Validate data against Lexicon schema. 11 + */ 12 + public function validate(array $data, LexiconDocument $schema): bool; 13 + 14 + /** 15 + * Validate and return errors. 16 + * 17 + * @return array<string, array<string>> 18 + */ 19 + public function validateWithErrors(array $data, LexiconDocument $schema): array; 20 + 21 + /** 22 + * Validate a specific field. 23 + */ 24 + public function validateField(mixed $value, string $field, LexiconDocument $schema): bool; 25 + 26 + /** 27 + * Set validation mode (strict, optimistic, lenient). 28 + */ 29 + public function setMode(string $mode): void; 30 + }
+35
src/Contracts/SchemaRepository.php
··· 1 + <?php 2 + 3 + namespace SocialDept\Schema\Contracts; 4 + 5 + use SocialDept\Schema\Data\LexiconDocument; 6 + 7 + interface SchemaRepository 8 + { 9 + /** 10 + * Find schema by NSID. 11 + */ 12 + public function find(string $nsid): ?LexiconDocument; 13 + 14 + /** 15 + * Load schema from multiple sources. 16 + */ 17 + public function load(string $nsid): LexiconDocument; 18 + 19 + /** 20 + * Check if schema exists. 21 + */ 22 + public function exists(string $nsid): bool; 23 + 24 + /** 25 + * Get all available schema NSIDs. 26 + * 27 + * @return array<string> 28 + */ 29 + public function all(): array; 30 + 31 + /** 32 + * Clear cached schemas. 33 + */ 34 + public function clearCache(?string $nsid = null): void; 35 + }
+33
src/Contracts/TypeMapper.php
··· 1 + <?php 2 + 3 + namespace SocialDept\Schema\Contracts; 4 + 5 + interface TypeMapper 6 + { 7 + /** 8 + * Map Lexicon type to PHP type. 9 + */ 10 + public function toPhpType(string $lexiconType): string; 11 + 12 + /** 13 + * Map Lexicon type to PHPDoc type. 14 + */ 15 + public function toPhpDocType(string $lexiconType): string; 16 + 17 + /** 18 + * Handle union types. 19 + * 20 + * @param array<string> $types 21 + */ 22 + public function unionType(array $types): string; 23 + 24 + /** 25 + * Check if type is nullable. 26 + */ 27 + public function isNullable(array $definition): bool; 28 + 29 + /** 30 + * Resolve type reference. 31 + */ 32 + public function resolveReference(string $ref): string; 33 + }
+50
src/Exceptions/BlobException.php
··· 1 + <?php 2 + 3 + namespace SocialDept\Schema\Exceptions; 4 + 5 + class BlobException extends SchemaException 6 + { 7 + /** 8 + * Create exception for upload failure. 9 + */ 10 + public static function uploadFailed(string $reason): self 11 + { 12 + return static::withContext( 13 + "Blob upload failed: {$reason}", 14 + ['reason' => $reason] 15 + ); 16 + } 17 + 18 + /** 19 + * Create exception for download failure. 20 + */ 21 + public static function downloadFailed(string $cid, string $reason): self 22 + { 23 + return static::withContext( 24 + "Failed to download blob {$cid}: {$reason}", 25 + ['cid' => $cid, 'reason' => $reason] 26 + ); 27 + } 28 + 29 + /** 30 + * Create exception for invalid MIME type. 31 + */ 32 + public static function invalidMimeType(string $mimeType, array $accepted): self 33 + { 34 + return static::withContext( 35 + "Invalid MIME type {$mimeType}. Accepted: " . implode(', ', $accepted), 36 + ['mimeType' => $mimeType, 'accepted' => $accepted] 37 + ); 38 + } 39 + 40 + /** 41 + * Create exception for file size violation. 42 + */ 43 + public static function fileTooLarge(int $size, int $maxSize): self 44 + { 45 + return static::withContext( 46 + "File size {$size} bytes exceeds maximum {$maxSize} bytes", 47 + ['size' => $size, 'maxSize' => $maxSize] 48 + ); 49 + } 50 + }
+39
src/Exceptions/GenerationException.php
··· 1 + <?php 2 + 3 + namespace SocialDept\Schema\Exceptions; 4 + 5 + class GenerationException extends SchemaException 6 + { 7 + /** 8 + * Create exception for generation failure. 9 + */ 10 + public static function failed(string $nsid, string $reason): self 11 + { 12 + return static::withContext( 13 + "Failed to generate Data class for {$nsid}: {$reason}", 14 + ['nsid' => $nsid, 'reason' => $reason] 15 + ); 16 + } 17 + 18 + /** 19 + * Create exception for file write failure. 20 + */ 21 + public static function fileWriteFailed(string $path, string $error): self 22 + { 23 + return static::withContext( 24 + "Failed to write generated file to {$path}: {$error}", 25 + ['path' => $path, 'error' => $error] 26 + ); 27 + } 28 + 29 + /** 30 + * Create exception for unsupported feature. 31 + */ 32 + public static function unsupportedFeature(string $nsid, string $feature): self 33 + { 34 + return static::withContext( 35 + "Unsupported feature in schema {$nsid}: {$feature}", 36 + ['nsid' => $nsid, 'feature' => $feature] 37 + ); 38 + } 39 + }
+53
src/Exceptions/RecordValidationException.php
··· 1 + <?php 2 + 3 + namespace SocialDept\Schema\Exceptions; 4 + 5 + class RecordValidationException extends SchemaException 6 + { 7 + /** 8 + * Validation errors. 9 + */ 10 + protected array $errors = []; 11 + 12 + /** 13 + * Create exception with validation errors. 14 + */ 15 + public static function withErrors(string $nsid, array $errors): self 16 + { 17 + $instance = new static("Record validation failed for {$nsid}"); 18 + $instance->errors = $errors; 19 + $instance->setContext(['nsid' => $nsid, 'errors' => $errors]); 20 + 21 + return $instance; 22 + } 23 + 24 + /** 25 + * Get validation errors. 26 + */ 27 + public function getErrors(): array 28 + { 29 + return $this->errors; 30 + } 31 + 32 + /** 33 + * Create exception for type mismatch. 34 + */ 35 + public static function typeMismatch(string $field, string $expected, string $actual): self 36 + { 37 + return static::withContext( 38 + "Type mismatch for field {$field}: expected {$expected}, got {$actual}", 39 + ['field' => $field, 'expected' => $expected, 'actual' => $actual] 40 + ); 41 + } 42 + 43 + /** 44 + * Create exception for constraint violation. 45 + */ 46 + public static function constraintViolation(string $field, string $constraint, mixed $value): self 47 + { 48 + return static::withContext( 49 + "Constraint violation for field {$field}: {$constraint}", 50 + ['field' => $field, 'constraint' => $constraint, 'value' => $value] 51 + ); 52 + } 53 + }
+39
src/Exceptions/SchemaException.php
··· 1 + <?php 2 + 3 + namespace SocialDept\Schema\Exceptions; 4 + 5 + use Exception; 6 + 7 + class SchemaException extends Exception 8 + { 9 + /** 10 + * Additional context data for the exception. 11 + */ 12 + protected array $context = []; 13 + 14 + /** 15 + * Set context data. 16 + */ 17 + public function setContext(array $context): self 18 + { 19 + $this->context = $context; 20 + 21 + return $this; 22 + } 23 + 24 + /** 25 + * Get context data. 26 + */ 27 + public function getContext(): array 28 + { 29 + return $this->context; 30 + } 31 + 32 + /** 33 + * Create exception with context. 34 + */ 35 + public static function withContext(string $message, array $context = []): self 36 + { 37 + return (new static($message))->setContext($context); 38 + } 39 + }
+28
src/Exceptions/SchemaNotFoundException.php
··· 1 + <?php 2 + 3 + namespace SocialDept\Schema\Exceptions; 4 + 5 + class SchemaNotFoundException extends SchemaException 6 + { 7 + /** 8 + * Create exception for missing NSID. 9 + */ 10 + public static function forNsid(string $nsid): self 11 + { 12 + return static::withContext( 13 + "Schema not found for NSID: {$nsid}", 14 + ['nsid' => $nsid] 15 + ); 16 + } 17 + 18 + /** 19 + * Create exception for missing file. 20 + */ 21 + public static function forFile(string $path): self 22 + { 23 + return static::withContext( 24 + "Schema file not found: {$path}", 25 + ['path' => $path] 26 + ); 27 + } 28 + }
+28
src/Exceptions/SchemaParseException.php
··· 1 + <?php 2 + 3 + namespace SocialDept\Schema\Exceptions; 4 + 5 + class SchemaParseException extends SchemaException 6 + { 7 + /** 8 + * Create exception for invalid JSON. 9 + */ 10 + public static function invalidJson(string $nsid, string $error): self 11 + { 12 + return static::withContext( 13 + "Failed to parse schema JSON for {$nsid}: {$error}", 14 + ['nsid' => $nsid, 'error' => $error] 15 + ); 16 + } 17 + 18 + /** 19 + * Create exception for malformed schema. 20 + */ 21 + public static function malformed(string $nsid, string $reason): self 22 + { 23 + return static::withContext( 24 + "Malformed schema for {$nsid}: {$reason}", 25 + ['nsid' => $nsid, 'reason' => $reason] 26 + ); 27 + } 28 + }
+41
src/Exceptions/SchemaValidationException.php
··· 1 + <?php 2 + 3 + namespace SocialDept\Schema\Exceptions; 4 + 5 + class SchemaValidationException extends SchemaException 6 + { 7 + /** 8 + * Create exception for invalid schema structure. 9 + */ 10 + public static function invalidStructure(string $nsid, array $errors): self 11 + { 12 + $message = "Schema validation failed for {$nsid}:\n" . implode("\n", $errors); 13 + 14 + return static::withContext($message, [ 15 + 'nsid' => $nsid, 16 + 'errors' => $errors, 17 + ]); 18 + } 19 + 20 + /** 21 + * Create exception for missing required field. 22 + */ 23 + public static function missingField(string $nsid, string $field): self 24 + { 25 + return static::withContext( 26 + "Required field missing in schema {$nsid}: {$field}", 27 + ['nsid' => $nsid, 'field' => $field] 28 + ); 29 + } 30 + 31 + /** 32 + * Create exception for invalid lexicon version. 33 + */ 34 + public static function invalidVersion(string $nsid, int $version): self 35 + { 36 + return static::withContext( 37 + "Unsupported lexicon version {$version} in schema {$nsid}", 38 + ['nsid' => $nsid, 'version' => $version] 39 + ); 40 + } 41 + }
+39
src/Exceptions/TypeResolutionException.php
··· 1 + <?php 2 + 3 + namespace SocialDept\Schema\Exceptions; 4 + 5 + class TypeResolutionException extends SchemaException 6 + { 7 + /** 8 + * Create exception for unknown type. 9 + */ 10 + public static function unknownType(string $type): self 11 + { 12 + return static::withContext( 13 + "Unknown Lexicon type: {$type}", 14 + ['type' => $type] 15 + ); 16 + } 17 + 18 + /** 19 + * Create exception for unresolvable reference. 20 + */ 21 + public static function unresolv ableReference(string $ref, string $nsid): self 22 + { 23 + return static::withContext( 24 + "Cannot resolve reference {$ref} in schema {$nsid}", 25 + ['ref' => $ref, 'nsid' => $nsid] 26 + ); 27 + } 28 + 29 + /** 30 + * Create exception for circular reference. 31 + */ 32 + public static function circularReference(string $ref, array $chain): self 33 + { 34 + return static::withContext( 35 + "Circular reference detected: {$ref}", 36 + ['ref' => $ref, 'chain' => $chain] 37 + ); 38 + } 39 + }