@atproto/lex 0.0.19 โ†’ 0.0.20

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +58 -15
  3. package/package.json +7 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atproto/lex
2
2
 
3
+ ## 0.0.20
4
+
5
+ ### Patch Changes
6
+
7
+ - [#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
8
+
9
+ - 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)]:
10
+ - @atproto/lex-schema@0.0.14
11
+ - @atproto/lex-data@0.0.13
12
+ - @atproto/lex-client@0.0.15
13
+ - @atproto/lex-installer@0.0.20
14
+ - @atproto/lex-builder@0.0.17
15
+ - @atproto/lex-json@0.0.13
16
+
3
17
  ## 0.0.19
4
18
 
5
19
  ### Patch Changes
package/README.md CHANGED
@@ -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)
@@ -223,13 +224,14 @@ function renderPost(p: app.bsky.feed.post.Main) {
223
224
  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
225
 
225
226
  ```typescript
227
+ import { l } from '@atproto/lex'
226
228
  import * as app from './lexicons/app.js'
227
229
 
228
230
  // variable type will be inferred as "app.bsky.feed.post.Main"
229
231
  const post = app.bsky.feed.post.$build({
230
232
  // No need to specify $type when using $build
231
233
  text: 'Hello, world!',
232
- createdAt: new Date().toISOString(),
234
+ createdAt: l.toDatetimeString(new Date()),
233
235
  })
234
236
  ```
235
237
 
@@ -263,12 +265,13 @@ console.log(app.bsky.actor.defs.profileViewBasic.$type) // 'app.bsky.actor.defs#
263
265
  Returns `true` if data matches the schema, `false` otherwise. Acts as a TypeScript type guard:
264
266
 
265
267
  ```typescript
268
+ import { l } from '@atproto/lex'
266
269
  import * as app from './lexicons/app.js'
267
270
 
268
271
  const data = {
269
272
  $type: 'app.bsky.feed.post',
270
273
  text: 'Hello!',
271
- createdAt: new Date().toISOString(),
274
+ createdAt: l.toDatetimeString(new Date()),
272
275
  }
273
276
 
274
277
  if (app.bsky.feed.post.$check(data)) {
@@ -282,13 +285,14 @@ if (app.bsky.feed.post.$check(data)) {
282
285
  Validates and returns typed data, throwing an error if validation fails:
283
286
 
284
287
  ```typescript
288
+ import { l } from '@atproto/lex'
285
289
  import * as app from './lexicons/app.js'
286
290
 
287
291
  try {
288
292
  const post = app.bsky.feed.post.$main.$parse({
289
293
  $type: 'app.bsky.feed.post',
290
294
  text: 'Hello!',
291
- createdAt: new Date().toISOString(),
295
+ createdAt: l.toDatetimeString(new Date()),
292
296
  })
293
297
  // post is now typed and validated
294
298
  console.log(post.text)
@@ -306,12 +310,13 @@ try {
306
310
  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
311
 
308
312
  ```typescript
313
+ import { l } from '@atproto/lex'
309
314
  import * as app from './lexicons/app.js'
310
315
 
311
316
  const value = {
312
317
  $type: 'app.bsky.feed.post',
313
318
  text: 'Hello!',
314
- createdAt: new Date().toISOString(),
319
+ createdAt: l.toDatetimeString(new Date()),
315
320
  }
316
321
 
317
322
  // Throws if no valid
@@ -325,12 +330,13 @@ value === result // true
325
330
  Returns a detailed validation result object without throwing:
326
331
 
327
332
  ```typescript
333
+ import { l } from '@atproto/lex'
328
334
  import * as app from './lexicons/app.js'
329
335
 
330
336
  const result = app.bsky.feed.post.$safeParse({
331
337
  $type: 'app.bsky.feed.post',
332
338
  text: 'Hello!',
333
- createdAt: new Date().toISOString(),
339
+ createdAt: l.toDatetimeString(new Date()),
334
340
  })
335
341
 
336
342
  if (result.success) {
@@ -345,6 +351,7 @@ if (result.success) {
345
351
  Builds data without needing to specify the `$type` property, and properly types the result:
346
352
 
347
353
  ```typescript
354
+ import { l } from '@atproto/lex'
348
355
  import * as app from './lexicons/app.js'
349
356
 
350
357
  // The type of the "like" variable will be "app.bsky.feed.like.Main"
@@ -353,7 +360,7 @@ const like = app.bsky.feed.like.$build({
353
360
  uri: 'at://did:plc:abc/app.bsky.feed.post/123',
354
361
  cid: 'bafyrei...',
355
362
  },
356
- createdAt: new Date().toISOString(),
363
+ createdAt: l.toDatetimeString(new Date()),
357
364
  })
358
365
  ```
359
366
 
@@ -605,11 +612,12 @@ const timeline = await client.call(
605
612
  Create a new record un the authenticated user's repo.
606
613
 
607
614
  ```typescript
615
+ import { l } from '@atproto/lex'
608
616
  import * as app from './lexicons/app.js'
609
617
 
610
618
  const result = await client.create(app.bsky.feed.post, {
611
619
  text: 'Hello, world!',
612
- createdAt: new Date().toISOString(),
620
+ createdAt: l.toDatetimeString(new Date()),
613
621
  })
614
622
 
615
623
  console.log(result.uri) // at://did:plc:...
@@ -757,7 +765,7 @@ if (result.success) {
757
765
  // All XrpcFailure types have these properties:
758
766
  result.shouldRetry() // boolean - whether the error is transient
759
767
 
760
- if (result.matchesSchema()) {
768
+ if (result.matchesSchemaErrors()) {
761
769
  // Check if the error matches a declared error in the schema.
762
770
  // TypeScript knows this is a declared error for the method.
763
771
  result.error // "HandleNotFound"
@@ -850,7 +858,7 @@ console.log(response.body)
850
858
 
851
859
  ## Utilities
852
860
 
853
- Various utilities for working with CIDs, string lengths, language tags, and low-level JSON encoding are exported from the package:
861
+ Various utilities for working with CIDs, datetime strings, string lengths, language tags, and low-level JSON encoding are exported from the package:
854
862
 
855
863
  ```typescript
856
864
  import {
@@ -859,6 +867,12 @@ import {
859
867
  ifCid, // Coerce to Cid or null
860
868
  isCid, // Type guard for Cid values
861
869
 
870
+ // Datetime string utilities
871
+ toDatetimeString, // Convert Date to DatetimeString (throws on invalid)
872
+ asDatetimeString, // Cast string to DatetimeString (throws on invalid)
873
+ isDatetimeString, // Type guard for DatetimeString
874
+ ifDatetimeString, // Returns DatetimeString or undefined
875
+
862
876
  // Blob references
863
877
  BlobRef, // { $type: 'blob', ref: Cid, mimeType: string, size: number }
864
878
  isBlobRef, // Type guard for BlobRef objects
@@ -886,6 +900,35 @@ utf8Len('๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ') // 25
886
900
  isLanguageString('en-US') // true
887
901
  ```
888
902
 
903
+ ### Datetime Strings
904
+
905
+ 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`:
906
+
907
+ - **`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.
908
+ - **`asDatetimeString(input: string)`** - Validates and casts an arbitrary string to `DatetimeString`, throwing an `InvalidDatetimeError` if the string does not conform.
909
+ - **`isDatetimeString(input)`** - Type guard that returns `true` if the input is a valid `DatetimeString`.
910
+ - **`ifDatetimeString(input)`** - Returns the input as a `DatetimeString` if valid, or `undefined` otherwise.
911
+ - **`currentDatetimeString()`** - Returns the current date and time as `DatetimeString`.
912
+
913
+ ```typescript
914
+ import { l } from '@atproto/lex'
915
+
916
+ // Convert a Date object to a DatetimeString (or throws)
917
+ const someDate = new Date('2024-01-15T12:30:00Z')
918
+ const now = l.toDatetimeString(someDate)
919
+
920
+ // Get the current datetime as a DatetimeString
921
+ const now = l.currentDatetimeString()
922
+
923
+ // Validate and cast an existing string
924
+ const dt = l.asDatetimeString('2024-01-15T12:30:00.000Z')
925
+
926
+ // Type guard for conditional checks
927
+ if (l.isDatetimeString(someString)) {
928
+ // someString is now typed as DatetimeString
929
+ }
930
+ ```
931
+
889
932
  ## Advanced Usage
890
933
 
891
934
  ### Workflow Integration
@@ -991,7 +1034,7 @@ Actions receive:
991
1034
  Actions are called using `client.call()`, the same method used for XRPC queries and procedures:
992
1035
 
993
1036
  ```typescript
994
- import { Action, Client } from '@atproto/lex'
1037
+ import { Action, Client, l } from '@atproto/lex'
995
1038
  import * as app from './lexicons/app.js'
996
1039
 
997
1040
  // Define an action
@@ -1005,7 +1048,7 @@ export const likePost: Action<
1005
1048
  app.bsky.feed.like,
1006
1049
  {
1007
1050
  subject: { uri, cid },
1008
- createdAt: new Date().toISOString(),
1051
+ createdAt: l.toDatetimeString(new Date()),
1009
1052
  },
1010
1053
  options,
1011
1054
  )
@@ -1206,7 +1249,7 @@ Actions enable you to create high-level, convenience APIs similar to [@atproto/a
1206
1249
  #### Creating Posts
1207
1250
 
1208
1251
  ```typescript
1209
- import { Action } from '@atproto/lex'
1252
+ import { Action, l } from '@atproto/lex'
1210
1253
  import * as app from './lexicons/app.js'
1211
1254
 
1212
1255
  type PostInput = Partial<app.bsky.feed.post.Main> &
@@ -1221,7 +1264,7 @@ export const post: Action<PostInput, { uri: string; cid: string }> = async (
1221
1264
  app.bsky.feed.post,
1222
1265
  {
1223
1266
  ...record,
1224
- createdAt: record.createdAt || new Date().toISOString(),
1267
+ createdAt: record.createdAt || l.currentDatetimeString(),
1225
1268
  },
1226
1269
  options,
1227
1270
  )
@@ -1237,7 +1280,7 @@ await client.call(post, {
1237
1280
  #### Following Users
1238
1281
 
1239
1282
  ```typescript
1240
- import { Action } from '@atproto/lex'
1283
+ import { Action, l } from '@atproto/lex'
1241
1284
  import { AtUri } from '@atproto/syntax'
1242
1285
  import * as app from './lexicons/app.js'
1243
1286
 
@@ -1249,7 +1292,7 @@ export const follow: Action<
1249
1292
  app.bsky.graph.follow,
1250
1293
  {
1251
1294
  subject: did,
1252
- createdAt: new Date().toISOString(),
1295
+ createdAt: l.currentDatetimeString(),
1253
1296
  },
1254
1297
  options,
1255
1298
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/lex",
3
- "version": "0.0.19",
3
+ "version": "0.0.20",
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.16",
42
- "@atproto/lex-client": "^0.0.14",
43
- "@atproto/lex-data": "^0.0.12",
44
- "@atproto/lex-json": "^0.0.12",
45
- "@atproto/lex-installer": "^0.0.19",
46
- "@atproto/lex-schema": "^0.0.13"
41
+ "@atproto/lex-builder": "^0.0.17",
42
+ "@atproto/lex-client": "^0.0.15",
43
+ "@atproto/lex-data": "^0.0.13",
44
+ "@atproto/lex-json": "^0.0.13",
45
+ "@atproto/lex-installer": "^0.0.20",
46
+ "@atproto/lex-schema": "^0.0.14"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/yargs": "^17.0.33",