@atproto/lex-schema 0.0.3 → 0.0.5

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 (109) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/core/$type.d.ts +7 -0
  3. package/dist/core/$type.d.ts.map +1 -1
  4. package/dist/core/$type.js.map +1 -1
  5. package/dist/core/result.d.ts +7 -6
  6. package/dist/core/result.d.ts.map +1 -1
  7. package/dist/core/result.js +9 -8
  8. package/dist/core/result.js.map +1 -1
  9. package/dist/core/string-format.d.ts +37 -26
  10. package/dist/core/string-format.d.ts.map +1 -1
  11. package/dist/core/string-format.js +66 -59
  12. package/dist/core/string-format.js.map +1 -1
  13. package/dist/core/types.d.ts +3 -0
  14. package/dist/core/types.d.ts.map +1 -1
  15. package/dist/core/types.js.map +1 -1
  16. package/dist/external.d.ts +7 -6
  17. package/dist/external.d.ts.map +1 -1
  18. package/dist/external.js +1 -0
  19. package/dist/external.js.map +1 -1
  20. package/dist/helpers.d.ts +36 -0
  21. package/dist/helpers.d.ts.map +1 -0
  22. package/dist/helpers.js +3 -0
  23. package/dist/helpers.js.map +1 -0
  24. package/dist/schema/blob.d.ts +1 -0
  25. package/dist/schema/blob.d.ts.map +1 -1
  26. package/dist/schema/blob.js +32 -18
  27. package/dist/schema/blob.js.map +1 -1
  28. package/dist/schema/custom.js +1 -1
  29. package/dist/schema/custom.js.map +1 -1
  30. package/dist/schema/integer.js +1 -1
  31. package/dist/schema/integer.js.map +1 -1
  32. package/dist/schema/params.d.ts +0 -1
  33. package/dist/schema/params.d.ts.map +1 -1
  34. package/dist/schema/params.js.map +1 -1
  35. package/dist/schema/payload.d.ts +17 -15
  36. package/dist/schema/payload.d.ts.map +1 -1
  37. package/dist/schema/payload.js +28 -0
  38. package/dist/schema/payload.js.map +1 -1
  39. package/dist/schema/procedure.d.ts +3 -6
  40. package/dist/schema/procedure.d.ts.map +1 -1
  41. package/dist/schema/procedure.js +1 -0
  42. package/dist/schema/procedure.js.map +1 -1
  43. package/dist/schema/query.d.ts +3 -5
  44. package/dist/schema/query.d.ts.map +1 -1
  45. package/dist/schema/query.js +1 -0
  46. package/dist/schema/query.js.map +1 -1
  47. package/dist/schema/record.d.ts +13 -12
  48. package/dist/schema/record.d.ts.map +1 -1
  49. package/dist/schema/record.js.map +1 -1
  50. package/dist/schema/refine.js +1 -1
  51. package/dist/schema/refine.js.map +1 -1
  52. package/dist/schema/subscription.d.ts +4 -7
  53. package/dist/schema/subscription.d.ts.map +1 -1
  54. package/dist/schema/subscription.js.map +1 -1
  55. package/dist/schema/typed-object.d.ts +7 -6
  56. package/dist/schema/typed-object.d.ts.map +1 -1
  57. package/dist/schema/typed-object.js.map +1 -1
  58. package/dist/schema/union.d.ts.map +1 -1
  59. package/dist/schema/union.js +1 -4
  60. package/dist/schema/union.js.map +1 -1
  61. package/dist/util/assertion-util.d.ts +8 -0
  62. package/dist/util/assertion-util.d.ts.map +1 -0
  63. package/dist/util/assertion-util.js +31 -0
  64. package/dist/util/assertion-util.js.map +1 -0
  65. package/dist/validation/schema.d.ts +21 -2
  66. package/dist/validation/schema.d.ts.map +1 -1
  67. package/dist/validation/schema.js +25 -2
  68. package/dist/validation/schema.js.map +1 -1
  69. package/dist/validation/validation-error.d.ts.map +1 -1
  70. package/dist/validation/validation-error.js +3 -3
  71. package/dist/validation/validation-error.js.map +1 -1
  72. package/dist/validation/validation-issue.js +10 -2
  73. package/dist/validation/validation-issue.js.map +1 -1
  74. package/dist/validation/validator.d.ts +4 -3
  75. package/dist/validation/validator.d.ts.map +1 -1
  76. package/dist/validation/validator.js +13 -10
  77. package/dist/validation/validator.js.map +1 -1
  78. package/package.json +2 -2
  79. package/src/core/$type.ts +4 -0
  80. package/src/core/result.ts +9 -8
  81. package/src/core/string-format.ts +88 -68
  82. package/src/core/types.ts +4 -0
  83. package/src/external.ts +9 -8
  84. package/src/helpers.test.ts +486 -0
  85. package/src/helpers.ts +61 -0
  86. package/src/schema/blob.test.ts +2 -4
  87. package/src/schema/blob.ts +31 -23
  88. package/src/schema/custom.test.ts +5 -5
  89. package/src/schema/custom.ts +1 -1
  90. package/src/schema/integer.ts +1 -1
  91. package/src/schema/params.ts +0 -7
  92. package/src/schema/payload.ts +67 -34
  93. package/src/schema/permission-set.test.ts +36 -36
  94. package/src/schema/procedure.test.ts +1 -62
  95. package/src/schema/procedure.ts +8 -20
  96. package/src/schema/query.test.ts +22 -69
  97. package/src/schema/query.ts +7 -14
  98. package/src/schema/record.ts +8 -4
  99. package/src/schema/refine.ts +1 -1
  100. package/src/schema/subscription.test.ts +30 -93
  101. package/src/schema/subscription.ts +11 -24
  102. package/src/schema/typed-object.ts +7 -3
  103. package/src/schema/union.ts +1 -4
  104. package/src/util/assertion-util.ts +40 -0
  105. package/src/validation/schema.ts +29 -4
  106. package/src/validation/validation-error.ts +4 -4
  107. package/src/validation/validation-issue.ts +12 -2
  108. package/src/validation/validator.ts +16 -12
  109. package/tsconfig.tests.json +1 -1
