@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 +27 -0
- package/README.md +176 -477
- package/dist/index.d.ts +62 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -1
- package/package.json +9 -7
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
|
-
- [
|
|
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
|
-
- [
|
|
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
|
|
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
|
|
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(
|
|
426
|
-
|
|
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
|
-
###
|
|
446
|
+
### CBOR Encoding
|
|
430
447
|
|
|
431
|
-
Use `@atproto/lex-cbor` to encode/decode the data model to/from
|
|
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
|
|
454
|
+
// Encode data model to CBOR bytes
|
|
438
455
|
const cborBytes = encode(someLexValue)
|
|
439
456
|
|
|
440
|
-
// Decode
|
|
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
|
|
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) =>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
####
|
|
666
|
+
#### XrpcFailure Type
|
|
849
667
|
|
|
850
|
-
|
|
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 {
|
|
854
|
-
|
|
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: {
|
|
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
|
|
869
|
-
//
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
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 `
|
|
900
|
-
|
|
901
|
-
1.
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
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
|
|
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
|
-
###
|
|
890
|
+
### Blob references
|
|
1132
891
|
|
|
1133
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1152
|
-
type
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
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
|
-
|
|
1214
|
-
|
|
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
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
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';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
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":"
|
|
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.
|
|
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.
|
|
40
|
-
"@atproto/lex-client": "^0.0.
|
|
41
|
-
"@atproto/lex-data": "^0.0.
|
|
42
|
-
"@atproto/lex-json": "^0.0.
|
|
43
|
-
"@atproto/lex-installer": "^0.0.
|
|
44
|
-
"@atproto/lex-schema": "^0.0.
|
|
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",
|