# Comparison with @atproto/lexicon This document describes the behavioral differences between lexicon.js and @atproto/lexicon (the official TypeScript implementation). ## Summary When comparing against @atproto/lexicon, there are ~44 behavioral differences. These fall into several categories. --- ## Category 1: Schema Constraint Validation **Our behavior:** Validate that schema constraints are logically valid. **@atproto behavior:** Does not perform these checks. | Test | What we check | |------|---------------| | `string-invalid-length-constraints` | minLength <= maxLength | | `string-invalid-negative-minLength` | minLength >= 0 | | `string-invalid-negative-maxLength` | maxLength >= 0 | | `string-invalid-negative-minGraphemes` | minGraphemes >= 0 | | `string-invalid-negative-maxGraphemes` | maxGraphemes >= 0 | | `integer-invalid-range-constraints` | minimum <= maximum | | `array-invalid-length-constraints` | minLength <= maxLength | | `bytes-invalid-max-less-than-min` | minLength <= maxLength | | `bytes-invalid-negative-min` | minLength >= 0 | | `bytes-invalid-negative-max` | maxLength >= 0 | | `blob-invalid-mime-no-slash` | accept MIME types have / | | `blob-invalid-partial-wildcard` | accept patterns are valid | | `blob-invalid-zero-maxsize` | maxSize > 0 | | `object-invalid-nullable-not-in-properties` | nullable fields exist in properties | **Rationale:** Catching invalid schemas early prevents runtime confusion. --- ## Category 2: Inline Type Definitions **Our behavior:** Allow inline object/union type definitions in schemas. **@atproto behavior:** Requires all complex types to be defined as named refs. | Test | What we allow | |------|---------------| | `object-valid-nested` | `{ type: 'object', properties: { inner: { type: 'object', ... } } }` | | `array-valid-object-items` | `{ type: 'array', items: { type: 'object', ... } }` | | `array-valid-nested-array` | `{ type: 'array', items: { type: 'array', ... } }` | | `union-valid-open-empty-refs` | `{ type: 'union', refs: [] }` | | `union-valid-with-refs` | Union with local refs | | `union-valid-closed-with-refs` | Closed union with refs | | `ref-valid-local` | Local ref `#defName` | | `params-valid-*` (7 tests) | Various params configurations | | `subscription-valid-*` (3 tests) | Various subscription configurations | **Rationale:** The [Lexicon spec](https://atproto.com/specs/lexicon) explicitly allows object properties to contain "any Lexicon field type" including nested objects, arrays, refs, and unions. --- ## Category 3: Blob Data Constraint Validation **Our behavior:** Validate blob constraints at data validation time. **@atproto behavior:** Does not validate blob constraints. | Test | What we validate | |------|------------------| | `blob-data-invalid-unaccepted-mime` | Blob MIME type matches schema `accept` | | `blob-data-invalid-exceeds-maxSize` | Blob size <= schema `maxSize` | **Rationale:** Schema constraints should be enforced at validation time. --- ## Category 4: Token Type Support **Our behavior:** Support token type. **@atproto behavior:** Throws "Unexpected lexicon type: token". | Test | |------| | `token-data-valid-simple-string` | | `token-data-valid-local-ref` | **Rationale:** Token is a valid lexicon type per the spec. --- ## Category 5: Unknown Type Validation **Our behavior:** Reject structured types (arrays, blob objects, bytes objects) for unknown type. **@atproto behavior:** Accepts these values. | Test | What we reject | |------|----------------| | `unknown-data-invalid-array` | Arrays for unknown type | | `unknown-data-invalid-bytes-object` | `{ $bytes: ... }` objects | | `unknown-data-invalid-blob-object` | `{ $type: 'blob', ... }` objects | **Rationale:** Unknown should be primitive JSON values, not complex IPLD types. --- ## Category 6: Format Validation - Handles **Our behavior:** Reject reserved TLDs (.local, .localhost). **@atproto behavior:** Accepts these handles. | Test | Handle value | |------|--------------| | `handle-invalid-local-tld` | `user.local` | | `handle-invalid-localhost-tld` | `app.localhost` | **Rationale:** The [AT Protocol Handle spec](https://atproto.com/specs/handle) explicitly lists `.local` and `.localhost` as disallowed TLDs. --- ## Category 7: Format Validation - CID **Our behavior:** Reject CIDv0, require CIDv1. **@atproto behavior:** Accepts CIDv0. | Test | CID value | |------|-----------| | `cid-invalid-qmb-prefix` | `QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR` (CIDv0) | **Rationale:** The [AT Protocol Data Model spec](https://atproto.com/specs/data-model) lists only CIDv1 as a "blessed" format. --- ## Category 8: Ref Type in Data Validation **Our behavior:** Support ref resolution in data validation. **@atproto behavior:** Throws "Unexpected lexicon type: ref". | Test | |------| | `ref-data-valid-nested-chain` | **Rationale:** Refs should be resolvable during data validation. --- ## Design Philosophy lexicon.js prioritizes: 1. **Spec compliance** - We follow the AT Protocol specs for handles, CIDs, and other formats 2. **Strict schema validation** - We catch invalid schemas early (constraint validation) 3. **Flexible schema authoring** - We allow inline types as the spec permits 4. **Full type support** - We support token and ref types that @atproto/lexicon doesn't handle