Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Atproto Lexicon Contracts Laravel Package

revolution/atproto-lexicon-contracts

PHP contracts for AT Protocol lexicons: typed interfaces and value objects that keep atproto records, XRPC payloads, and schema handling consistent across Laravel apps. Code against stable abstractions instead of raw arrays.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require revolution/atproto-lexicon-contracts

This is a contracts-only package: auto-generated PHP interfaces and enums derived from ATProto lexicon JSON schemas. There is no HTTP client, no serializer, and no runtime behaviour bundled — you bring (or install) an implementation. That distinction shapes everything below.

Where to look first:

  1. vendor/revolution/atproto-lexicon-contracts/composer.json — confirm the PHP version floor (enums require 8.1+), the PSR-4 root, and whether a generation script is shipped.
  2. src/ — namespaces typically mirror ATProto NSIDs in PascalCase, e.g. App\Bsky\Feed\Post, Com\Atproto\Repo\CreateRecord. Skim the tree before writing code; the shape tells you what's covered.
  3. README.md and any CHANGELOG — auto-generated packages change shape with upstream lexicon revisions, so check the last update date against the ATProto lexicons you care about.

First use case: stop writing 'app.bsky.feed.post' as a string literal. Type a record creation flow against the generated interface and the $type enum:

use Revolution\Atproto\Lexicon\App\Bsky\Feed\Post;

final class CreatePost
{
    public function __construct(private Post $record) {}

    public function payload(): array
    {
        return [
            'repo'       => auth()->user()->did,
            'collection' => $this->record::NSID, // or the enum case
            'record'     => $this->record->toArray(),
        ];
    }
}

The win is compile-time safety on field names and enum values, not transport.

Implementation Patterns

Interface-first services with container bindings. These are contracts; Laravel won't autowire a concrete implementation unless you tell it to. Register bindings in a service provider and type-hint interfaces in your services and jobs. This keeps your app decoupled from whichever runtime package (the author's sibling packages, symfony/serializer, cuyz/valinor, or hand-rolled hydrators) you end up using.

Enum-driven validation and casts. The generated enums map lexicon knownValues. Use them in FormRequest rules via Rule::enum(PostType::class) and as Eloquent cast targets for any column storing a known-value string. This gives you validation, IDE completion, and DB consistency from one source of truth.

DTO hydration at the boundary. Keep JSON↔contract mapping in one small mapper class. Controllers, jobs, and listeners should never call json_decode and index into arrays for ATProto payloads. When the lexicon updates, you change the mapper, not forty call sites.

Record builders. Wrap multi-field records in a fluent builder that returns a contract instance. ATProto records have many optional and union-typed fields (facets, embed, langs); builders keep controllers thin and make test fixtures trivial.

Queue boundaries. Interface instances are not serializable by default. Before dispatching a job, convert records to plain arrays (or implement Serializable on your concrete classes). Re-hydrate on the worker side.

Pin the version. Auto-generated code churns. Use an exact constraint ("1.2.3", not "^1.2") and review diffs on upgrade — a lexicon revision can rename or remove an interface without a semver major.

Testing. Mock the generated interfaces in unit tests; assert on enum cases rather than magic strings. For integration tests against a real PDS, treat the contracts as fixtures, not as an HTTP layer.

Gotchas and Tips

  • Never edit vendor/. The code is generated; any local patch is lost on the next composer update. If a schema is wrong for your use case, wrap it or open an upstream issue.
  • Contracts do nothing on their own. No PDS calls, no auth, no DID resolution, no CBOR. Budget for a runtime layer before you commit to this package.
  • Unknown enum values will throw. ATProto explicitly permits values outside knownValues (the "open enum" pattern). Prefer ::tryFrom() and retain the raw string when persisting, or you'll crash on records from newer clients.
  • $type discriminators and unions. Lexicon unions map to interfaces with a discriminator accessor. Handle the "unknown union member" branch defensively; treat it as an open extension point, not an error.
  • Deep namespaces. Generated PSR-4 paths are verbose (\Revolution\Atproto\Lexicon\App\Bsky\Feed\Post\Embed\External). Alias imports aggressively; run composer dump-autoload -o — the class count is large and classmap authoring speeds up boot.
  • Laravel specifics. Enums work as Eloquent casts and in validation rules on PHP 8.1+; interfaces require explicit container bindings and will not resolve from auto-discovery alone. There is no facade, no config file, no artisan command.
  • Maturity warning. Zero stars, zero dependents, score 0.1. Read the generation script and the most recent commit before depending on it in production. It is best treated as an alpha-grade schema mirror — useful, but you are the first-line debugger.
  • Debugging tip. If hydration "silently" produces empty objects, you're almost certainly instantiating a stub or a mismatched implementation rather than the generated contract. var_dump($record::class) and array_keys((array) $record) will expose the mismatch faster than stepping through the serializer.

Extension points. The only real extension surfaces are your own concrete classes implementing the generated interfaces, your own enum-to-string mapping layer, and your serializer's normalizer configuration. There are no service providers to extend and no events to listen to inside the package itself.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast