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 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 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 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:
- Spec compliance - We follow the AT Protocol specs for handles, CIDs, and other formats
- Strict schema validation - We catch invalid schemas early (constraint validation)
- Flexible schema authoring - We allow inline types as the spec permits
- Full type support - We support token and ref types that @atproto/lexicon doesn't handle