@atproto/lex 0.0.19 โ 0.0.21
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 +24 -0
- package/README.md +87 -16
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @atproto/lex
|
|
2
2
|
|
|
3
|
+
## 0.0.21
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`5a2f884`](https://github.com/bluesky-social/atproto/commit/5a2f8847efd91252971fa243d21bd52ada7aa8f4), [`3dc3791`](https://github.com/bluesky-social/atproto/commit/3dc37915436dec7e18c7dc9dcf01b72cad53fdbe), [`3dc3791`](https://github.com/bluesky-social/atproto/commit/3dc37915436dec7e18c7dc9dcf01b72cad53fdbe), [`3dc3791`](https://github.com/bluesky-social/atproto/commit/3dc37915436dec7e18c7dc9dcf01b72cad53fdbe), [`3dc3791`](https://github.com/bluesky-social/atproto/commit/3dc37915436dec7e18c7dc9dcf01b72cad53fdbe), [`112b159`](https://github.com/bluesky-social/atproto/commit/112b159ec293a5c3fff41237474a3788fc47f9ca), [`3dc3791`](https://github.com/bluesky-social/atproto/commit/3dc37915436dec7e18c7dc9dcf01b72cad53fdbe), [`3dc3791`](https://github.com/bluesky-social/atproto/commit/3dc37915436dec7e18c7dc9dcf01b72cad53fdbe)]:
|
|
8
|
+
- @atproto/lex-client@0.0.16
|
|
9
|
+
- @atproto/lex-schema@0.0.15
|
|
10
|
+
- @atproto/lex-builder@0.0.18
|
|
11
|
+
- @atproto/lex-installer@0.0.21
|
|
12
|
+
|
|
13
|
+
## 0.0.20
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- [#4689](https://github.com/bluesky-social/atproto/pull/4689) [`f7c2610`](https://github.com/bluesky-social/atproto/commit/f7c26103a6d4e24e5bedbb6fd908be140420e0dd) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Update readme
|
|
18
|
+
|
|
19
|
+
- Updated dependencies [[`52834ab`](https://github.com/bluesky-social/atproto/commit/52834aba182da8df3611fd9dff924e6c6a3973a7), [`f7c2610`](https://github.com/bluesky-social/atproto/commit/f7c26103a6d4e24e5bedbb6fd908be140420e0dd), [`52834ab`](https://github.com/bluesky-social/atproto/commit/52834aba182da8df3611fd9dff924e6c6a3973a7), [`52834ab`](https://github.com/bluesky-social/atproto/commit/52834aba182da8df3611fd9dff924e6c6a3973a7), [`52834ab`](https://github.com/bluesky-social/atproto/commit/52834aba182da8df3611fd9dff924e6c6a3973a7), [`52834ab`](https://github.com/bluesky-social/atproto/commit/52834aba182da8df3611fd9dff924e6c6a3973a7), [`52834ab`](https://github.com/bluesky-social/atproto/commit/52834aba182da8df3611fd9dff924e6c6a3973a7), [`52834ab`](https://github.com/bluesky-social/atproto/commit/52834aba182da8df3611fd9dff924e6c6a3973a7), [`52834ab`](https://github.com/bluesky-social/atproto/commit/52834aba182da8df3611fd9dff924e6c6a3973a7), [`52834ab`](https://github.com/bluesky-social/atproto/commit/52834aba182da8df3611fd9dff924e6c6a3973a7)]:
|
|
20
|
+
- @atproto/lex-schema@0.0.14
|
|
21
|
+
- @atproto/lex-data@0.0.13
|
|
22
|
+
- @atproto/lex-client@0.0.15
|
|
23
|
+
- @atproto/lex-installer@0.0.20
|
|
24
|
+
- @atproto/lex-builder@0.0.17
|
|
25
|
+
- @atproto/lex-json@0.0.13
|
|
26
|
+
|
|
3
27
|
## 0.0.19
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ const newPost = app.bsky.feed.post.$build({
|
|
|
20
20
|
app.bsky.actor.profile.$validate({
|
|
21
21
|
$type: 'app.bsky.actor.profile',
|
|
22
22
|
displayName: 'Ha'.repeat(32) + '!',
|
|
23
|
-
}) // Error: grapheme too big (maximum 64) at $.displayName
|
|
23
|
+
}) // Error: grapheme too big (maximum 64, got 65) at $.displayName
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
```typescript
|
|
@@ -67,6 +67,7 @@ const posts = await client.list(app.bsky.feed.post, { limit: 10 })
|
|
|
67
67
|
- [Labeler Configuration](#labeler-configuration)
|
|
68
68
|
- [Low-Level XRPC](#low-level-xrpc)
|
|
69
69
|
- [Utilities](#utilities)
|
|
70
|
+
- [Datetime Strings](#datetime-strings)
|
|
70
71
|
- [Advanced Usage](#advanced-usage)
|
|
71
72
|
- [Workflow Integration](#workflow-integration)
|
|
72
73
|
- [Tree-Shaking](#tree-shaking)
|
|
@@ -74,6 +75,7 @@ const posts = await client.list(app.bsky.feed.post, { limit: 10 })
|
|
|
74
75
|
- [Actions](#actions)
|
|
75
76
|
- [Creating a Client from Another Client](#creating-a-client-from-another-client)
|
|
76
77
|
- [Building Library-Style APIs with Actions](#building-library-style-apis-with-actions)
|
|
78
|
+
- [Standard Schema Compatibility](#standard-schema-compatibility)
|
|
77
79
|
- [License](#license)
|
|
78
80
|
|
|
79
81
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
|
@@ -223,13 +225,14 @@ function renderPost(p: app.bsky.feed.post.Main) {
|
|
|
223
225
|
It is recommended to use the generated builders to create data that conforms to the schema. This ensures that all required fields are present.
|
|
224
226
|
|
|
225
227
|
```typescript
|
|
228
|
+
import { l } from '@atproto/lex'
|
|
226
229
|
import * as app from './lexicons/app.js'
|
|
227
230
|
|
|
228
231
|
// variable type will be inferred as "app.bsky.feed.post.Main"
|
|
229
232
|
const post = app.bsky.feed.post.$build({
|
|
230
233
|
// No need to specify $type when using $build
|
|
231
234
|
text: 'Hello, world!',
|
|
232
|
-
createdAt: new Date()
|
|
235
|
+
createdAt: l.toDatetimeString(new Date()),
|
|
233
236
|
})
|
|
234
237
|
```
|
|
235
238
|
|
|
@@ -263,12 +266,13 @@ console.log(app.bsky.actor.defs.profileViewBasic.$type) // 'app.bsky.actor.defs#
|
|
|
263
266
|
Returns `true` if data matches the schema, `false` otherwise. Acts as a TypeScript type guard:
|
|
264
267
|
|
|
265
268
|
```typescript
|
|
269
|
+
import { l } from '@atproto/lex'
|
|
266
270
|
import * as app from './lexicons/app.js'
|
|
267
271
|
|
|
268
272
|
const data = {
|
|
269
273
|
$type: 'app.bsky.feed.post',
|
|
270
274
|
text: 'Hello!',
|
|
271
|
-
createdAt: new Date()
|
|
275
|
+
createdAt: l.toDatetimeString(new Date()),
|
|
272
276
|
}
|
|
273
277
|
|
|
274
278
|
if (app.bsky.feed.post.$check(data)) {
|
|
@@ -282,13 +286,14 @@ if (app.bsky.feed.post.$check(data)) {
|
|
|
282
286
|
Validates and returns typed data, throwing an error if validation fails:
|
|
283
287
|
|
|
284
288
|
```typescript
|
|
289
|
+
import { l } from '@atproto/lex'
|
|
285
290
|
import * as app from './lexicons/app.js'
|
|
286
291
|
|
|
287
292
|
try {
|
|
288
293
|
const post = app.bsky.feed.post.$main.$parse({
|
|
289
294
|
$type: 'app.bsky.feed.post',
|
|
290
295
|
text: 'Hello!',
|
|
291
|
-
createdAt: new Date()
|
|
296
|
+
createdAt: l.toDatetimeString(new Date()),
|
|
292
297
|
})
|
|
293
298
|
// post is now typed and validated
|
|
294
299
|
console.log(post.text)
|
|
@@ -306,12 +311,13 @@ try {
|
|
|
306
311
|
Validates an existing value against a schema, returning the value itself if, and only if, it already matches the schema (ie. without applying defaults or coercion).
|
|
307
312
|
|
|
308
313
|
```typescript
|
|
314
|
+
import { l } from '@atproto/lex'
|
|
309
315
|
import * as app from './lexicons/app.js'
|
|
310
316
|
|
|
311
317
|
const value = {
|
|
312
318
|
$type: 'app.bsky.feed.post',
|
|
313
319
|
text: 'Hello!',
|
|
314
|
-
createdAt: new Date()
|
|
320
|
+
createdAt: l.toDatetimeString(new Date()),
|
|
315
321
|
}
|
|
316
322
|
|
|
317
323
|
// Throws if no valid
|
|
@@ -325,12 +331,13 @@ value === result // true
|
|
|
325
331
|
Returns a detailed validation result object without throwing:
|
|
326
332
|
|
|
327
333
|
```typescript
|
|
334
|
+
import { l } from '@atproto/lex'
|
|
328
335
|
import * as app from './lexicons/app.js'
|
|
329
336
|
|
|
330
337
|
const result = app.bsky.feed.post.$safeParse({
|
|
331
338
|
$type: 'app.bsky.feed.post',
|
|
332
339
|
text: 'Hello!',
|
|
333
|
-
createdAt: new Date()
|
|
340
|
+
createdAt: l.toDatetimeString(new Date()),
|
|
334
341
|
})
|
|
335
342
|
|
|
336
343
|
if (result.success) {
|
|
@@ -345,6 +352,7 @@ if (result.success) {
|
|
|
345
352
|
Builds data without needing to specify the `$type` property, and properly types the result:
|
|
346
353
|
|
|
347
354
|
```typescript
|
|
355
|
+
import { l } from '@atproto/lex'
|
|
348
356
|
import * as app from './lexicons/app.js'
|
|
349
357
|
|
|
350
358
|
// The type of the "like" variable will be "app.bsky.feed.like.Main"
|
|
@@ -353,7 +361,7 @@ const like = app.bsky.feed.like.$build({
|
|
|
353
361
|
uri: 'at://did:plc:abc/app.bsky.feed.post/123',
|
|
354
362
|
cid: 'bafyrei...',
|
|
355
363
|
},
|
|
356
|
-
createdAt: new Date()
|
|
364
|
+
createdAt: l.toDatetimeString(new Date()),
|
|
357
365
|
})
|
|
358
366
|
```
|
|
359
367
|
|
|
@@ -605,11 +613,12 @@ const timeline = await client.call(
|
|
|
605
613
|
Create a new record un the authenticated user's repo.
|
|
606
614
|
|
|
607
615
|
```typescript
|
|
616
|
+
import { l } from '@atproto/lex'
|
|
608
617
|
import * as app from './lexicons/app.js'
|
|
609
618
|
|
|
610
619
|
const result = await client.create(app.bsky.feed.post, {
|
|
611
620
|
text: 'Hello, world!',
|
|
612
|
-
createdAt: new Date()
|
|
621
|
+
createdAt: l.toDatetimeString(new Date()),
|
|
613
622
|
})
|
|
614
623
|
|
|
615
624
|
console.log(result.uri) // at://did:plc:...
|
|
@@ -757,7 +766,7 @@ if (result.success) {
|
|
|
757
766
|
// All XrpcFailure types have these properties:
|
|
758
767
|
result.shouldRetry() // boolean - whether the error is transient
|
|
759
768
|
|
|
760
|
-
if (result.
|
|
769
|
+
if (result.matchesSchemaErrors()) {
|
|
761
770
|
// Check if the error matches a declared error in the schema.
|
|
762
771
|
// TypeScript knows this is a declared error for the method.
|
|
763
772
|
result.error // "HandleNotFound"
|
|
@@ -850,7 +859,7 @@ console.log(response.body)
|
|
|
850
859
|
|
|
851
860
|
## Utilities
|
|
852
861
|
|
|
853
|
-
Various utilities for working with CIDs, string lengths, language tags, and low-level JSON encoding are exported from the package:
|
|
862
|
+
Various utilities for working with CIDs, datetime strings, string lengths, language tags, and low-level JSON encoding are exported from the package:
|
|
854
863
|
|
|
855
864
|
```typescript
|
|
856
865
|
import {
|
|
@@ -859,6 +868,12 @@ import {
|
|
|
859
868
|
ifCid, // Coerce to Cid or null
|
|
860
869
|
isCid, // Type guard for Cid values
|
|
861
870
|
|
|
871
|
+
// Datetime string utilities
|
|
872
|
+
toDatetimeString, // Convert Date to DatetimeString (throws on invalid)
|
|
873
|
+
asDatetimeString, // Cast string to DatetimeString (throws on invalid)
|
|
874
|
+
isDatetimeString, // Type guard for DatetimeString
|
|
875
|
+
ifDatetimeString, // Returns DatetimeString or undefined
|
|
876
|
+
|
|
862
877
|
// Blob references
|
|
863
878
|
BlobRef, // { $type: 'blob', ref: Cid, mimeType: string, size: number }
|
|
864
879
|
isBlobRef, // Type guard for BlobRef objects
|
|
@@ -886,6 +901,35 @@ utf8Len('๐จโ๐ฉโ๐งโ๐ฆ') // 25
|
|
|
886
901
|
isLanguageString('en-US') // true
|
|
887
902
|
```
|
|
888
903
|
|
|
904
|
+
### Datetime Strings
|
|
905
|
+
|
|
906
|
+
Many AT Protocol records (such as posts, likes, and follows) include a `createdAt` field that expects a valid `DatetimeString`. While `new Date().toISOString()` produces a string that looks like a valid datetime, it is not guaranteed to always conform to the AT Protocol's [datetime format requirements](https://atproto.com/specs/lexicon#datetime) (for example, `Date` objects representing dates before year 10 or after year 9999 will produce non-conforming strings). To ensure correctness and type safety, use the `DatetimeString` utilities exported from `@atproto/lex`:
|
|
907
|
+
|
|
908
|
+
- **`toDatetimeString(date: Date)`** - Converts a `Date` object into a valid `DatetimeString`, throwing an `InvalidDatetimeError` if the date cannot be represented as a valid AT Protocol datetime.
|
|
909
|
+
- **`asDatetimeString(input: string)`** - Validates and casts an arbitrary string to `DatetimeString`, throwing an `InvalidDatetimeError` if the string does not conform.
|
|
910
|
+
- **`isDatetimeString(input)`** - Type guard that returns `true` if the input is a valid `DatetimeString`.
|
|
911
|
+
- **`ifDatetimeString(input)`** - Returns the input as a `DatetimeString` if valid, or `undefined` otherwise.
|
|
912
|
+
- **`currentDatetimeString()`** - Returns the current date and time as `DatetimeString`.
|
|
913
|
+
|
|
914
|
+
```typescript
|
|
915
|
+
import { l } from '@atproto/lex'
|
|
916
|
+
|
|
917
|
+
// Convert a Date object to a DatetimeString (or throws)
|
|
918
|
+
const someDate = new Date('2024-01-15T12:30:00Z')
|
|
919
|
+
const now = l.toDatetimeString(someDate)
|
|
920
|
+
|
|
921
|
+
// Get the current datetime as a DatetimeString
|
|
922
|
+
const now = l.currentDatetimeString()
|
|
923
|
+
|
|
924
|
+
// Validate and cast an existing string
|
|
925
|
+
const dt = l.asDatetimeString('2024-01-15T12:30:00.000Z')
|
|
926
|
+
|
|
927
|
+
// Type guard for conditional checks
|
|
928
|
+
if (l.isDatetimeString(someString)) {
|
|
929
|
+
// someString is now typed as DatetimeString
|
|
930
|
+
}
|
|
931
|
+
```
|
|
932
|
+
|
|
889
933
|
## Advanced Usage
|
|
890
934
|
|
|
891
935
|
### Workflow Integration
|
|
@@ -991,7 +1035,7 @@ Actions receive:
|
|
|
991
1035
|
Actions are called using `client.call()`, the same method used for XRPC queries and procedures:
|
|
992
1036
|
|
|
993
1037
|
```typescript
|
|
994
|
-
import { Action, Client } from '@atproto/lex'
|
|
1038
|
+
import { Action, Client, l } from '@atproto/lex'
|
|
995
1039
|
import * as app from './lexicons/app.js'
|
|
996
1040
|
|
|
997
1041
|
// Define an action
|
|
@@ -1005,7 +1049,7 @@ export const likePost: Action<
|
|
|
1005
1049
|
app.bsky.feed.like,
|
|
1006
1050
|
{
|
|
1007
1051
|
subject: { uri, cid },
|
|
1008
|
-
createdAt: new Date()
|
|
1052
|
+
createdAt: l.toDatetimeString(new Date()),
|
|
1009
1053
|
},
|
|
1010
1054
|
options,
|
|
1011
1055
|
)
|
|
@@ -1206,7 +1250,7 @@ Actions enable you to create high-level, convenience APIs similar to [@atproto/a
|
|
|
1206
1250
|
#### Creating Posts
|
|
1207
1251
|
|
|
1208
1252
|
```typescript
|
|
1209
|
-
import { Action } from '@atproto/lex'
|
|
1253
|
+
import { Action, l } from '@atproto/lex'
|
|
1210
1254
|
import * as app from './lexicons/app.js'
|
|
1211
1255
|
|
|
1212
1256
|
type PostInput = Partial<app.bsky.feed.post.Main> &
|
|
@@ -1221,7 +1265,7 @@ export const post: Action<PostInput, { uri: string; cid: string }> = async (
|
|
|
1221
1265
|
app.bsky.feed.post,
|
|
1222
1266
|
{
|
|
1223
1267
|
...record,
|
|
1224
|
-
createdAt: record.createdAt ||
|
|
1268
|
+
createdAt: record.createdAt || l.currentDatetimeString(),
|
|
1225
1269
|
},
|
|
1226
1270
|
options,
|
|
1227
1271
|
)
|
|
@@ -1237,7 +1281,7 @@ await client.call(post, {
|
|
|
1237
1281
|
#### Following Users
|
|
1238
1282
|
|
|
1239
1283
|
```typescript
|
|
1240
|
-
import { Action } from '@atproto/lex'
|
|
1284
|
+
import { Action, l } from '@atproto/lex'
|
|
1241
1285
|
import { AtUri } from '@atproto/syntax'
|
|
1242
1286
|
import * as app from './lexicons/app.js'
|
|
1243
1287
|
|
|
@@ -1249,7 +1293,7 @@ export const follow: Action<
|
|
|
1249
1293
|
app.bsky.graph.follow,
|
|
1250
1294
|
{
|
|
1251
1295
|
subject: did,
|
|
1252
|
-
createdAt:
|
|
1296
|
+
createdAt: l.currentDatetimeString(),
|
|
1253
1297
|
},
|
|
1254
1298
|
options,
|
|
1255
1299
|
)
|
|
@@ -1380,6 +1424,33 @@ await client.call(actions.post, { text: 'Hello!' })
|
|
|
1380
1424
|
5. **Retries**: Implement retry logic for operations with optimistic concurrency control
|
|
1381
1425
|
6. **Tree-shaking**: Export actions individually to allow tree-shaking (instead of bundling them in a single class)
|
|
1382
1426
|
|
|
1427
|
+
### Standard Schema Compatibility
|
|
1428
|
+
|
|
1429
|
+
All generated schemas implement the [Standard Schema](https://standardschema.dev/) interface (`StandardSchemaV1`), which means they can be used with any library or framework that supports Standard Schema, such as form validation libraries, API frameworks, and more.
|
|
1430
|
+
|
|
1431
|
+
Every `Schema` instance exposes a `~standard` property conforming to the spec:
|
|
1432
|
+
|
|
1433
|
+
```typescript
|
|
1434
|
+
import * as app from './lexicons/app.js'
|
|
1435
|
+
|
|
1436
|
+
// Use with any Standard Schema-compatible library
|
|
1437
|
+
const schema = app.bsky.feed.post
|
|
1438
|
+
|
|
1439
|
+
schema['~standard'].version // 1
|
|
1440
|
+
schema['~standard'].vendor // '@atproto/lex-schema'
|
|
1441
|
+
|
|
1442
|
+
// Validate using the Standard Schema interface
|
|
1443
|
+
const result = schema['~standard'].validate(someData)
|
|
1444
|
+
|
|
1445
|
+
if ('value' in result) {
|
|
1446
|
+
console.log(result.value) // Parsed and validated data
|
|
1447
|
+
} else {
|
|
1448
|
+
console.error(result.issues)
|
|
1449
|
+
}
|
|
1450
|
+
```
|
|
1451
|
+
|
|
1452
|
+
When validated through the Standard Schema interface, schemas operate in "parse" mode, meaning transformations like defaults and coercions are applied to the output.
|
|
1453
|
+
|
|
1383
1454
|
## License
|
|
1384
1455
|
|
|
1385
1456
|
MIT or Apache2
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/lex",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.21",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Lexicon tooling for AT",
|
|
6
6
|
"keywords": [
|
|
@@ -38,12 +38,12 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"tslib": "^2.8.1",
|
|
40
40
|
"yargs": "^17.0.0",
|
|
41
|
-
"@atproto/lex-builder": "^0.0.
|
|
42
|
-
"@atproto/lex-client": "^0.0.
|
|
43
|
-
"@atproto/lex-data": "^0.0.
|
|
44
|
-
"@atproto/lex-json": "^0.0.
|
|
45
|
-
"@atproto/lex-installer": "^0.0.
|
|
46
|
-
"@atproto/lex-schema": "^0.0.
|
|
41
|
+
"@atproto/lex-builder": "^0.0.18",
|
|
42
|
+
"@atproto/lex-client": "^0.0.16",
|
|
43
|
+
"@atproto/lex-data": "^0.0.13",
|
|
44
|
+
"@atproto/lex-json": "^0.0.13",
|
|
45
|
+
"@atproto/lex-installer": "^0.0.21",
|
|
46
|
+
"@atproto/lex-schema": "^0.0.15"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@types/yargs": "^17.0.33",
|