@atproto/lex 0.0.8 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @atproto/lex
2
2
 
3
+ ## 0.0.9
4
+
5
+ ### Patch Changes
6
+
7
+ - [#4501](https://github.com/bluesky-social/atproto/pull/4501) [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add an `indexFile` option that allows generating an "index.ts" file that re-exports every tld namespaces.
8
+
9
+ - [#4501](https://github.com/bluesky-social/atproto/pull/4501) [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Export everything from `@atproto/lex-data` and `@atproto/lex-json`
10
+
11
+ - Updated dependencies [[`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98)]:
12
+ - @atproto/lex-builder@0.0.9
13
+ - @atproto/lex-client@0.0.7
14
+ - @atproto/lex-data@0.0.6
15
+ - @atproto/lex-schema@0.0.7
16
+ - @atproto/lex-installer@0.0.9
17
+ - @atproto/lex-json@0.0.6
18
+
3
19
  ## 0.0.8
4
20
 
5
21
  ### Patch Changes
package/README.md CHANGED
@@ -53,7 +53,12 @@ app.bsky.actor.profile.$validate({
53
53
  - [TypeScript Schemas](#typescript-schemas)
54
54
  - [Generated Schema Structure](#generated-schema-structure)
55
55
  - [Type definitions](#type-definitions)
56
+ - [Building data](#building-data)
56
57
  - [Validation Helpers](#validation-helpers)
58
+ - [Data Model](#data-model)
59
+ - [Types](#types)
60
+ - [JSON Encoding](#json-encoding)
61
+ - [DAG-CBOR Encoding](#dag-cbor-encoding)
57
62
  - [Client API](#client-api)
58
63
  - [Creating a Client](#creating-a-client)
59
64
  - [Core Methods](#core-methods)
@@ -61,6 +66,8 @@ app.bsky.actor.profile.$validate({
61
66
  - [Authentication Methods](#authentication-methods)
62
67
  - [Labeler Configuration](#labeler-configuration)
63
68
  - [Low-Level XRPC](#low-level-xrpc)
69
+ - [Blob references](#blob-references)
70
+ - [Utilities](#utilities)
64
71
  - [Advanced Usage](#advanced-usage)
65
72
  - [Workflow Integration](#workflow-integration)
66
73
  - [Tree-Shaking](#tree-shaking)
@@ -89,7 +96,7 @@ This creates:
89
96
 
90
97
  > [!NOTE]
91
98
  >
92
- > The `lex` command might conflict with other binaries intalled on your system.
99
+ > The `lex` command might conflict with other binaries installed on your system.
93
100
  > If that happens, you can also run the CLI using `ts-lex`, `pnpm exec lex` or
94
101
  > `npx @atproto/lex`.
95
102
 
@@ -193,6 +200,7 @@ Options:
193
200
  - `--allowLegacyBlobs` - Allow generating schemas that accept legacy blob references (disabled by default; enable this if you encounter issues while processing records created a long time ago)
194
201
  - `--importExt <ext>` - File extension to use for import statements in generated files (default: `.js`). Use `--importExt ""` to generate extension-less imports
195
202
  - `--fileExt <ext>` - File extension to use for generated files (default: `.ts`)
203
+ - `--indexFile` - Generate an "index" file that re-exports all root-level namespaces (disabled by default)
196
204
 
197
205
  ### Generated Schema Structure
198
206
 
@@ -209,15 +217,25 @@ You can extract TypeScript types from the generated schemas for use in you appli
209
217
  ```typescript
210
218
  import * as app from './lexicons/app.js'
211
219
 
212
- // Extract the type for a post record
213
- type Post = app.bsky.feed.post.Main
220
+ function renderPost(p: app.bsky.feed.post.Main) {
221
+ console.log(p.$type) // 'app.bsky.feed.post'
222
+ console.log(p.text)
223
+ }
224
+ ```
214
225
 
215
- // Use the extracted types
216
- const post: Post = {
217
- $type: 'app.bsky.feed.post',
218
- text: 'Hello, AT Protocol!',
226
+ ### Building data
227
+
228
+ It is recommended to use the generated builders to create data that conforms to the schema. This ensures that all required fields are present.
229
+
230
+ ```typescript
231
+ import * as app from './lexicons/app.js'
232
+
233
+ // variable type will be inferred as "app.bsky.feed.post.Main"
234
+ const post = app.bsky.feed.post.$build({
235
+ // No need to specify $type when using $build
236
+ text: 'Hello, world!',
219
237
  createdAt: new Date().toISOString(),
220
- }
238
+ })
221
239
  ```
222
240
 
223
241
  ### Validation Helpers
@@ -284,6 +302,10 @@ try {
284
302
  }
285
303
  ```
286
304
 
305
+ > [!NOTE]
306
+ >
307
+ > The `$parse` method will apply defaults defined in the schema for optional fields, as well as data coercion (e.g., CID strings to Cid types). This means that the returned value might be different from the input data if defaults were applied. Disable this behavior by passing `{ allowTransform: false }` as the second argument to `$parse()`.
308
+
287
309
  #### `$validate(data)` - Get Validation Result
288
310
 
289
311
  Returns a detailed validation result object without throwing:
@@ -304,14 +326,18 @@ if (result.success) {
304
326
  }
305
327
  ```
306
328
 
329
+ > [!NOTE]
330
+ >
331
+ > Like `$parse`, the `$validate` method will apply defaults and coercion. Disable this behavior by passing `{ allowTransform: false }` as the second argument to `$validate()`.
332
+
307
333
  #### `$build(data)` - Build with Defaults
308
334
 
309
- Creates a valid object by applying defaults for optional fields:
335
+ Builds data without needing to specify the `$type` property, and properly types the result:
310
336
 
311
337
  ```typescript
312
338
  import * as app from './lexicons/app.js'
313
339
 
314
- // Build a like record with defaults (and without needing to specify $type)
340
+ // The type of the "like" variable will be "app.bsky.feed.like.Main"
315
341
  const like = app.bsky.feed.like.$build({
316
342
  subject: {
317
343
  uri: 'at://did:plc:abc/app.bsky.feed.post/123',
@@ -323,7 +349,7 @@ const like = app.bsky.feed.like.$build({
323
349
 
324
350
  #### `$isTypeOf(data)` - Type Discriminator
325
351
 
326
- Discriminates (already validated) data by `$type`, without re-validating. This is especially useful when working with union types:
352
+ Discriminates (pre-validated) data based on its `$type` property, without re-validating. This is especially useful when working with union types:
327
353
 
328
354
  ```typescript
329
355
  import { l } from '@atproto/lex'
@@ -340,6 +366,66 @@ if (app.bsky.feed.post.$isTypeOf(data)) {
340
366
  }
341
367
  ```
342
368
 
369
+ ## Data Model
370
+
371
+ The AT Protocol uses a [data model](https://atproto.com/specs/data-model) that extends JSON with two additional types: **CIDs** (content-addressed links) and **bytes**. This data is encoded as JSON for XRPC (HTTP API) or as [DAG-CBOR](https://ipld.io/docs/codecs/known/dag-cbor/) for storage and authentication (see [`@atproto/lex-cbor`](../lex-cbor)).
372
+
373
+ ### Types
374
+
375
+ ```typescript
376
+ import type {
377
+ LexValue,
378
+ LexMap,
379
+ LexScalar,
380
+ TypedLexMap,
381
+ Cid,
382
+ } from '@atproto/lex'
383
+ import { isLexValue, isLexMap, isTypedLexMap, isCid } from '@atproto/lex'
384
+
385
+ // LexScalar: number | string | boolean | null | Cid | Uint8Array
386
+ // LexValue: LexScalar | LexValue[] | { [key: string]?: LexValue }
387
+ // LexMap: { [key: string]?: LexValue }
388
+ // TypedLexMap: LexMap & { $type: string }
389
+ // Cid: Content Identifier (link by hash)
390
+
391
+ if (isTypedLexMap(data)) {
392
+ console.log(data.$type) // some string
393
+ }
394
+ ```
395
+
396
+ ### JSON Encoding
397
+
398
+ In JSON, CIDs are represented as `{"$link": "bafyrei..."}` and bytes as `{"$bytes": "base64..."}`:
399
+
400
+ ```typescript
401
+ import { lexParse, lexStringify, jsonToLex, lexToJson } from '@atproto/lex'
402
+
403
+ // Parse JSON string → data model (decodes $link and $bytes)
404
+ const data = lexParse('{"ref": {"$link": "bafyrei..."}}')
405
+
406
+ // Data model → JSON string (encodes CIDs and bytes)
407
+ const json = lexStringify({ ref: someCid, data: someBytes })
408
+
409
+ // Convert between parsed JSON objects and data model values
410
+ const lex = jsonToLex(jsonObject)
411
+ const obj = lexToJson(lexValue)
412
+ ```
413
+
414
+ ### DAG-CBOR Encoding
415
+
416
+ Use `@atproto/lex-cbor` to encode/decode the data model to/from DAG-CBOR format for storage and authentication:
417
+
418
+ ```typescript
419
+ import { encode, decode } from '@atproto/lex-cbor'
420
+ import type { LexValue } from '@atproto/lex'
421
+
422
+ // Encode data model to DAG-CBOR bytes
423
+ const cborBytes = encode(someLexValue)
424
+
425
+ // Decode DAG-CBOR bytes to data model
426
+ const lexValue: LexValue = decode(cborBytes)
427
+ ```
428
+
343
429
  ## Client API
344
430
 
345
431
  ### Creating a Client
@@ -767,6 +853,77 @@ console.log(response.headers)
767
853
  console.log(response.body)
768
854
  ```
769
855
 
856
+ ## Blob references
857
+
858
+ In AT Protocol, binary data (blobs) are referenced using `BlobRef`, which include metadata like MIME type and size. These references are what allow PDSs to determine which binary data ("files") is referenced by records.
859
+
860
+ ```typescript
861
+ import { BlobRef, isBlobRef } from '@atproto/lex'
862
+
863
+ const blobRef: BlobRef = {
864
+ $type: 'blob',
865
+ ref: parseCid('bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku'),
866
+ mimeType: 'image/png',
867
+ size: 12345,
868
+ }
869
+
870
+ if (isBlobRef(blobRef)) {
871
+ console.log('Valid BlobRef:', blobRef.mimeType, blobRef.size)
872
+ }
873
+ ```
874
+
875
+ > [!NOTE]
876
+ >
877
+ > Historically, references to blobs were represented as simple objects with the following structure:
878
+ >
879
+ > ```typescript
880
+ > type LegacyBlobRef = {
881
+ > ref: string
882
+ > mimeType: string
883
+ > }
884
+ > ```
885
+ >
886
+ > These should no longer be used for new records, but existing records using this format might still be encountered. To handle legacy blob references when validating data, enable the `--allowLegacyBlobs` flag when generating TypeScript schemas with `lex build`. You can use `isLegacyBlobRef()` from `@atproto/lex` to discriminate legacy blob references.
887
+
888
+ ## Utilities
889
+
890
+ Various utilities for working with CIDs, string lengths, language tags, and low-level JSON encoding are available:
891
+
892
+ ```typescript
893
+ import {
894
+ // CID utilities
895
+ parseCid, // Parse CID string (throws on invalid)
896
+ asCid, // Coerce to Cid or null
897
+ isCid, // Type guard for Cid values
898
+
899
+ // Blob references
900
+ BlobRef, // { $type: 'blob', ref: Cid, mimeType: string, size: number }
901
+ isBlobRef, // Type guard for BlobRef objects
902
+
903
+ // Equality
904
+ lexEquals, // Deep equality (handles CIDs and bytes)
905
+
906
+ // String length for Lexicon validation
907
+ graphemeLen, // Count user-perceived characters
908
+ utf8Len, // Count UTF-8 bytes
909
+
910
+ // Language tag validation (BCP-47)
911
+ isLanguageString, // Validate language tags (e.g., 'en', 'pt-BR')
912
+
913
+ // Low-level JSON encoding helpers
914
+ parseLexLink, // { $link: string } → Cid
915
+ encodeLexLink, // Cid → { $link: string }
916
+ parseLexBytes, // { $bytes: string } → Uint8Array
917
+ encodeLexBytes, // Uint8Array → { $bytes: string }
918
+ } from '@atproto/lex'
919
+
920
+ // Examples
921
+ const cid = parseCid('bafyreiabc...')
922
+ graphemeLen('👨‍👩‍👧‍👦') // 1
923
+ utf8Len('👨‍👩‍👧‍👦') // 25
924
+ isLanguageString('en-US') // true
925
+ ```
926
+
770
927
  ## Advanced Usage
771
928
 
772
929
  ### Workflow Integration
package/bin/lex CHANGED
@@ -94,6 +94,12 @@ yargs(hideBin(process.argv))
94
94
  describe:
95
95
  'file extension to use for generated files (e.g. ".ts", ".mts", ".cts")',
96
96
  },
97
+ indexFile: {
98
+ type: 'boolean',
99
+ default: false,
100
+ describe:
101
+ 'generate an "index.<fileExt>" file that exports all root-level namespaces',
102
+ },
97
103
  ignoreInvalidLexicons: {
98
104
  type: 'boolean',
99
105
  default: false,
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export * from '@atproto/lex-data';
2
+ export * from '@atproto/lex-json';
1
3
  export * from '@atproto/lex-schema';
2
4
  export * from '@atproto/lex-client';
3
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA"}
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("@atproto/lex-data"), exports);
5
+ tslib_1.__exportStar(require("@atproto/lex-json"), exports);
4
6
  tslib_1.__exportStar(require("@atproto/lex-schema"), exports);
5
7
  tslib_1.__exportStar(require("@atproto/lex-client"), exports);
6
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,8DAAmC;AACnC,8DAAmC","sourcesContent":["export * from '@atproto/lex-schema'\nexport * from '@atproto/lex-client'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,4DAAiC;AACjC,4DAAiC;AACjC,8DAAmC;AACnC,8DAAmC","sourcesContent":["export * from '@atproto/lex-data'\nexport * from '@atproto/lex-json'\nexport * from '@atproto/lex-schema'\nexport * from '@atproto/lex-client'\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/lex",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "license": "MIT",
5
5
  "description": "Lexicon tooling for AT",
6
6
  "keywords": [
@@ -36,10 +36,12 @@
36
36
  "dependencies": {
37
37
  "tslib": "^2.8.1",
38
38
  "yargs": "^17.0.0",
39
- "@atproto/lex-builder": "0.0.8",
40
- "@atproto/lex-client": "0.0.6",
41
- "@atproto/lex-installer": "0.0.8",
42
- "@atproto/lex-schema": "0.0.6"
39
+ "@atproto/lex-builder": "0.0.9",
40
+ "@atproto/lex-client": "0.0.7",
41
+ "@atproto/lex-data": "0.0.6",
42
+ "@atproto/lex-json": "0.0.6",
43
+ "@atproto/lex-installer": "0.0.9",
44
+ "@atproto/lex-schema": "0.0.7"
43
45
  },
44
46
  "devDependencies": {
45
47
  "@types/yargs": "^17.0.33",