@atproto/lex 0.0.14 → 0.0.16

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,32 @@
1
1
  # @atproto/lex
2
2
 
3
+ ## 0.0.16
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`619068f`](https://github.com/bluesky-social/atproto/commit/619068fb81203b3b43b632892bdcb0a5067f7fe4)]:
8
+ - @atproto/lex-builder@0.0.15
9
+ - @atproto/lex-client@0.0.12
10
+ - @atproto/lex-installer@0.0.16
11
+
12
+ ## 0.0.15
13
+
14
+ ### Patch Changes
15
+
16
+ - [#4601](https://github.com/bluesky-social/atproto/pull/4601) [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Fix `exports` field in package.json
17
+
18
+ - [#4601](https://github.com/bluesky-social/atproto/pull/4601) [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add JSDoc
19
+
20
+ - [#4601](https://github.com/bluesky-social/atproto/pull/4601) [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Update README
21
+
22
+ - Updated dependencies [[`7b9a98a`](https://github.com/bluesky-social/atproto/commit/7b9a98a763636c5f66a06da11fe6013f29dd9157), [`7b9a98a`](https://github.com/bluesky-social/atproto/commit/7b9a98a763636c5f66a06da11fe6013f29dd9157), [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015), [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015), [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015), [`7b9a98a`](https://github.com/bluesky-social/atproto/commit/7b9a98a763636c5f66a06da11fe6013f29dd9157), [`7b9a98a`](https://github.com/bluesky-social/atproto/commit/7b9a98a763636c5f66a06da11fe6013f29dd9157), [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015), [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015)]:
23
+ - @atproto/lex-schema@0.0.12
24
+ - @atproto/lex-client@0.0.12
25
+ - @atproto/lex-json@0.0.11
26
+ - @atproto/lex-installer@0.0.15
27
+ - @atproto/lex-data@0.0.11
28
+ - @atproto/lex-builder@0.0.14
29
+
3
30
  ## 0.0.14
4
31
 
5
32
  ### Patch Changes
package/README.md CHANGED
@@ -58,7 +58,7 @@ app.bsky.actor.profile.$validate({
58
58
  - [Data Model](#data-model)
59
59
  - [Types](#types)
60
60
  - [JSON Encoding](#json-encoding)
61
- - [DAG-CBOR Encoding](#dag-cbor-encoding)
61
+ - [CBOR Encoding](#cbor-encoding)
62
62
  - [Client API](#client-api)
63
63
  - [Creating a Client](#creating-a-client)
64
64
  - [Core Methods](#core-methods)
@@ -66,14 +66,13 @@ app.bsky.actor.profile.$validate({
66
66
  - [Authentication Methods](#authentication-methods)
67
67
  - [Labeler Configuration](#labeler-configuration)
68
68
  - [Low-Level XRPC](#low-level-xrpc)
69
- - [Blob references](#blob-references)
70
69
  - [Utilities](#utilities)
71
70
  - [Advanced Usage](#advanced-usage)
72
71
  - [Workflow Integration](#workflow-integration)
73
72
  - [Tree-Shaking](#tree-shaking)
74
- - [Custom Headers](#custom-headers)
75
- - [Request Options](#request-options)
73
+ - [Blob references](#blob-references)
76
74
  - [Actions](#actions)
75
+ - [Creating a Client from Another Client](#creating-a-client-from-another-client)
77
76
  - [Building Library-Style APIs with Actions](#building-library-style-apis-with-actions)
78
77
  - [License](#license)
79
78
 
@@ -383,10 +382,12 @@ if (app.bsky.feed.post.$isTypeOf(data)) {
383
382
 
384
383
  ## Data Model
385
384
 
386
- 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)).
385
+ The AT Protocol uses a [data model](https://atproto.com/specs/data-model) that extends JSON with two additional data structures: **CIDs** (content-addressed links) and **bytes** (for raw data). This data model can be encoded either as JSON for XRPC (HTTP API) or as [CBOR](https://dasl.ing/drisl.html) for storage and authentication (see [`@atproto/lex-cbor`](../lex-cbor)).
387
386
 
388
387
  ### Types
389
388
 
389
+ The package exports TypeScript types and type guards for working with the data model:
390
+
390
391
  ```typescript
391
392
  import type {
392
393
  LexValue,
@@ -410,34 +411,50 @@ if (isTypedLexMap(data)) {
410
411
 
411
412
  ### JSON Encoding
412
413
 
413
- In JSON, CIDs are represented as `{"$link": "bafyrei..."}` and bytes as `{"$bytes": "base64..."}`:
414
+ In JSON, CIDs are represented as `{"$link": "bafyrei..."}` and bytes as `{"$bytes": "base64..."}`. This package provides utilities to parse and stringify data model values to/from JSON:
414
415
 
415
416
  ```typescript
416
417
  import { lexParse, lexStringify, jsonToLex, lexToJson } from '@atproto/lex'
417
418
 
418
419
  // Parse JSON string → data model (decodes $link and $bytes)
419
- const data = lexParse('{"ref": {"$link": "bafyrei..."}}')
420
+ const parsed = lexParse<{
421
+ ref: Cid
422
+ data: Uint8Array
423
+ }>(`{
424
+ "ref": { "$link": "bafyrei..." },
425
+ "data": { "$bytes": "SGVsbG8sIHdvcmxkIQ==" }
426
+ }`)
427
+
428
+ const someCid = lexParse<Cid>('{"$link": "bafyrei..."}')
429
+ const someBytes = lexParse<Uint8Array>('{"$bytes": "SGVsbG8sIHdvcmxkIQ=="}')
420
430
 
421
431
  // Data model → JSON string (encodes CIDs and bytes)
422
432
  const json = lexStringify({ ref: someCid, data: someBytes })
423
433
 
424
434
  // Convert between parsed JSON objects and data model values
425
- const lex = jsonToLex(jsonObject)
426
- const obj = lexToJson(lexValue)
435
+ const lex = jsonToLex({
436
+ ref: { $link: 'bafyrei...' }, // Converted to Cid
437
+ data: { $bytes: 'SGVsbG8sIHdvcmxkIQ==' }, // Converted to Uint8Array
438
+ })
439
+
440
+ const obj = lexToJson({
441
+ ref: someCid, // Converted to { $link: string }
442
+ data: someBytes, // Converted to { $bytes: string }
443
+ })
427
444
  ```
428
445
 
429
- ### DAG-CBOR Encoding
446
+ ### CBOR Encoding
430
447
 
431
- Use `@atproto/lex-cbor` to encode/decode the data model to/from DAG-CBOR format for storage and authentication:
448
+ Use `@atproto/lex-cbor` to encode/decode the data model to/from CBOR ([DRISL](https://dasl.ing/drisl.html)) format for storage and authentication:
432
449
 
433
450
  ```typescript
434
451
  import { encode, decode } from '@atproto/lex-cbor'
435
452
  import type { LexValue } from '@atproto/lex'
436
453
 
437
- // Encode data model to DAG-CBOR bytes
454
+ // Encode data model to CBOR bytes
438
455
  const cborBytes = encode(someLexValue)
439
456
 
440
- // Decode DAG-CBOR bytes to data model
457
+ // Decode CBOR bytes to data model
441
458
  const lexValue: LexValue = decode(cborBytes)
442
459
  ```
443
460
 
@@ -475,217 +492,24 @@ For detailed OAuth setup, see the [@atproto/oauth-client](../../../oauth/oauth-c
475
492
 
476
493
  #### Authenticated Client with Password
477
494
 
478
- For simpler use cases (CLI tools, scripts, server-to-server), you can use password-based authentication with `@atproto/lex-password-session`:
479
-
480
- ```bash
481
- npm install @atproto/lex-password-session
482
- ```
495
+ For CLI tools, scripts, and bots, you can use password-based authentication with [`@atproto/lex-password-session`](../lex-password-session):
483
496
 
484
497
  ```typescript
485
498
  import { Client } from '@atproto/lex'
486
499
  import { PasswordSession } from '@atproto/lex-password-session'
487
- import * as app from './lexicons/app.js'
488
500
 
489
- // Create a session with app password credentials
490
- const session = await PasswordSession.login({
491
- service: 'https://bsky.social',
492
- identifier: 'alice.bsky.social', // handle or email
493
- password: 'xxxx-xxxx-xxxx-xxxx', // App password (not your main password)
494
-
495
- // Called when session is created or refreshed - persist the session data
496
- onUpdated: (data) => {
497
- saveToStorage(data) // Your persistence logic
498
- },
499
-
500
- // Called when session becomes invalid - clean up stored data
501
- onDeleted: (data) => {
502
- removeFromStorage(data.did)
503
- },
504
- })
505
-
506
- // Use the session with a Client
507
- const client = new Client(session)
508
-
509
- const profile = await client.call(app.bsky.actor.getProfile, {
510
- actor: 'atproto.com',
511
- })
512
- ```
513
-
514
- **Resuming a Session**
515
-
516
- Resume a previously persisted session. The `resume()` method validates the session by refreshing it:
517
-
518
- ```typescript
519
- const savedData = loadFromStorage() // Your retrieval logic
520
-
521
- // Resume validates the session by refreshing it
522
- // Throws if the session is definitively invalid
523
- const session = await PasswordSession.resume(savedData, {
524
- onUpdated: (data) => saveToStorage(data),
525
- onDeleted: (data) => removeFromStorage(data.did),
526
- })
527
-
528
- const client = new Client(session)
529
-
530
- // Access session properties
531
- console.log(session.did) // User's DID
532
- console.log(session.handle) // User's handle
533
- console.log(session.destroyed) // false (session is active)
534
- ```
535
-
536
- **Logging Out**
537
-
538
- ```typescript
539
- await session.logout()
540
- ```
541
-
542
- **Deleting a Session Without Resuming**
543
-
544
- Delete a stored session without needing to resume it first:
545
-
546
- ```typescript
547
- const savedData = loadFromStorage()
548
-
549
- // Delete the session directly - throws on transient errors (network, server down)
550
- await PasswordSession.delete(savedData)
551
- ```
552
-
553
- **Error Handling Hooks**
554
-
555
- Handle transient errors (network issues, server unavailability) separately from permanent failures:
556
-
557
- ```typescript
558
501
  const session = await PasswordSession.login({
559
502
  service: 'https://bsky.social',
560
503
  identifier: 'alice.bsky.social',
561
- password: 'xxxx-xxxx-xxxx-xxxx',
562
-
504
+ password: 'xxxx-xxxx-xxxx-xxxx', // App password
563
505
  onUpdated: (data) => saveToStorage(data),
564
- onDeleted: (data) => removeFromStorage(data.did),
565
-
566
- // Called when refresh fails due to transient errors (network, server down)
567
- // The session may still be valid - don't delete stored credentials
568
- onUpdateFailure: (data, error) => {
569
- console.warn('Session refresh failed, will retry:', error.message)
570
- },
571
-
572
- // Called when logout fails due to transient errors
573
- // Consider retrying later to avoid orphaned sessions
574
- onDeleteFailure: (data, error) => {
575
- console.error('Logout failed, session may still be active:', error.message)
576
- scheduleRetry(data) // Your retry logic
577
- },
506
+ onDeleted: (data) => clearStorage(data.did),
578
507
  })
579
- ```
580
-
581
- **Handling Two-Factor Authentication (2FA)**
582
508
 
583
- > [!CAUTION]
584
- >
585
- > Two-factor authentication only applies when using **main account credentials**, which is **strongly discouraged**. Password authentication should be used with [app passwords](https://bsky.app/settings/app-passwords) only because they are designed for programmatic access (bots, scripts, CLI tools). For user-facing applications, use OAuth via [@atproto/oauth-client](../../../oauth/oauth-client) which provides better security and user control.
586
-
587
- ```typescript
588
- import {
589
- PasswordSession,
590
- LexAuthFactorError,
591
- } from '@atproto/lex-password-session'
592
-
593
- async function loginWithMainCredentials(
594
- identifier: string,
595
- password: string,
596
- authFactorToken?: string,
597
- ): Promise<PasswordSession> {
598
- try {
599
- return await PasswordSession.login({
600
- service: 'https://bsky.social',
601
- identifier,
602
- password,
603
- authFactorToken,
604
-
605
- onUpdated: (data) => saveToStorage(data),
606
- onDeleted: (data) => removeFromStorage(data.did),
607
- })
608
- } catch (err) {
609
- if (err instanceof LexAuthFactorError && !authFactorToken) {
610
- // 2FA required
611
- const token = await promptUserFor2FACode(err.message)
612
- return loginWithMainCredentials(identifier, password, token)
613
- }
614
- throw err
615
- }
616
- }
509
+ const client = new Client(session)
617
510
  ```
618
511
 
619
- #### Creating a Client from Another Client
620
-
621
- You can create a new `Client` instance from an existing client. The new client will share the same underlying configuration (authentication, headers, labelers, service proxy), with the ability to override specific settings.
622
-
623
- > [!NOTE]
624
- >
625
- > When you create a client from another client, the child client inherits the base client's configuration. On every request, the child client merges its own configuration with the base client's current configuration, with the child's settings taking precedence. Changes to the base client's configuration (like `baseClient.setLabelers()`) will be reflected in child client requests, but changes to child clients do not affect the base client.
626
-
627
- ```typescript
628
- import { Client } from '@atproto/lex'
629
-
630
- // Base client with authentication
631
- const baseClient = new Client(session)
632
-
633
- baseClient.setLabelers(['did:plc:labelerA', 'did:plc:labelerB'])
634
- baseClient.headers.set('x-app-version', '1.0.0')
635
-
636
- // Create a new client with additional configuration that will get merged with
637
- // baseClient's settings on every request.
638
- const configuredClient = new Client(baseClient, {
639
- labelers: ['did:plc:labelerC'],
640
- headers: { 'x-trace-id': 'abc123' },
641
- })
642
- ```
643
-
644
- This pattern is particularly useful when you need to:
645
-
646
- - Configure labelers after authentication
647
- - Add application-specific headers
648
- - Create multiple clients with different configurations from the same session
649
-
650
- **Example: Configuring labelers after sign-in**
651
-
652
- ```typescript
653
- import { Client } from '@atproto/lex'
654
- import * as app from './lexicons/app.js'
655
-
656
- async function createBaseClient(session: OAuthSession) {
657
- // Create base client
658
- const client = new Client(session, {
659
- service: 'did:web:api.bsky.app#bsky_appview',
660
- })
661
-
662
- // Fetch user preferences
663
- const { preferences } = await client.call(app.bsky.actor.getPreferences)
664
-
665
- // Extract labeler preferences
666
- const labelerPref = preferences.findLast((p) =>
667
- app.bsky.actor.defs.labelersPref.check(p),
668
- )
669
- const labelers = labelerPref?.labelers.map((l) => l.did) ?? []
670
-
671
- // Configure the client with the user's preferred labelers
672
- client.setLabelers(labelers)
673
-
674
- return client
675
- }
676
-
677
- // Usage
678
- const baseClient = await createBaseClient(session)
679
-
680
- // Create a new client with a different service, but reusing the labelers
681
- // from the base client.
682
- const otherClient = new Client(baseClient, {
683
- service: 'did:web:com.example.other#other_service',
684
- })
685
-
686
- // Whenever you update labelers on the base client, the other client will automatically
687
- // receive the same updates, since they share the same labeler set.
688
- ```
512
+ For detailed password session setup, see the [@atproto/lex-password-session](../lex-password-session) documentation.
689
513
 
690
514
  #### Client with Service Proxy (authenticated only)
691
515
 
@@ -837,104 +661,72 @@ By default, all client methods throw errors when requests fail. For more ergonom
837
661
 
838
662
  #### Safe Methods
839
663
 
840
- Each client method has a corresponding "Safe" variant that catches errors and returns them as part of the result type:
841
-
842
- - `xrpcSafe()` - Safe version of `xrpc()`
843
- - `createRecordsSafe()` - Safe version of `createRecord()`
844
- - `deleteRecordsSafe()` - Safe version of `deleteRecord()`
845
- - `getRecordsSafe()` - Safe version of `getRecord()`
846
- - `putRecordsSafe()` - Safe version of `putRecord()`
664
+ The `xrpcSafe()` method catches errors and returns them as part of the result type instead of throwing:
847
665
 
848
- #### ResponseFailure Type
666
+ #### XrpcFailure Type
849
667
 
850
- Safe methods return a union type that includes the success case and all possible failure cases:
668
+ The `xrpcSafe()` method returns a union type that includes the success case (`XrpcResponse`) and failure cases (`XrpcFailure`):
851
669
 
852
670
  ```typescript
853
- import { Client, ResponseFailure } from '@atproto/lex'
854
- import * as app from './lexicons/app.js'
671
+ import {
672
+ Client,
673
+ XrpcResponseError,
674
+ XrpcUpstreamError,
675
+ XrpcInternalError,
676
+ } from '@atproto/lex'
677
+ import * as com from './lexicons/com.js'
855
678
 
856
679
  const client = new Client(session)
857
680
 
858
681
  // Using a safe method
859
682
  const result = await client.xrpcSafe(com.atproto.identity.resolveHandle, {
860
- params: { limit: 50 },
683
+ params: { handle: 'alice.bsky.social' },
861
684
  })
862
685
 
863
686
  if (result.success) {
864
687
  // Handle success
865
688
  console.log(result.body)
866
689
  } else {
867
- // Handle failure
868
- if (result.error === 'Unknown') {
869
- // Unable to perform the request
870
- const { reason } = result
871
- if (reason instanceof XrpcResponseError) {
872
- // The server returned a syntactically valid XRPC error response, but
873
- // used an error code that is not declared for this method
874
- reason.error // string (e.g. "AuthenticationRequired", "RateLimitExceeded", etc.)
875
- reason.message // string
876
- reason.status // number
877
- reason.headers // Headers
878
- reason.payload // { body: { error: string, message?: string }; encoding: string }
879
- } else if (reason instanceof XrpcUpstreamError) {
880
- // The response was incomplete (e.g. connection dropped), or
881
- // invalid (e.g. malformed JSON, data does not match schema).
882
- reason.error // "InvalidResponse"
883
- reason.message // string
884
- reason.response.status // number
885
- reason.response.headers // Headers
886
- reason.response.payload // null | { body: unknown; encoding: string }
887
- } else {
888
- reason // unknown (fetch failed, other?)
889
- }
890
- } else {
891
- // A declared error for that method
892
- result // XrpcResponseError<"HandleNotFound">
893
- result.error // "HandleNotFound"
690
+ // Handle failure - result is an XrpcFailure
691
+ if (result instanceof XrpcResponseError) {
692
+ // The server returned a valid XRPC error response
693
+ result.error // string (e.g. "HandleNotFound", "AuthenticationRequired", etc.)
694
+ result.message // string
695
+ result.response.status // number
696
+ result.response.headers // Headers
697
+ result.payload // { body: { error: string, message?: string }; encoding: string }
698
+ } else if (result instanceof XrpcUpstreamError) {
699
+ // The response was not a valid XRPC response (e.g. malformed JSON,
700
+ // data does not match schema, connection dropped)
701
+ result.error // "UpstreamFailure"
894
702
  result.message // string
703
+ result.response.status // number
704
+ result.response.headers // Headers
705
+ result.payload // null | { body: unknown; encoding: string }
706
+ } else if (result instanceof XrpcInternalError) {
707
+ // Something went wrong on the client side (network error, etc.)
708
+ result.error // "InternalServerError"
709
+ result.message // string
710
+ }
711
+
712
+ // All XrpcFailure types have these properties:
713
+ result.shouldRetry() // boolean - whether the error is transient
714
+
715
+ if (result.matchesSchema()) {
716
+ // Check if the error matches a declared error in the schema.
717
+ // TypeScript knows this is a declared error for the method.
718
+ result.error // "HandleNotFound"
895
719
  }
896
720
  }
897
721
  ```
898
722
 
899
- The `ResponseFailure<M>` type is a union with three possible error types:
900
-
901
- 1. **Declared errors** - Errors explicitly listed in the method's Lexicon schema will be represented as an `XrpcResponseError<N>` instance:
902
-
903
- ```typescript
904
- // XrpcResponseError<N>
905
- type KnownLexRpcResponseFailure<N extends string> = {
906
- success: false
907
- name: N
908
- error: XrpcResponseError<N>
909
-
910
- // Additional response details
911
- status: number
912
- headers: Headers
913
- encoding: undefined | string
914
- body: LexErrorData<N>
915
- }
916
- ```
917
-
918
- 2. **Unknown errors** - Server errors not declared in the method's schema:
919
-
920
- ```typescript
921
- // LexRpcResponseFailure<'Unexpected', XrpcResponseError>
922
- type UnknownLexRpcResponseFailure = {
923
- success: false
924
- name: 'Unexpected'
925
- error: XrpcResponseError<string>
926
- }
927
- ```
928
-
929
- 3. **Unexpected errors** - Network errors, invalid responses, or other client-side errors:
930
- ```typescript
931
- // LexRpcResponseFailure<'UnexpectedError', unknown>
932
- type UnexpectedLexRpcResponseFailure = {
933
- success: false
934
- name: 'UnexpectedError'
935
- error: unknown // Could be anything (network error, parsing error, etc.)
936
- }
937
- ```
723
+ The `XrpcFailure<M>` type is a union of three error classes:
724
+
725
+ 1. **`XrpcResponseError`** - The server returned a valid XRPC error response (non-2xx with proper error payload)
726
+
727
+ 2. **`XrpcUpstreamError`** - The response was invalid or unprocessable (malformed JSON, schema mismatch, incomplete response)
728
+
729
+ 3. **`XrpcInternalError`** - Client-side errors (network failures, timeouts, etc.)
938
730
 
939
731
  ### Authentication Methods
940
732
 
@@ -1011,41 +803,9 @@ console.log(response.headers)
1011
803
  console.log(response.body)
1012
804
  ```
1013
805
 
1014
- ## Blob references
1015
-
1016
- 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.
1017
-
1018
- ```typescript
1019
- import { BlobRef, isBlobRef } from '@atproto/lex'
1020
-
1021
- const blobRef: BlobRef = {
1022
- $type: 'blob',
1023
- ref: parseCid('bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku'),
1024
- mimeType: 'image/png',
1025
- size: 12345,
1026
- }
1027
-
1028
- if (isBlobRef(blobRef)) {
1029
- console.log('Valid BlobRef:', blobRef.mimeType, blobRef.size)
1030
- }
1031
- ```
1032
-
1033
- > [!NOTE]
1034
- >
1035
- > Historically, references to blobs were represented as simple objects with the following structure:
1036
- >
1037
- > ```typescript
1038
- > type LegacyBlobRef = {
1039
- > ref: string
1040
- > mimeType: string
1041
- > }
1042
- > ```
1043
- >
1044
- > 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.
1045
-
1046
806
  ## Utilities
1047
807
 
1048
- Various utilities for working with CIDs, string lengths, language tags, and low-level JSON encoding are available:
808
+ Various utilities for working with CIDs, string lengths, language tags, and low-level JSON encoding are exported from the package:
1049
809
 
1050
810
  ```typescript
1051
811
  import {
@@ -1075,7 +835,6 @@ import {
1075
835
  encodeLexBytes, // Uint8Array → { $bytes: string }
1076
836
  } from '@atproto/lex'
1077
837
 
1078
- // Examples
1079
838
  const cid = parseCid('bafyreiabc...')
1080
839
  graphemeLen('👨‍👩‍👧‍👦') // 1
1081
840
  utf8Len('👨‍👩‍👧‍👦') // 25
@@ -1128,168 +887,37 @@ lex build --pure-annotations
1128
887
 
1129
888
  This will make the generated code more easily tree-shakeable from places that import your library.
1130
889
 
1131
- ### Custom Headers
890
+ ### Blob references
1132
891
 
1133
- Add custom headers to all requests:
892
+ 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.
1134
893
 
1135
894
  ```typescript
1136
- const client = new Client(session, {
1137
- headers: {
1138
- 'x-custom-header': 'value',
1139
- },
1140
- })
1141
- ```
1142
-
1143
- ### Request Options
1144
-
1145
- All client methods accept options for controlling request behavior. The available options depend on the type of operation.
1146
-
1147
- #### Base Call Options
1148
-
1149
- All methods support these base options:
895
+ import { BlobRef, isBlobRef } from '@atproto/lex'
1150
896
 
1151
- ```typescript
1152
- type CallOptions = {
1153
- signal?: AbortSignal // Abort the request
1154
- headers?: HeadersInit // Additional request headers
1155
- service?: Service // Override service proxy for this request
1156
- labelers?: Iterable<Did> // Additional labelers for this request
1157
- validateRequest?: boolean // Set to "true" to enable request schema validation
1158
- validateResponse?: boolean // Set to "false" to skip response schema validation
897
+ const blobRef: BlobRef = {
898
+ $type: 'blob',
899
+ ref: parseCid('bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku'),
900
+ mimeType: 'image/png',
901
+ size: 12345,
1159
902
  }
1160
- ```
1161
-
1162
- #### Query and Procedure Calls
1163
-
1164
- When using `.call()` with Query or Procedure schemas:
1165
-
1166
- ```typescript
1167
- import * as app from './lexicons/app.js'
1168
-
1169
- // Query with parameters
1170
- const timeline = await client.call(
1171
- app.bsky.feed.getTimeline,
1172
- { limit: 50 },
1173
- {
1174
- signal: abortController.signal,
1175
- headers: { 'x-custom': 'value' },
1176
- },
1177
- )
1178
-
1179
- // Procedure with body
1180
- const result = await client.call(
1181
- app.bsky.actor.putPreferences,
1182
- { preferences: [...] },
1183
- {
1184
- signal: abortController.signal,
1185
- },
1186
- )
1187
- ```
1188
-
1189
- For low-level access with full response data, use `.xrpc()`:
1190
-
1191
- ```typescript
1192
- const response = await client.xrpc(app.bsky.feed.getTimeline, {
1193
- params: { limit: 50 },
1194
- signal: abortController.signal,
1195
- headers: { 'x-custom': 'value' },
1196
- skipVerification: false, // Whether to skip response schema validation
1197
- })
1198
-
1199
- console.log(response.status) // 200
1200
- console.log(response.headers) // Headers object
1201
- console.log(response.body) // Parsed response body
1202
- ```
1203
-
1204
- #### Record Operations (CRUD)
1205
-
1206
- Record operations support additional options beyond base `CallOptions`:
1207
-
1208
- **Creating Records**
1209
-
1210
- ```typescript
1211
- import * as app from './lexicons/app.js'
1212
903
 
1213
- await client.create(
1214
- app.bsky.feed.post,
1215
- {
1216
- text: 'Hello!',
1217
- createdAt: new Date().toISOString(),
1218
- },
1219
- {
1220
- // Base options
1221
- signal: abortController.signal,
1222
- headers: { 'x-custom': 'value' },
1223
-
1224
- // Create-specific options
1225
- rkey: 'custom-key', // Custom record key (optional, auto-generated if omitted)
1226
- validate: true, // Validate before creating
1227
- swapCommit: 'bafyrei...', // CID for optimistic concurrency
1228
- },
1229
- )
1230
- ```
1231
-
1232
- **Reading Records**
1233
-
1234
- ```typescript
1235
- await client.get(app.bsky.actor.profile, {
1236
- // Base options
1237
- signal: abortController.signal,
1238
-
1239
- // Get-specific options
1240
- rkey: 'self', // Record key (required for non-literal keys)
1241
- })
1242
- ```
1243
-
1244
- **Updating Records**
1245
-
1246
- ```typescript
1247
- await client.put(
1248
- app.bsky.actor.profile,
1249
- {
1250
- displayName: 'New Name',
1251
- description: 'Updated bio',
1252
- },
1253
- {
1254
- // Base options
1255
- signal: abortController.signal,
1256
-
1257
- // Put-specific options
1258
- rkey: 'self', // Record key
1259
- validate: true, // Validate before updating
1260
- swapCommit: 'bafyrei...', // Expected repo commit CID
1261
- swapRecord: 'bafyrei...', // Expected record CID (for CAS)
1262
- },
1263
- )
1264
- ```
1265
-
1266
- **Deleting Records**
1267
-
1268
- ```typescript
1269
- await client.delete(app.bsky.feed.post, {
1270
- // Base options
1271
- signal: abortController.signal,
1272
-
1273
- // Delete-specific options
1274
- rkey: '3jxf7z2k3q2', // Record key
1275
- swapCommit: 'bafyrei...', // Expected repo commit CID
1276
- swapRecord: 'bafyrei...', // Expected record CID
1277
- })
904
+ if (isBlobRef(blobRef)) {
905
+ console.log('Valid BlobRef:', blobRef.mimeType, blobRef.size)
906
+ }
1278
907
  ```
1279
908
 
1280
- **Listing Records**
1281
-
1282
- ```typescript
1283
- await client.list(app.bsky.feed.post, {
1284
- // Base options
1285
- signal: abortController.signal,
1286
-
1287
- // List-specific options
1288
- limit: 50, // Maximum records to return
1289
- cursor: 'abc123', // Pagination cursor
1290
- reverse: true, // Reverse chronological order
1291
- })
1292
- ```
909
+ > [!NOTE]
910
+ >
911
+ > Historically, references to blobs were represented as simple objects with the following structure:
912
+ >
913
+ > ```typescript
914
+ > type LegacyBlobRef = {
915
+ > ref: string
916
+ > mimeType: string
917
+ > }
918
+ > ```
919
+ >
920
+ > 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.
1293
921
 
1294
922
  ### Actions
1295
923
 
@@ -1455,6 +1083,77 @@ const enableAdultContent: Action<void, Preference[]> = async (
1455
1083
  await client.call(enableAdultContent)
1456
1084
  ```
1457
1085
 
1086
+ ### Creating a Client from Another Client
1087
+
1088
+ You can create a new `Client` instance from an existing client. The new client will share the same underlying configuration (authentication, headers, labelers, service proxy), with the ability to override specific settings.
1089
+
1090
+ > [!NOTE]
1091
+ >
1092
+ > When you create a client from another client, the child client inherits the base client's configuration. On every request, the child client merges its own configuration with the base client's current configuration, with the child's settings taking precedence. Changes to the base client's configuration (like `baseClient.setLabelers()`) will be reflected in child client requests, but changes to child clients do not affect the base client.
1093
+
1094
+ ```typescript
1095
+ import { Client } from '@atproto/lex'
1096
+
1097
+ // Base client with authentication
1098
+ const baseClient = new Client(session)
1099
+
1100
+ baseClient.setLabelers(['did:plc:labelerA', 'did:plc:labelerB'])
1101
+ baseClient.headers.set('x-app-version', '1.0.0')
1102
+
1103
+ // Create a new client with additional configuration that will get merged with
1104
+ // baseClient's settings on every request.
1105
+ const configuredClient = new Client(baseClient, {
1106
+ labelers: ['did:plc:labelerC'],
1107
+ headers: { 'x-trace-id': 'abc123' },
1108
+ })
1109
+ ```
1110
+
1111
+ This pattern is particularly useful when you need to:
1112
+
1113
+ - Configure labelers after authentication
1114
+ - Add application-specific headers
1115
+ - Create multiple clients with different configurations from the same session
1116
+
1117
+ **Example: Configuring labelers after sign-in**
1118
+
1119
+ ```typescript
1120
+ import { Client } from '@atproto/lex'
1121
+ import * as app from './lexicons/app.js'
1122
+
1123
+ async function createBaseClient(session: OAuthSession) {
1124
+ // Create base client
1125
+ const client = new Client(session, {
1126
+ service: 'did:web:api.bsky.app#bsky_appview',
1127
+ })
1128
+
1129
+ // Fetch user preferences
1130
+ const { preferences } = await client.call(app.bsky.actor.getPreferences)
1131
+
1132
+ // Extract labeler preferences
1133
+ const labelerPref = preferences.findLast((p) =>
1134
+ app.bsky.actor.defs.labelersPref.check(p),
1135
+ )
1136
+ const labelers = labelerPref?.labelers.map((l) => l.did) ?? []
1137
+
1138
+ // Configure the client with the user's preferred labelers
1139
+ client.setLabelers(labelers)
1140
+
1141
+ return client
1142
+ }
1143
+
1144
+ // Usage
1145
+ const baseClient = await createBaseClient(session)
1146
+
1147
+ // Create a new client with a different service, but reusing the labelers
1148
+ // from the base client.
1149
+ const otherClient = new Client(baseClient, {
1150
+ service: 'did:web:com.example.other#other_service',
1151
+ })
1152
+
1153
+ // Whenever you update labelers on the base client, the other client will automatically
1154
+ // receive the same updates, since they share the same labeler set.
1155
+ ```
1156
+
1458
1157
  ### Building Library-Style APIs with Actions
1459
1158
 
1460
1159
  Actions enable you to create high-level, convenience APIs similar to [@atproto/api](https://www.npmjs.com/package/@atproto/api)'s `Agent` class. Here are patterns for common operations:
package/dist/index.d.ts CHANGED
@@ -1,3 +1,65 @@
1
+ /**
2
+ * The `@atproto/lex` package provides utilities for working with ATProtocol
3
+ * lexicons, including data types, JSON encoding/decoding, schema validation,
4
+ * and HTTP client functionality.
5
+ *
6
+ * ## `@atproto/lex-client`
7
+ *
8
+ * - {@link client.Client} - Type-safe XRPC client for making ATProtocol API calls
9
+ * - {@link client.XrpcError} - Base error class for XRPC request failures
10
+ * - {@link client.Agent} - Interface used by {@link client.Client} for making HTTP requests
11
+ * - {@link client.xrpc} - Utility function for making XRPC requests
12
+ *
13
+ * ## `@atproto/lex-data`
14
+ *
15
+ * - {@link data.LexValue} - Union type representing any valid Lexicon value
16
+ * - {@link data.LexMap} - Object type with string keys and {@link data.LexValue} values
17
+ * - {@link data.Cid} - Content Identifier for referencing data by hash
18
+ * - {@link data.BlobRef} - Reference to binary data (images, videos, etc.)
19
+ *
20
+ * ## `@atproto/lex-json`
21
+ *
22
+ * - {@link json.lexStringify} - Serialize Lex values to JSON strings
23
+ * - {@link json.lexParse} - Parse JSON strings into Lex values
24
+ * - {@link json.lexToJson} - Convert Lex values to plain JSON objects
25
+ * - {@link json.jsonToLex} - Convert plain JSON objects to Lex values
26
+ *
27
+ * ## `@atproto/lex-schema`
28
+ *
29
+ * The {@link l} namespace provides a fluent API for building schemas:
30
+ *
31
+ * ### Primitive Types
32
+ * - {@link l.string | l.string()} - String values with optional format/length constraints
33
+ * - {@link l.integer | l.integer()} - Integer values with optional min/max constraints
34
+ * - {@link l.boolean | l.boolean()} - Boolean values
35
+ * - {@link l.bytes | l.bytes()} - Binary data (Uint8Array)
36
+ * - {@link l.cid | l.cid()} - Content Identifier values
37
+ * - {@link l.blob | l.blob()} - Blob references with mime type and size
38
+ *
39
+ * ### Composite Types
40
+ * - {@link l.object | l.object()} - Objects with defined property schemas
41
+ * - {@link l.array | l.array()} - Arrays with element type validation
42
+ * - {@link l.union | l.union()} - Union of multiple possible types
43
+ * - {@link l.ref | l.ref()} - Reference to another schema definition
44
+ * - {@link l.literal | l.literal()} - Literal constant values
45
+ * - {@link l.enum | l.enum()} - Enum of allowed string values
46
+ * - {@link l.typedRef | l.typedRef()} - Reference to a {@link l.typedObject | l.typedObject()}
47
+ * - {@link l.typedUnion | l.typedUnion()} - Discriminated union between multiple {@link l.typedRef | l.typedRef()} or {@link l.typedObject | l.typedObject()} types
48
+ *
49
+ * ### Modifiers
50
+ * - {@link l.optional | l.optional()} - Mark a property as optional
51
+ * - {@link l.nullable | l.nullable()} - Allow null values
52
+ * - {@link l.withDefault | l.withDefault()} - Provide a default value
53
+ *
54
+ * ### Lexicon Definitions
55
+ * - {@link l.typedObject | l.typedObject()} - Define a typed object with a `$type` property
56
+ * - {@link l.record | l.record()} - Define a Lexicon record type
57
+ * - {@link l.query | l.query()} - Define a Lexicon query method
58
+ * - {@link l.procedure | l.procedure()} - Define a Lexicon procedure method
59
+ * - {@link l.subscription | l.subscription()} - Define a Lexicon subscription method
60
+ *
61
+ * @packageDocumentation
62
+ */
1
63
  export * from '@atproto/lex-data';
2
64
  export * from '@atproto/lex-json';
3
65
  export * from '@atproto/lex-schema';
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AAEH,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA"}
package/dist/index.js CHANGED
@@ -1,6 +1,69 @@
1
1
  "use strict";
2
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  const tslib_1 = require("tslib");
5
+ /**
6
+ * The `@atproto/lex` package provides utilities for working with ATProtocol
7
+ * lexicons, including data types, JSON encoding/decoding, schema validation,
8
+ * and HTTP client functionality.
9
+ *
10
+ * ## `@atproto/lex-client`
11
+ *
12
+ * - {@link client.Client} - Type-safe XRPC client for making ATProtocol API calls
13
+ * - {@link client.XrpcError} - Base error class for XRPC request failures
14
+ * - {@link client.Agent} - Interface used by {@link client.Client} for making HTTP requests
15
+ * - {@link client.xrpc} - Utility function for making XRPC requests
16
+ *
17
+ * ## `@atproto/lex-data`
18
+ *
19
+ * - {@link data.LexValue} - Union type representing any valid Lexicon value
20
+ * - {@link data.LexMap} - Object type with string keys and {@link data.LexValue} values
21
+ * - {@link data.Cid} - Content Identifier for referencing data by hash
22
+ * - {@link data.BlobRef} - Reference to binary data (images, videos, etc.)
23
+ *
24
+ * ## `@atproto/lex-json`
25
+ *
26
+ * - {@link json.lexStringify} - Serialize Lex values to JSON strings
27
+ * - {@link json.lexParse} - Parse JSON strings into Lex values
28
+ * - {@link json.lexToJson} - Convert Lex values to plain JSON objects
29
+ * - {@link json.jsonToLex} - Convert plain JSON objects to Lex values
30
+ *
31
+ * ## `@atproto/lex-schema`
32
+ *
33
+ * The {@link l} namespace provides a fluent API for building schemas:
34
+ *
35
+ * ### Primitive Types
36
+ * - {@link l.string | l.string()} - String values with optional format/length constraints
37
+ * - {@link l.integer | l.integer()} - Integer values with optional min/max constraints
38
+ * - {@link l.boolean | l.boolean()} - Boolean values
39
+ * - {@link l.bytes | l.bytes()} - Binary data (Uint8Array)
40
+ * - {@link l.cid | l.cid()} - Content Identifier values
41
+ * - {@link l.blob | l.blob()} - Blob references with mime type and size
42
+ *
43
+ * ### Composite Types
44
+ * - {@link l.object | l.object()} - Objects with defined property schemas
45
+ * - {@link l.array | l.array()} - Arrays with element type validation
46
+ * - {@link l.union | l.union()} - Union of multiple possible types
47
+ * - {@link l.ref | l.ref()} - Reference to another schema definition
48
+ * - {@link l.literal | l.literal()} - Literal constant values
49
+ * - {@link l.enum | l.enum()} - Enum of allowed string values
50
+ * - {@link l.typedRef | l.typedRef()} - Reference to a {@link l.typedObject | l.typedObject()}
51
+ * - {@link l.typedUnion | l.typedUnion()} - Discriminated union between multiple {@link l.typedRef | l.typedRef()} or {@link l.typedObject | l.typedObject()} types
52
+ *
53
+ * ### Modifiers
54
+ * - {@link l.optional | l.optional()} - Mark a property as optional
55
+ * - {@link l.nullable | l.nullable()} - Allow null values
56
+ * - {@link l.withDefault | l.withDefault()} - Provide a default value
57
+ *
58
+ * ### Lexicon Definitions
59
+ * - {@link l.typedObject | l.typedObject()} - Define a typed object with a `$type` property
60
+ * - {@link l.record | l.record()} - Define a Lexicon record type
61
+ * - {@link l.query | l.query()} - Define a Lexicon query method
62
+ * - {@link l.procedure | l.procedure()} - Define a Lexicon procedure method
63
+ * - {@link l.subscription | l.subscription()} - Define a Lexicon subscription method
64
+ *
65
+ * @packageDocumentation
66
+ */
4
67
  tslib_1.__exportStar(require("@atproto/lex-data"), exports);
5
68
  tslib_1.__exportStar(require("@atproto/lex-json"), exports);
6
69
  tslib_1.__exportStar(require("@atproto/lex-schema"), exports);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,sDAAsD;;;AAOtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AAEH,4DAAiC;AACjC,4DAAiC;AACjC,8DAAmC;AACnC,8DAAmC","sourcesContent":["/* eslint-disable @typescript-eslint/no-unused-vars */\n\nimport type * as client from '@atproto/lex-client'\nimport type * as data from '@atproto/lex-data'\nimport type * as json from '@atproto/lex-json'\nimport { l } from '@atproto/lex-schema'\n\n/**\n * The `@atproto/lex` package provides utilities for working with ATProtocol\n * lexicons, including data types, JSON encoding/decoding, schema validation,\n * and HTTP client functionality.\n *\n * ## `@atproto/lex-client`\n *\n * - {@link client.Client} - Type-safe XRPC client for making ATProtocol API calls\n * - {@link client.XrpcError} - Base error class for XRPC request failures\n * - {@link client.Agent} - Interface used by {@link client.Client} for making HTTP requests\n * - {@link client.xrpc} - Utility function for making XRPC requests\n *\n * ## `@atproto/lex-data`\n *\n * - {@link data.LexValue} - Union type representing any valid Lexicon value\n * - {@link data.LexMap} - Object type with string keys and {@link data.LexValue} values\n * - {@link data.Cid} - Content Identifier for referencing data by hash\n * - {@link data.BlobRef} - Reference to binary data (images, videos, etc.)\n *\n * ## `@atproto/lex-json`\n *\n * - {@link json.lexStringify} - Serialize Lex values to JSON strings\n * - {@link json.lexParse} - Parse JSON strings into Lex values\n * - {@link json.lexToJson} - Convert Lex values to plain JSON objects\n * - {@link json.jsonToLex} - Convert plain JSON objects to Lex values\n *\n * ## `@atproto/lex-schema`\n *\n * The {@link l} namespace provides a fluent API for building schemas:\n *\n * ### Primitive Types\n * - {@link l.string | l.string()} - String values with optional format/length constraints\n * - {@link l.integer | l.integer()} - Integer values with optional min/max constraints\n * - {@link l.boolean | l.boolean()} - Boolean values\n * - {@link l.bytes | l.bytes()} - Binary data (Uint8Array)\n * - {@link l.cid | l.cid()} - Content Identifier values\n * - {@link l.blob | l.blob()} - Blob references with mime type and size\n *\n * ### Composite Types\n * - {@link l.object | l.object()} - Objects with defined property schemas\n * - {@link l.array | l.array()} - Arrays with element type validation\n * - {@link l.union | l.union()} - Union of multiple possible types\n * - {@link l.ref | l.ref()} - Reference to another schema definition\n * - {@link l.literal | l.literal()} - Literal constant values\n * - {@link l.enum | l.enum()} - Enum of allowed string values\n * - {@link l.typedRef | l.typedRef()} - Reference to a {@link l.typedObject | l.typedObject()}\n * - {@link l.typedUnion | l.typedUnion()} - Discriminated union between multiple {@link l.typedRef | l.typedRef()} or {@link l.typedObject | l.typedObject()} types\n *\n * ### Modifiers\n * - {@link l.optional | l.optional()} - Mark a property as optional\n * - {@link l.nullable | l.nullable()} - Allow null values\n * - {@link l.withDefault | l.withDefault()} - Provide a default value\n *\n * ### Lexicon Definitions\n * - {@link l.typedObject | l.typedObject()} - Define a typed object with a `$type` property\n * - {@link l.record | l.record()} - Define a Lexicon record type\n * - {@link l.query | l.query()} - Define a Lexicon query method\n * - {@link l.procedure | l.procedure()} - Define a Lexicon procedure method\n * - {@link l.subscription | l.subscription()} - Define a Lexicon subscription method\n *\n * @packageDocumentation\n */\n\nexport * 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.14",
3
+ "version": "0.0.16",
4
4
  "license": "MIT",
5
5
  "description": "Lexicon tooling for AT",
6
6
  "keywords": [
@@ -30,18 +30,20 @@
30
30
  "exports": {
31
31
  ".": {
32
32
  "types": "./dist/index.d.ts",
33
+ "browser": "./dist/index.js",
34
+ "import": "./dist/index.js",
33
35
  "default": "./dist/index.js"
34
36
  }
35
37
  },
36
38
  "dependencies": {
37
39
  "tslib": "^2.8.1",
38
40
  "yargs": "^17.0.0",
39
- "@atproto/lex-builder": "^0.0.13",
40
- "@atproto/lex-client": "^0.0.11",
41
- "@atproto/lex-data": "^0.0.10",
42
- "@atproto/lex-json": "^0.0.10",
43
- "@atproto/lex-installer": "^0.0.14",
44
- "@atproto/lex-schema": "^0.0.11"
41
+ "@atproto/lex-builder": "^0.0.15",
42
+ "@atproto/lex-client": "^0.0.12",
43
+ "@atproto/lex-data": "^0.0.11",
44
+ "@atproto/lex-json": "^0.0.11",
45
+ "@atproto/lex-installer": "^0.0.16",
46
+ "@atproto/lex-schema": "^0.0.12"
45
47
  },
46
48
  "devDependencies": {
47
49
  "@types/yargs": "^17.0.33",