A plain JavaScript validator for AT Protocol lexicon schemas
at main 148 lines 5.3 kB view raw view rendered
1# Comparison with @atproto/lexicon 2 3This document describes the behavioral differences between lexicon.js and @atproto/lexicon (the official TypeScript implementation). 4 5## Summary 6 7When comparing against @atproto/lexicon, there are ~44 behavioral differences. These fall into several categories. 8 9--- 10 11## Category 1: Schema Constraint Validation 12 13**Our behavior:** Validate that schema constraints are logically valid. 14**@atproto behavior:** Does not perform these checks. 15 16| Test | What we check | 17|------|---------------| 18| `string-invalid-length-constraints` | minLength <= maxLength | 19| `string-invalid-negative-minLength` | minLength >= 0 | 20| `string-invalid-negative-maxLength` | maxLength >= 0 | 21| `string-invalid-negative-minGraphemes` | minGraphemes >= 0 | 22| `string-invalid-negative-maxGraphemes` | maxGraphemes >= 0 | 23| `integer-invalid-range-constraints` | minimum <= maximum | 24| `array-invalid-length-constraints` | minLength <= maxLength | 25| `bytes-invalid-max-less-than-min` | minLength <= maxLength | 26| `bytes-invalid-negative-min` | minLength >= 0 | 27| `bytes-invalid-negative-max` | maxLength >= 0 | 28| `blob-invalid-mime-no-slash` | accept MIME types have / | 29| `blob-invalid-partial-wildcard` | accept patterns are valid | 30| `blob-invalid-zero-maxsize` | maxSize > 0 | 31| `object-invalid-nullable-not-in-properties` | nullable fields exist in properties | 32 33**Rationale:** Catching invalid schemas early prevents runtime confusion. 34 35--- 36 37## Category 2: Inline Type Definitions 38 39**Our behavior:** Allow inline object/union type definitions in schemas. 40**@atproto behavior:** Requires all complex types to be defined as named refs. 41 42| Test | What we allow | 43|------|---------------| 44| `object-valid-nested` | `{ type: 'object', properties: { inner: { type: 'object', ... } } }` | 45| `array-valid-object-items` | `{ type: 'array', items: { type: 'object', ... } }` | 46| `array-valid-nested-array` | `{ type: 'array', items: { type: 'array', ... } }` | 47| `union-valid-open-empty-refs` | `{ type: 'union', refs: [] }` | 48| `union-valid-with-refs` | Union with local refs | 49| `union-valid-closed-with-refs` | Closed union with refs | 50| `ref-valid-local` | Local ref `#defName` | 51| `params-valid-*` (7 tests) | Various params configurations | 52| `subscription-valid-*` (3 tests) | Various subscription configurations | 53 54**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. 55 56--- 57 58## Category 3: Blob Data Constraint Validation 59 60**Our behavior:** Validate blob constraints at data validation time. 61**@atproto behavior:** Does not validate blob constraints. 62 63| Test | What we validate | 64|------|------------------| 65| `blob-data-invalid-unaccepted-mime` | Blob MIME type matches schema `accept` | 66| `blob-data-invalid-exceeds-maxSize` | Blob size <= schema `maxSize` | 67 68**Rationale:** Schema constraints should be enforced at validation time. 69 70--- 71 72## Category 4: Token Type Support 73 74**Our behavior:** Support token type. 75**@atproto behavior:** Throws "Unexpected lexicon type: token". 76 77| Test | 78|------| 79| `token-data-valid-simple-string` | 80| `token-data-valid-local-ref` | 81 82**Rationale:** Token is a valid lexicon type per the spec. 83 84--- 85 86## Category 5: Unknown Type Validation 87 88**Our behavior:** Reject structured types (arrays, blob objects, bytes objects) for unknown type. 89**@atproto behavior:** Accepts these values. 90 91| Test | What we reject | 92|------|----------------| 93| `unknown-data-invalid-array` | Arrays for unknown type | 94| `unknown-data-invalid-bytes-object` | `{ $bytes: ... }` objects | 95| `unknown-data-invalid-blob-object` | `{ $type: 'blob', ... }` objects | 96 97**Rationale:** Unknown should be primitive JSON values, not complex IPLD types. 98 99--- 100 101## Category 6: Format Validation - Handles 102 103**Our behavior:** Reject reserved TLDs (.local, .localhost). 104**@atproto behavior:** Accepts these handles. 105 106| Test | Handle value | 107|------|--------------| 108| `handle-invalid-local-tld` | `user.local` | 109| `handle-invalid-localhost-tld` | `app.localhost` | 110 111**Rationale:** The [AT Protocol Handle spec](https://atproto.com/specs/handle) explicitly lists `.local` and `.localhost` as disallowed TLDs. 112 113--- 114 115## Category 7: Format Validation - CID 116 117**Our behavior:** Reject CIDv0, require CIDv1. 118**@atproto behavior:** Accepts CIDv0. 119 120| Test | CID value | 121|------|-----------| 122| `cid-invalid-qmb-prefix` | `QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR` (CIDv0) | 123 124**Rationale:** The [AT Protocol Data Model spec](https://atproto.com/specs/data-model) lists only CIDv1 as a "blessed" format. 125 126--- 127 128## Category 8: Ref Type in Data Validation 129 130**Our behavior:** Support ref resolution in data validation. 131**@atproto behavior:** Throws "Unexpected lexicon type: ref". 132 133| Test | 134|------| 135| `ref-data-valid-nested-chain` | 136 137**Rationale:** Refs should be resolvable during data validation. 138 139--- 140 141## Design Philosophy 142 143lexicon.js prioritizes: 144 1451. **Spec compliance** - We follow the AT Protocol specs for handles, CIDs, and other formats 1462. **Strict schema validation** - We catch invalid schemas early (constraint validation) 1473. **Flexible schema authoring** - We allow inline types as the spec permits 1484. **Full type support** - We support token and ref types that @atproto/lexicon doesn't handle