@@ -18,13 +18,6 @@ export type ParamsSchemaOutput<Shape extends ParamsSchemaShape> =
18
18
  [K in keyof Shape]: Infer<Shape[K]>
19
19
  }>
20
20
 
21
- export type InferParamsSchema<T> =
22
- T extends ParamsSchema<infer P>
23
- ? NonNullable<unknown> extends ParamsSchemaOutput<P>
24
- ? ParamsSchemaOutput<P> | undefined // Allow undefined if all params are optional
25
- : ParamsSchemaOutput<P>
26
- : never
27
-
28
21
  export class ParamsSchema<
29
22
  const Shape extends ParamsSchemaShape = ParamsSchemaShape,
30
23
  > extends Schema<ParamsSchemaOutput<Shape>> {
@@ -1,53 +1,86 @@
1
1
  import { LexValue } from '@atproto/lex-data'
2
- import { Infer, Validator } from '../validation.js'
2
+ import { Infer, Schema } from '../validation.js'
3
3
 
4
- export type LexBody<E extends string = any> = E extends `text/${string}`
5
- ? string // Text encodings always yield string bodies
6
- : E extends 'application/json'
7
- ? LexValue
8
- : Uint8Array
4
+ export type InferPayload<
5
+ P extends Payload,
6
+ B,
7
+ > = P['encoding'] extends infer E extends string
8
+ ? {
9
+ encoding: SchemaEncodingToDataEncoding<E>
10
+ body: InferPayloadBody<P, B>
11
+ }
12
+ : void | undefined
13
+
14
+ export type SchemaEncodingToDataEncoding<E extends string> = E extends '*/*'
15
+ ? `${string}/${string}`
16
+ : E extends `${infer T extends string}/*`
17
+ ? `${T}/${string}`
18
+ : E
9
19
 
10
20
  export type InferPayloadEncoding<P extends Payload> =
11
- P extends Payload<infer E, any> ? E : undefined
12
-
13
- export type InferPayloadBody<P extends Payload> =
14
- P extends Payload<any, infer S>
15
- ? S extends Validator
16
- ? Infer<S>
17
- : P extends Payload<infer E extends string>
18
- ? LexBody<E>
19
- : undefined
21
+ P['encoding'] extends string
22
+ ? SchemaEncodingToDataEncoding<P['encoding']>
20
23
  : undefined
21
24
 
22
- export type PayloadOutput<
23
- E extends string | undefined = any,
24
- S extends Validator | undefined = any,
25
- > = E extends string
26
- ? S extends Validator
27
- ? {
28
- encoding: E
29
- body: Infer<S>
30
- }
31
- : {
32
- encoding: E
33
- body: LexBody<E>
34
- }
35
- : void
36
-
37
- export type PayloadBody<E extends string | undefined> = E extends undefined
25
+ export type InferPayloadBody<
26
+ P extends Payload,
27
+ B,
28
+ > = P['encoding'] extends undefined
29
+ ? undefined // No encoding, no payload
30
+ : P['schema'] extends Schema
31
+ ? Infer<P['schema']>
32
+ : P['encoding'] extends `application/json`
33
+ ? LexValue
34
+ : B
35
+
36
+ export type PayloadSchema<E extends string | undefined> = E extends undefined
38
37
  ? undefined
39
- : Validator | undefined
38
+ : Schema | undefined
40
39
 
41
40
  export class Payload<
42
41
  const Encoding extends string | undefined = string | undefined,
43
- const Body extends PayloadBody<Encoding> = PayloadBody<Encoding>,
42
+ const Schema extends PayloadSchema<Encoding> = PayloadSchema<Encoding>,
44
43
  > {
45
44
  constructor(
46
45
  readonly encoding: Encoding,
47
- readonly schema: Body,
46
+ readonly schema: Schema,
48
47
  ) {
49
48
  if (encoding === undefined && schema !== undefined) {
50
49
  throw new TypeError('schema cannot be defined when encoding is undefined')
51
50
  }
52
51
  }
52
+
53
+ /**
54
+ * Checks whether the given content-type matches the expected payload schema's
55
+ * encoding.
56
+ */
57
+ matchesEncoding(contentType: string | undefined): boolean {
58
+ const mime = contentType?.split(';', 1)[0].trim()
59
+
60
+ const { encoding } = this
61
+
62
+ // Handle undefined cases
63
+ if (encoding === undefined) {
64
+ // Expecting no body
65
+ return mime === undefined
66
+ } else if (mime === undefined) {
67
+ // Expecting a body, but got no content-type
68
+ return false
69
+ }
70
+
71
+ if (encoding === '*/*') {
72
+ return true
73
+ }
74
+
75
+ if (encoding.endsWith('/*')) {
76
+ return mime.startsWith(encoding.slice(0, -1))
77
+ }
78
+
79
+ // Invalid: Lexicon can only specify "*/*" or "type/*" wildcards
80
+ if (encoding.includes('*')) {
81
+ return false
82
+ }
83
+
84
+ return encoding === mime
85
+ }
53
86
  }
@@ -1,11 +1,11 @@
1
- import { asNsid } from '../core.js'
1
+ import { asNsidString } from '../core.js'
2
2
  import { PermissionSet } from './permission-set.js'
3
3
  import { Permission } from './permission.js'
4
4
 
5
5
  describe('PermissionSet', () => {
6
6
  describe('constructor', () => {
7
7
  it('creates a PermissionSet instance with all parameters', () => {
8
- const nsid = asNsid('app.bsky.oauth.permissions')
8
+ const nsid = asNsidString('app.bsky.oauth.permissions')
9
9
  const permissions = [
10
10
  new Permission('app.bsky.feed.post:read', {}),
11
11
  new Permission('app.bsky.feed.post:write', {}),
@@ -24,7 +24,7 @@ describe('PermissionSet', () => {
24
24
  })
25
25
 
26
26
  it('creates a PermissionSet instance with minimal options', () => {
27
- const nsid = asNsid('app.bsky.oauth.permissions')
27
+ const nsid = asNsidString('app.bsky.oauth.permissions')
28
28
  const permissions = [
29
29
  new Permission('app.bsky.feed.post:read', {}),
30
30
  ] as const
@@ -39,7 +39,7 @@ describe('PermissionSet', () => {
39
39
  })
40
40
 
41
41
  it('creates a PermissionSet instance with empty permissions array', () => {
42
- const nsid = asNsid('app.bsky.oauth.permissions')
42
+ const nsid = asNsidString('app.bsky.oauth.permissions')
43
43
  const permissions = [] as const
44
44
  const options = {}
45
45
 
@@ -50,7 +50,7 @@ describe('PermissionSet', () => {
50
50
  })
51
51
 
52
52
  it('creates a PermissionSet instance with title only', () => {
53
- const nsid = asNsid('app.bsky.oauth.permissions')
53
+ const nsid = asNsidString('app.bsky.oauth.permissions')
54
54
  const permissions = [
55
55
  new Permission('app.bsky.feed.like:read', {}),
56
56
  ] as const
@@ -65,7 +65,7 @@ describe('PermissionSet', () => {
65
65
  })
66
66
 
67
67
  it('creates a PermissionSet instance with detail only', () => {
68
- const nsid = asNsid('app.bsky.oauth.permissions')
68
+ const nsid = asNsidString('app.bsky.oauth.permissions')
69
69
  const permissions = [
70
70
  new Permission('app.bsky.feed.like:read', {}),
71
71
  ] as const
@@ -80,7 +80,7 @@ describe('PermissionSet', () => {
80
80
  })
81
81
 
82
82
  it('creates a PermissionSet instance with localized titles', () => {
83
- const nsid = asNsid('app.bsky.oauth.permissions')
83
+ const nsid = asNsidString('app.bsky.oauth.permissions')
84
84
  const permissions = [
85
85
  new Permission('app.bsky.feed.post:read', {}),
86
86
  ] as const
@@ -102,7 +102,7 @@ describe('PermissionSet', () => {
102
102
  })
103
103
 
104
104
  it('creates a PermissionSet instance with localized details', () => {
105
- const nsid = asNsid('app.bsky.oauth.permissions')
105
+ const nsid = asNsidString('app.bsky.oauth.permissions')
106
106
  const permissions = [
107
107
  new Permission('app.bsky.feed.post:read', {}),
108
108
  ] as const
@@ -124,7 +124,7 @@ describe('PermissionSet', () => {
124
124
  })
125
125
 
126
126
  it('creates a PermissionSet instance with all options including localization', () => {
127
- const nsid = asNsid('app.bsky.oauth.permissions')
127
+ const nsid = asNsidString('app.bsky.oauth.permissions')
128
128
  const permissions = [
129
129
  new Permission('app.bsky.feed.post:read', {}),
130
130
  new Permission('app.bsky.feed.post:write', {}),
@@ -165,7 +165,7 @@ describe('PermissionSet', () => {
165
165
 
166
166
  describe('property immutability', () => {
167
167
  it('options object itself is mutable', () => {
168
- const nsid = asNsid('app.bsky.oauth.permissions')
168
+ const nsid = asNsidString('app.bsky.oauth.permissions')
169
169
  const permissions = [
170
170
  new Permission('app.bsky.feed.post:read', {}),
171
171
  ] as const
@@ -181,7 +181,7 @@ describe('PermissionSet', () => {
181
181
 
182
182
  describe('with multiple permissions', () => {
183
183
  it('creates a PermissionSet with multiple read permissions', () => {
184
- const nsid = asNsid('app.bsky.oauth.read')
184
+ const nsid = asNsidString('app.bsky.oauth.read')
185
185
  const permissions = [
186
186
  new Permission('app.bsky.feed.post:read', {}),
187
187
  new Permission('app.bsky.feed.like:read', {}),
@@ -211,7 +211,7 @@ describe('PermissionSet', () => {
211
211
  })
212
212
 
213
213
  it('creates a PermissionSet with mixed read/write permissions', () => {
214
- const nsid = asNsid('app.bsky.oauth.full')
214
+ const nsid = asNsidString('app.bsky.oauth.full')
215
215
  const permissions = [
216
216
  new Permission('app.bsky.feed.post:read', {}),
217
217
  new Permission('app.bsky.feed.post:write', {}),
@@ -229,7 +229,7 @@ describe('PermissionSet', () => {
229
229
  })
230
230
 
231
231
  it('creates a PermissionSet with a single permission', () => {
232
- const nsid = asNsid('app.bsky.oauth.limited')
232
+ const nsid = asNsidString('app.bsky.oauth.limited')
233
233
  const permissions = [
234
234
  new Permission('app.bsky.actor.profile:read', {}),
235
235
  ] as const
@@ -249,7 +249,7 @@ describe('PermissionSet', () => {
249
249
 
250
250
  describe('edge cases', () => {
251
251
  it('handles very long NSID', () => {
252
- const nsid = asNsid(
252
+ const nsid = asNsidString(
253
253
  'com.example.very.long.namespace.identifier.oauth.permissions',
254
254
  )
255
255
  const permissions = [new Permission('resource:action', {})] as const
@@ -261,7 +261,7 @@ describe('PermissionSet', () => {
261
261
  })
262
262
 
263
263
  it('handles long title strings', () => {
264
- const nsid = asNsid('app.bsky.oauth.permissions')
264
+ const nsid = asNsidString('app.bsky.oauth.permissions')
265
265
  const permissions = [
266
266
  new Permission('app.bsky.feed.post:read', {}),
267
267
  ] as const
@@ -277,7 +277,7 @@ describe('PermissionSet', () => {
277
277
  })
278
278
 
279
279
  it('handles long detail strings', () => {
280
- const nsid = asNsid('app.bsky.oauth.permissions')
280
+ const nsid = asNsidString('app.bsky.oauth.permissions')
281
281
  const permissions = [
282
282
  new Permission('app.bsky.feed.post:read', {}),
283
283
  ] as const
@@ -293,7 +293,7 @@ describe('PermissionSet', () => {
293
293
  })
294
294
 
295
295
  it('handles multiple language codes in title:lang', () => {
296
- const nsid = asNsid('app.bsky.oauth.permissions')
296
+ const nsid = asNsidString('app.bsky.oauth.permissions')
297
297
  const permissions = [
298
298
  new Permission('app.bsky.feed.post:read', {}),
299
299
  ] as const
@@ -319,7 +319,7 @@ describe('PermissionSet', () => {
319
319
  })
320
320
 
321
321
  it('handles undefined values in title:lang', () => {
322
- const nsid = asNsid('app.bsky.oauth.permissions')
322
+ const nsid = asNsidString('app.bsky.oauth.permissions')
323
323
  const permissions = [
324
324
  new Permission('app.bsky.feed.post:read', {}),
325
325
  ] as const
@@ -342,7 +342,7 @@ describe('PermissionSet', () => {
342
342
  })
343
343
 
344
344
  it('handles undefined values in detail:lang', () => {
345
- const nsid = asNsid('app.bsky.oauth.permissions')
345
+ const nsid = asNsidString('app.bsky.oauth.permissions')
346
346
  const permissions = [
347
347
  new Permission('app.bsky.feed.post:read', {}),
348
348
  ] as const
@@ -363,7 +363,7 @@ describe('PermissionSet', () => {
363
363
  })
364
364
 
365
365
  it('handles special characters in title', () => {
366
- const nsid = asNsid('app.bsky.oauth.permissions')
366
+ const nsid = asNsidString('app.bsky.oauth.permissions')
367
367
  const permissions = [
368
368
  new Permission('app.bsky.feed.post:read', {}),
369
369
  ] as const
@@ -379,7 +379,7 @@ describe('PermissionSet', () => {
379
379
  })
380
380
 
381
381
  it('handles special characters in detail', () => {
382
- const nsid = asNsid('app.bsky.oauth.permissions')
382
+ const nsid = asNsidString('app.bsky.oauth.permissions')
383
383
  const permissions = [
384
384
  new Permission('app.bsky.feed.post:read', {}),
385
385
  ] as const
@@ -396,7 +396,7 @@ describe('PermissionSet', () => {
396
396
  })
397
397
 
398
398
  it('handles unicode characters in title', () => {
399
- const nsid = asNsid('app.bsky.oauth.permissions')
399
+ const nsid = asNsidString('app.bsky.oauth.permissions')
400
400
  const permissions = [
401
401
  new Permission('app.bsky.feed.post:read', {}),
402
402
  ] as const
@@ -410,7 +410,7 @@ describe('PermissionSet', () => {
410
410
  })
411
411
 
412
412
  it('handles empty strings in title', () => {
413
- const nsid = asNsid('app.bsky.oauth.permissions')
413
+ const nsid = asNsidString('app.bsky.oauth.permissions')
414
414
  const permissions = [
415
415
  new Permission('app.bsky.feed.post:read', {}),
416
416
  ] as const
@@ -424,7 +424,7 @@ describe('PermissionSet', () => {
424
424
  })
425
425
 
426
426
  it('handles empty strings in detail', () => {
427
- const nsid = asNsid('app.bsky.oauth.permissions')
427
+ const nsid = asNsidString('app.bsky.oauth.permissions')
428
428
  const permissions = [
429
429
  new Permission('app.bsky.feed.post:read', {}),
430
430
  ] as const
@@ -438,7 +438,7 @@ describe('PermissionSet', () => {
438
438
  })
439
439
 
440
440
  it('handles large number of permissions', () => {
441
- const nsid = asNsid('app.bsky.oauth.permissions')
441
+ const nsid = asNsidString('app.bsky.oauth.permissions')
442
442
  const permissions = Array.from(
443
443
  { length: 100 },
444
444
  (_, i) => new Permission(`resource${i}:action`, {}),
@@ -453,7 +453,7 @@ describe('PermissionSet', () => {
453
453
 
454
454
  describe('real-world permission set examples', () => {
455
455
  it('creates a feed management permission set', () => {
456
- const nsid = asNsid('app.bsky.oauth.feed')
456
+ const nsid = asNsidString('app.bsky.oauth.feed')
457
457
  const permissions = [
458
458
  new Permission('app.bsky.feed.post:read', {}),
459
459
  new Permission('app.bsky.feed.post:write', {}),
@@ -483,7 +483,7 @@ describe('PermissionSet', () => {
483
483
  })
484
484
 
485
485
  it('creates a read-only permission set', () => {
486
- const nsid = asNsid('app.bsky.oauth.readonly')
486
+ const nsid = asNsidString('app.bsky.oauth.readonly')
487
487
  const permissions = [
488
488
  new Permission('app.bsky.feed.post:read', {}),
489
489
  new Permission('app.bsky.feed.like:read', {}),
@@ -504,7 +504,7 @@ describe('PermissionSet', () => {
504
504
  })
505
505
 
506
506
  it('creates a profile management permission set', () => {
507
- const nsid = asNsid('app.bsky.oauth.profile')
507
+ const nsid = asNsidString('app.bsky.oauth.profile')
508
508
  const permissions = [
509
509
  new Permission('app.bsky.actor.profile:read', {}),
510
510
  new Permission('app.bsky.actor.profile:write', {}),
@@ -531,7 +531,7 @@ describe('PermissionSet', () => {
531
531
  })
532
532
 
533
533
  it('creates a minimal permission set', () => {
534
- const nsid = asNsid('app.bsky.oauth.minimal')
534
+ const nsid = asNsidString('app.bsky.oauth.minimal')
535
535
  const permissions = [
536
536
  new Permission('app.bsky.actor.profile:read', {}),
537
537
  ] as const
@@ -549,7 +549,7 @@ describe('PermissionSet', () => {
549
549
 
550
550
  describe('permission validation', () => {
551
551
  it('validates that permissions are Permission instances', () => {
552
- const nsid = asNsid('app.bsky.oauth.permissions')
552
+ const nsid = asNsidString('app.bsky.oauth.permissions')
553
553
  const permission1 = new Permission('app.bsky.feed.post:read', {})
554
554
  const permission2 = new Permission('app.bsky.feed.post:write', {})
555
555
  const permissions = [permission1, permission2] as const
@@ -562,7 +562,7 @@ describe('PermissionSet', () => {
562
562
  })
563
563
 
564
564
  it('preserves permission resource strings', () => {
565
- const nsid = asNsid('app.bsky.oauth.permissions')
565
+ const nsid = asNsidString('app.bsky.oauth.permissions')
566
566
  const permissions = [
567
567
  new Permission('app.bsky.feed.post:read', {}),
568
568
  new Permission('app.bsky.feed.like:write', {}),
@@ -584,7 +584,7 @@ describe('PermissionSet', () => {
584
584
  })
585
585
 
586
586
  it('preserves permission options', () => {
587
- const nsid = asNsid('app.bsky.oauth.permissions')
587
+ const nsid = asNsidString('app.bsky.oauth.permissions')
588
588
  const permissionOptions = { custom: 'value' }
589
589
  const permissions = [
590
590
  new Permission('app.bsky.feed.post:read', permissionOptions),
@@ -599,7 +599,7 @@ describe('PermissionSet', () => {
599
599
 
600
600
  describe('option variations', () => {
601
601
  it('accepts title without detail', () => {
602
- const nsid = asNsid('app.bsky.oauth.permissions')
602
+ const nsid = asNsidString('app.bsky.oauth.permissions')
603
603
  const permissions = [
604
604
  new Permission('app.bsky.feed.post:read', {}),
605
605
  ] as const
@@ -616,7 +616,7 @@ describe('PermissionSet', () => {
616
616
  })
617
617
 
618
618
  it('accepts detail without title', () => {
619
- const nsid = asNsid('app.bsky.oauth.permissions')
619
+ const nsid = asNsidString('app.bsky.oauth.permissions')
620
620
  const permissions = [
621
621
  new Permission('app.bsky.feed.post:read', {}),
622
622
  ] as const
@@ -635,7 +635,7 @@ describe('PermissionSet', () => {
635
635
  })
636
636
 
637
637
  it('accepts title:lang without title', () => {
638
- const nsid = asNsid('app.bsky.oauth.permissions')
638
+ const nsid = asNsidString('app.bsky.oauth.permissions')
639
639
  const permissions = [
640
640
  new Permission('app.bsky.feed.post:read', {}),
641
641
  ] as const
@@ -656,7 +656,7 @@ describe('PermissionSet', () => {
656
656
  })
657
657
 
658
658
  it('accepts detail:lang without detail', () => {
659
- const nsid = asNsid('app.bsky.oauth.permissions')
659
+ const nsid = asNsidString('app.bsky.oauth.permissions')
660
660
  const permissions = [
661
661
  new Permission('app.bsky.feed.post:read', {}),
662
662
  ] as const
@@ -1,12 +1,7 @@
1
1
  import { ObjectSchema } from './object.js'
2
2
  import { ParamsSchema } from './params.js'
3
3
  import { Payload } from './payload.js'
4
- import {
5
- InferProcedureInputBody,
6
- InferProcedureOutputBody,
7
- InferProcedureParameters,
8
- Procedure,
9
- } from './procedure.js'
4
+ import { Procedure } from './procedure.js'
10
5
  import { StringSchema } from './string.js'
11
6
 
12
7
  describe('Procedure', () => {
@@ -288,62 +283,6 @@ describe('Procedure', () => {
288
283
  })
289
284
  })
290
285
 
291
- describe('type inference helpers', () => {
292
- it('infers procedure parameters type', () => {
293
- const parameters = new ParamsSchema({
294
- limit: new StringSchema({}),
295
- })
296
- const procedure = new Procedure(
297
- 'com.example.list',
298
- parameters,
299
- new Payload(undefined, undefined),
300
- new Payload(undefined, undefined),
301
- undefined,
302
- )
303
-
304
- type Params = InferProcedureParameters<typeof procedure>
305
- // Type test - this will fail at compile time if inference is wrong
306
- const params: Params = { limit: 'test' }
307
- expect(params).toBeDefined()
308
- })
309
-
310
- it('infers procedure input body type', () => {
311
- const inputSchema = new ObjectSchema({
312
- text: new StringSchema({}),
313
- })
314
- const procedure = new Procedure(
315
- 'com.example.create',
316
- new ParamsSchema({}),
317
- new Payload('application/json', inputSchema),
318
- new Payload(undefined, undefined),
319
- undefined,
320
- )
321
-
322
- type InputBody = InferProcedureInputBody<typeof procedure>
323
- // Type test - this will fail at compile time if inference is wrong
324
- const input: InputBody = { text: 'hello' }
325
- expect(input).toBeDefined()
326
- })
327
-
328
- it('infers procedure output body type', () => {
329
- const outputSchema = new ObjectSchema({
330
- uri: new StringSchema({}),
331
- })
332
- const procedure = new Procedure(
333
- 'com.example.get',
334
- new ParamsSchema({}),
335
- new Payload(undefined, undefined),
336
- new Payload('application/json', outputSchema),
337
- undefined,
338
- )
339
-
340
- type OutputBody = InferProcedureOutputBody<typeof procedure>
341
- // Type test - this will fail at compile time if inference is wrong
342
- const output: OutputBody = { uri: 'at://did:plc:abc/post/123' }
343
- expect(output).toBeDefined()
344
- })
345
- })
346
-
347
286
  describe('property access', () => {
348
287
  it('provides access to all properties', () => {
349
288
  const nsid = 'com.example.test'
@@ -1,28 +1,16 @@
1
1
  import { NsidString } from '../core.js'
2
- import { Infer } from '../validation.js'
3
2
  import { ParamsSchema } from './params.js'
4
- import { InferPayloadBody, Payload } from './payload.js'
5
-
6
- export type InferProcedureParameters<Q extends Procedure> =
7
- Q extends Procedure<any, infer P extends ParamsSchema, any> ? Infer<P> : never
8
-
9
- export type InferProcedureInputBody<Q extends Procedure> =
10
- Q extends Procedure<any, any, infer I extends Payload, any>
11
- ? InferPayloadBody<I>
12
- : never
13
-
14
- export type InferProcedureOutputBody<Q extends Procedure> =
15
- Q extends Procedure<any, any, any, infer O extends Payload>
16
- ? InferPayloadBody<O>
17
- : never
3
+ import { Payload } from './payload.js'
18
4
 
19
5
  export class Procedure<
20
- TNsid extends NsidString = any,
21
- TParameters extends ParamsSchema = any,
22
- TInputPayload extends Payload = any,
23
- TOutputPayload extends Payload = any,
24
- TErrors extends undefined | readonly string[] = any,
6
+ TNsid extends NsidString = NsidString,
7
+ TParameters extends ParamsSchema = ParamsSchema,
8
+ TInputPayload extends Payload = Payload,
9
+ TOutputPayload extends Payload = Payload,
10
+ TErrors extends undefined | readonly string[] = undefined | readonly string[],
25
11
  > {
12
+ readonly type = 'procedure' as const
13
+
26
14
  constructor(
27
15
  readonly nsid: TNsid,
28
16
  readonly parameters: TParameters,