@atproto/lex-schema 0.0.8 → 0.0.10

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 (279) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE.txt +1 -1
  3. package/dist/core/$type.d.ts +11 -0
  4. package/dist/core/$type.d.ts.map +1 -1
  5. package/dist/core/$type.js +4 -0
  6. package/dist/core/$type.js.map +1 -1
  7. package/dist/core/schema.d.ts +31 -24
  8. package/dist/core/schema.d.ts.map +1 -1
  9. package/dist/core/schema.js +38 -8
  10. package/dist/core/schema.js.map +1 -1
  11. package/dist/core/string-format.d.ts +35 -35
  12. package/dist/core/string-format.d.ts.map +1 -1
  13. package/dist/core/string-format.js +49 -91
  14. package/dist/core/string-format.js.map +1 -1
  15. package/dist/core/validation-issue.js +1 -1
  16. package/dist/core/validation-issue.js.map +1 -1
  17. package/dist/core/validator.d.ts +53 -32
  18. package/dist/core/validator.d.ts.map +1 -1
  19. package/dist/core/validator.js +18 -22
  20. package/dist/core/validator.js.map +1 -1
  21. package/dist/external.d.ts +0 -85
  22. package/dist/external.d.ts.map +1 -1
  23. package/dist/external.js +0 -164
  24. package/dist/external.js.map +1 -1
  25. package/dist/helpers.d.ts +10 -5
  26. package/dist/helpers.d.ts.map +1 -1
  27. package/dist/helpers.js +3 -3
  28. package/dist/helpers.js.map +1 -1
  29. package/dist/schema/array.d.ts +9 -5
  30. package/dist/schema/array.d.ts.map +1 -1
  31. package/dist/schema/array.js +14 -5
  32. package/dist/schema/array.js.map +1 -1
  33. package/dist/schema/blob.d.ts +9 -7
  34. package/dist/schema/blob.d.ts.map +1 -1
  35. package/dist/schema/blob.js +9 -5
  36. package/dist/schema/blob.js.map +1 -1
  37. package/dist/schema/boolean.d.ts +3 -7
  38. package/dist/schema/boolean.d.ts.map +1 -1
  39. package/dist/schema/boolean.js +6 -7
  40. package/dist/schema/boolean.js.map +1 -1
  41. package/dist/schema/bytes.d.ts +3 -2
  42. package/dist/schema/bytes.d.ts.map +1 -1
  43. package/dist/schema/bytes.js +7 -3
  44. package/dist/schema/bytes.js.map +1 -1
  45. package/dist/schema/cid.d.ts +10 -8
  46. package/dist/schema/cid.d.ts.map +1 -1
  47. package/dist/schema/cid.js +5 -1
  48. package/dist/schema/cid.js.map +1 -1
  49. package/dist/schema/custom.d.ts +6 -5
  50. package/dist/schema/custom.d.ts.map +1 -1
  51. package/dist/schema/custom.js +10 -4
  52. package/dist/schema/custom.js.map +1 -1
  53. package/dist/schema/dict.d.ts +8 -8
  54. package/dist/schema/dict.d.ts.map +1 -1
  55. package/dist/schema/dict.js +11 -2
  56. package/dist/schema/dict.js.map +1 -1
  57. package/dist/schema/discriminated-union.d.ts +21 -14
  58. package/dist/schema/discriminated-union.d.ts.map +1 -1
  59. package/dist/schema/discriminated-union.js +7 -0
  60. package/dist/schema/discriminated-union.js.map +1 -1
  61. package/dist/schema/enum.d.ts +7 -9
  62. package/dist/schema/enum.d.ts.map +1 -1
  63. package/dist/schema/enum.js +8 -4
  64. package/dist/schema/enum.js.map +1 -1
  65. package/dist/schema/integer.d.ts +5 -5
  66. package/dist/schema/integer.d.ts.map +1 -1
  67. package/dist/schema/integer.js +9 -5
  68. package/dist/schema/integer.js.map +1 -1
  69. package/dist/schema/intersection.d.ts +4 -4
  70. package/dist/schema/intersection.d.ts.map +1 -1
  71. package/dist/schema/intersection.js +5 -0
  72. package/dist/schema/intersection.js.map +1 -1
  73. package/dist/schema/literal.d.ts +6 -9
  74. package/dist/schema/literal.d.ts.map +1 -1
  75. package/dist/schema/literal.js +7 -4
  76. package/dist/schema/literal.js.map +1 -1
  77. package/dist/schema/never.d.ts +3 -2
  78. package/dist/schema/never.d.ts.map +1 -1
  79. package/dist/schema/never.js +5 -1
  80. package/dist/schema/never.js.map +1 -1
  81. package/dist/schema/null.d.ts +4 -3
  82. package/dist/schema/null.d.ts.map +1 -1
  83. package/dist/schema/null.js +6 -4
  84. package/dist/schema/null.js.map +1 -1
  85. package/dist/schema/nullable.d.ts +6 -5
  86. package/dist/schema/nullable.d.ts.map +1 -1
  87. package/dist/schema/nullable.js +9 -5
  88. package/dist/schema/nullable.js.map +1 -1
  89. package/dist/schema/object.d.ts +10 -8
  90. package/dist/schema/object.d.ts.map +1 -1
  91. package/dist/schema/object.js +11 -3
  92. package/dist/schema/object.js.map +1 -1
  93. package/dist/schema/optional.d.ts +7 -5
  94. package/dist/schema/optional.d.ts.map +1 -1
  95. package/dist/schema/optional.js +14 -6
  96. package/dist/schema/optional.js.map +1 -1
  97. package/dist/schema/params.d.ts +24 -13
  98. package/dist/schema/params.d.ts.map +1 -1
  99. package/dist/schema/params.js +47 -25
  100. package/dist/schema/params.js.map +1 -1
  101. package/dist/schema/payload.d.ts +12 -9
  102. package/dist/schema/payload.d.ts.map +1 -1
  103. package/dist/schema/payload.js +11 -0
  104. package/dist/schema/payload.js.map +1 -1
  105. package/dist/schema/permission-set.d.ts +1 -0
  106. package/dist/schema/permission-set.d.ts.map +1 -1
  107. package/dist/schema/permission-set.js +5 -0
  108. package/dist/schema/permission-set.js.map +1 -1
  109. package/dist/schema/permission.d.ts +6 -5
  110. package/dist/schema/permission.d.ts.map +1 -1
  111. package/dist/schema/permission.js +5 -0
  112. package/dist/schema/permission.js.map +1 -1
  113. package/dist/schema/procedure.d.ts +2 -1
  114. package/dist/schema/procedure.d.ts.map +1 -1
  115. package/dist/schema/procedure.js +5 -0
  116. package/dist/schema/procedure.js.map +1 -1
  117. package/dist/schema/query.d.ts +2 -1
  118. package/dist/schema/query.d.ts.map +1 -1
  119. package/dist/schema/query.js +5 -0
  120. package/dist/schema/query.js.map +1 -1
  121. package/dist/schema/record.d.ts +48 -30
  122. package/dist/schema/record.d.ts.map +1 -1
  123. package/dist/schema/record.js +12 -9
  124. package/dist/schema/record.js.map +1 -1
  125. package/dist/schema/ref.d.ts +9 -6
  126. package/dist/schema/ref.d.ts.map +1 -1
  127. package/dist/schema/ref.js +9 -16
  128. package/dist/schema/ref.js.map +1 -1
  129. package/dist/schema/refine.d.ts +4 -4
  130. package/dist/schema/refine.d.ts.map +1 -1
  131. package/dist/schema/refine.js.map +1 -1
  132. package/dist/schema/regexp.d.ts +4 -3
  133. package/dist/schema/regexp.d.ts.map +1 -1
  134. package/dist/schema/regexp.js +5 -0
  135. package/dist/schema/regexp.js.map +1 -1
  136. package/dist/schema/string.d.ts +7 -8
  137. package/dist/schema/string.d.ts.map +1 -1
  138. package/dist/schema/string.js +13 -19
  139. package/dist/schema/string.js.map +1 -1
  140. package/dist/schema/subscription.d.ts +2 -1
  141. package/dist/schema/subscription.d.ts.map +1 -1
  142. package/dist/schema/subscription.js +5 -0
  143. package/dist/schema/subscription.js.map +1 -1
  144. package/dist/schema/token.d.ts +6 -5
  145. package/dist/schema/token.d.ts.map +1 -1
  146. package/dist/schema/token.js +5 -0
  147. package/dist/schema/token.js.map +1 -1
  148. package/dist/schema/typed-object.d.ts +43 -26
  149. package/dist/schema/typed-object.d.ts.map +1 -1
  150. package/dist/schema/typed-object.js +6 -3
  151. package/dist/schema/typed-object.js.map +1 -1
  152. package/dist/schema/typed-ref.d.ts +16 -25
  153. package/dist/schema/typed-ref.d.ts.map +1 -1
  154. package/dist/schema/typed-ref.js +7 -17
  155. package/dist/schema/typed-ref.js.map +1 -1
  156. package/dist/schema/typed-union.d.ts +9 -21
  157. package/dist/schema/typed-union.d.ts.map +1 -1
  158. package/dist/schema/typed-union.js +15 -11
  159. package/dist/schema/typed-union.js.map +1 -1
  160. package/dist/schema/union.d.ts +6 -6
  161. package/dist/schema/union.d.ts.map +1 -1
  162. package/dist/schema/union.js +7 -5
  163. package/dist/schema/union.js.map +1 -1
  164. package/dist/schema/unknown-object.d.ts +5 -4
  165. package/dist/schema/unknown-object.d.ts.map +1 -1
  166. package/dist/schema/unknown-object.js +5 -1
  167. package/dist/schema/unknown-object.js.map +1 -1
  168. package/dist/schema/unknown.d.ts +3 -2
  169. package/dist/schema/unknown.d.ts.map +1 -1
  170. package/dist/schema/unknown.js +5 -1
  171. package/dist/schema/unknown.js.map +1 -1
  172. package/dist/schema/with-default.d.ts +9 -0
  173. package/dist/schema/with-default.d.ts.map +1 -0
  174. package/dist/schema/with-default.js +27 -0
  175. package/dist/schema/with-default.js.map +1 -0
  176. package/dist/schema.d.ts +2 -2
  177. package/dist/schema.d.ts.map +1 -1
  178. package/dist/schema.js +2 -4
  179. package/dist/schema.js.map +1 -1
  180. package/dist/util/assertion-util.d.ts +0 -6
  181. package/dist/util/assertion-util.d.ts.map +1 -1
  182. package/dist/util/assertion-util.js +0 -28
  183. package/dist/util/assertion-util.js.map +1 -1
  184. package/dist/util/memoize.d.ts +2 -2
  185. package/dist/util/memoize.d.ts.map +1 -1
  186. package/dist/util/memoize.js +23 -39
  187. package/dist/util/memoize.js.map +1 -1
  188. package/package.json +3 -3
  189. package/src/core/$type.test.ts +20 -0
  190. package/src/core/$type.ts +30 -0
  191. package/src/core/schema.ts +86 -38
  192. package/src/core/string-format.ts +119 -158
  193. package/src/core/validation-issue.ts +1 -1
  194. package/src/core/validator.ts +93 -53
  195. package/src/external.ts +0 -404
  196. package/src/helpers.test.ts +22 -21
  197. package/src/helpers.ts +14 -14
  198. package/src/schema/array.test.ts +38 -40
  199. package/src/schema/array.ts +35 -13
  200. package/src/schema/blob.test.ts +21 -21
  201. package/src/schema/blob.ts +19 -17
  202. package/src/schema/boolean.test.ts +9 -8
  203. package/src/schema/boolean.ts +7 -13
  204. package/src/schema/bytes.test.ts +13 -13
  205. package/src/schema/bytes.ts +13 -8
  206. package/src/schema/cid.test.ts +3 -3
  207. package/src/schema/cid.ts +15 -13
  208. package/src/schema/custom.test.ts +26 -26
  209. package/src/schema/custom.ts +20 -13
  210. package/src/schema/dict.test.ts +21 -39
  211. package/src/schema/dict.ts +28 -19
  212. package/src/schema/discriminated-union.test.ts +128 -128
  213. package/src/schema/discriminated-union.ts +45 -26
  214. package/src/schema/enum.test.ts +17 -16
  215. package/src/schema/enum.ts +16 -16
  216. package/src/schema/integer.test.ts +22 -21
  217. package/src/schema/integer.ts +12 -9
  218. package/src/schema/intersection.test.ts +10 -10
  219. package/src/schema/intersection.ts +17 -14
  220. package/src/schema/literal.test.ts +35 -34
  221. package/src/schema/literal.ts +12 -15
  222. package/src/schema/never.test.ts +5 -5
  223. package/src/schema/never.ts +7 -2
  224. package/src/schema/null.test.ts +3 -3
  225. package/src/schema/null.ts +9 -9
  226. package/src/schema/nullable.test.ts +31 -42
  227. package/src/schema/nullable.ts +17 -9
  228. package/src/schema/object.test.ts +10 -12
  229. package/src/schema/object.ts +27 -18
  230. package/src/schema/optional.test.ts +21 -28
  231. package/src/schema/optional.ts +27 -10
  232. package/src/schema/params.test.ts +471 -47
  233. package/src/schema/params.ts +72 -38
  234. package/src/schema/payload.test.ts +150 -156
  235. package/src/schema/payload.ts +35 -19
  236. package/src/schema/permission-set.test.ts +206 -273
  237. package/src/schema/permission-set.ts +8 -0
  238. package/src/schema/permission.test.ts +177 -177
  239. package/src/schema/permission.ts +13 -5
  240. package/src/schema/procedure.test.ts +183 -242
  241. package/src/schema/procedure.ts +18 -5
  242. package/src/schema/query.test.ts +186 -200
  243. package/src/schema/query.ts +16 -4
  244. package/src/schema/record.test.ts +121 -101
  245. package/src/schema/record.ts +74 -40
  246. package/src/schema/ref.test.ts +101 -118
  247. package/src/schema/ref.ts +33 -28
  248. package/src/schema/refine.test.ts +28 -28
  249. package/src/schema/refine.ts +23 -20
  250. package/src/schema/regexp.test.ts +29 -33
  251. package/src/schema/regexp.ts +11 -7
  252. package/src/schema/string.test.ts +35 -35
  253. package/src/schema/string.ts +24 -33
  254. package/src/schema/subscription.test.ts +259 -387
  255. package/src/schema/subscription.ts +16 -4
  256. package/src/schema/token.test.ts +47 -324
  257. package/src/schema/token.ts +14 -7
  258. package/src/schema/typed-object.test.ts +98 -81
  259. package/src/schema/typed-object.ts +68 -33
  260. package/src/schema/typed-ref.test.ts +206 -234
  261. package/src/schema/typed-ref.ts +40 -42
  262. package/src/schema/typed-union.test.ts +40 -64
  263. package/src/schema/typed-union.ts +36 -58
  264. package/src/schema/union.test.ts +17 -27
  265. package/src/schema/union.ts +20 -16
  266. package/src/schema/unknown-object.test.ts +8 -8
  267. package/src/schema/unknown-object.ts +9 -7
  268. package/src/schema/unknown.test.ts +4 -4
  269. package/src/schema/unknown.ts +7 -5
  270. package/src/schema/with-default.ts +35 -0
  271. package/src/schema.ts +2 -6
  272. package/src/util/assertion-util.ts +0 -39
  273. package/src/util/memoize.ts +26 -46
  274. package/dist/schema/_parameters.d.ts +0 -17
  275. package/dist/schema/_parameters.d.ts.map +0 -1
  276. package/dist/schema/_parameters.js +0 -20
  277. package/dist/schema/_parameters.js.map +0 -1
  278. package/src/schema/_parameters.test.ts +0 -417
  279. package/src/schema/_parameters.ts +0 -26
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
  import { parseCid } from '@atproto/lex-data'
3
- import { BlobSchema } from './blob.js'
3
+ import { blob } from './blob.js'
4
4
 
5
5
  // await cidForRawBytes(Buffer.from('Hello, World!'))
6
6
  const blobCid = parseCid(
@@ -13,7 +13,7 @@ const lexCid = parseCid(
13
13
 
14
14
  describe('BlobSchema', () => {
15
15
  describe('basic validation', () => {
16
- const schema = new BlobSchema({})
16
+ const schema = blob({})
17
17
 
18
18
  it('validates valid blob references', () => {
19
19
  const result = schema.safeParse({
@@ -82,7 +82,7 @@ describe('BlobSchema', () => {
82
82
  })
83
83
 
84
84
  describe('BlobRef validation', () => {
85
- const schema = new BlobSchema({})
85
+ const schema = blob({})
86
86
 
87
87
  it('rejects blob without $type', () => {
88
88
  const result = schema.safeParse({
@@ -214,7 +214,7 @@ describe('BlobSchema', () => {
214
214
  })
215
215
 
216
216
  describe('strict validation', () => {
217
- const strictSchema = new BlobSchema({ strict: true })
217
+ const strictSchema = blob({ strict: true })
218
218
 
219
219
  it('accepts valid raw CID in strict mode', () => {
220
220
  const result = strictSchema.safeParse({
@@ -237,7 +237,7 @@ describe('BlobSchema', () => {
237
237
  })
238
238
 
239
239
  it('accepts non-raw CID in non-strict mode', () => {
240
- const nonStrictSchema = new BlobSchema({ strict: false })
240
+ const nonStrictSchema = blob({ strict: false })
241
241
  const result = nonStrictSchema.safeParse({
242
242
  $type: 'blob',
243
243
  ref: lexCid,
@@ -250,7 +250,7 @@ describe('BlobSchema', () => {
250
250
 
251
251
  describe('legacy blob format', () => {
252
252
  it('rejects legacy format by default', () => {
253
- const schema = new BlobSchema({})
253
+ const schema = blob({})
254
254
  const result = schema.safeParse({
255
255
  cid: blobCid.toString(),
256
256
  mimeType: 'image/jpeg',
@@ -259,7 +259,7 @@ describe('BlobSchema', () => {
259
259
  })
260
260
 
261
261
  it('accepts legacy format when allowLegacy is true', () => {
262
- const schema = new BlobSchema({ allowLegacy: true })
262
+ const schema = blob({ allowLegacy: true })
263
263
  const result = schema.safeParse({
264
264
  cid: blobCid.toString(),
265
265
  mimeType: 'image/jpeg',
@@ -274,7 +274,7 @@ describe('BlobSchema', () => {
274
274
  })
275
275
 
276
276
  it('accepts legacy format with lexCid when allowLegacy is true', () => {
277
- const schema = new BlobSchema({ allowLegacy: true })
277
+ const schema = blob({ allowLegacy: true })
278
278
  const result = schema.safeParse({
279
279
  cid: lexCid.toString(),
280
280
  mimeType: 'image/png',
@@ -283,7 +283,7 @@ describe('BlobSchema', () => {
283
283
  })
284
284
 
285
285
  it('rejects legacy format without cid', () => {
286
- const schema = new BlobSchema({ allowLegacy: true })
286
+ const schema = blob({ allowLegacy: true })
287
287
  const result = schema.safeParse({
288
288
  mimeType: 'image/jpeg',
289
289
  })
@@ -291,7 +291,7 @@ describe('BlobSchema', () => {
291
291
  })
292
292
 
293
293
  it('rejects legacy format without mimeType', () => {
294
- const schema = new BlobSchema({ allowLegacy: true })
294
+ const schema = blob({ allowLegacy: true })
295
295
  const result = schema.safeParse({
296
296
  cid: blobCid.toString(),
297
297
  })
@@ -299,7 +299,7 @@ describe('BlobSchema', () => {
299
299
  })
300
300
 
301
301
  it('rejects legacy format with invalid cid', () => {
302
- const schema = new BlobSchema({ allowLegacy: true })
302
+ const schema = blob({ allowLegacy: true })
303
303
  const result = schema.safeParse({
304
304
  cid: 'invalid-cid',
305
305
  mimeType: 'image/jpeg',
@@ -308,7 +308,7 @@ describe('BlobSchema', () => {
308
308
  })
309
309
 
310
310
  it('rejects legacy format with numeric cid', () => {
311
- const schema = new BlobSchema({ allowLegacy: true })
311
+ const schema = blob({ allowLegacy: true })
312
312
  const result = schema.safeParse({
313
313
  cid: 123,
314
314
  mimeType: 'image/jpeg',
@@ -317,7 +317,7 @@ describe('BlobSchema', () => {
317
317
  })
318
318
 
319
319
  it('rejects legacy format with extra properties', () => {
320
- const schema = new BlobSchema({ allowLegacy: true })
320
+ const schema = blob({ allowLegacy: true })
321
321
  const result = schema.safeParse({
322
322
  cid: blobCid.toString(),
323
323
  mimeType: 'image/jpeg',
@@ -327,7 +327,7 @@ describe('BlobSchema', () => {
327
327
  })
328
328
 
329
329
  it('accepts both BlobRef and LegacyBlobRef formats when allowLegacy is true', () => {
330
- const schema = new BlobSchema({ allowLegacy: true })
330
+ const schema = blob({ allowLegacy: true })
331
331
 
332
332
  const blobRefResult = schema.safeParse({
333
333
  $type: 'blob',
@@ -347,7 +347,7 @@ describe('BlobSchema', () => {
347
347
 
348
348
  describe('accept and maxSize options', () => {
349
349
  it('accepts blob with accept option (not enforced)', () => {
350
- const schema = new BlobSchema({ accept: ['image/jpeg', 'image/png'] })
350
+ const schema = blob({ accept: ['image/jpeg', 'image/png'] })
351
351
  const result = schema.safeParse({
352
352
  $type: 'blob',
353
353
  ref: blobCid,
@@ -358,7 +358,7 @@ describe('BlobSchema', () => {
358
358
  })
359
359
 
360
360
  it('accepts blob with maxSize option (not enforced)', () => {
361
- const schema = new BlobSchema({ maxSize: 1000 })
361
+ const schema = blob({ maxSize: 1000 })
362
362
  const result = schema.safeParse({
363
363
  $type: 'blob',
364
364
  ref: blobCid,
@@ -369,7 +369,7 @@ describe('BlobSchema', () => {
369
369
  })
370
370
 
371
371
  it('accepts blob matching accept constraint', () => {
372
- const schema = new BlobSchema({ accept: ['image/jpeg', 'image/png'] })
372
+ const schema = blob({ accept: ['image/jpeg', 'image/png'] })
373
373
  const result = schema.safeParse({
374
374
  $type: 'blob',
375
375
  ref: blobCid,
@@ -380,7 +380,7 @@ describe('BlobSchema', () => {
380
380
  })
381
381
 
382
382
  it('accepts blob matching maxSize constraint', () => {
383
- const schema = new BlobSchema({ maxSize: 20000 })
383
+ const schema = blob({ maxSize: 20000 })
384
384
  const result = schema.safeParse({
385
385
  $type: 'blob',
386
386
  ref: blobCid,
@@ -392,7 +392,7 @@ describe('BlobSchema', () => {
392
392
  })
393
393
 
394
394
  describe('edge cases', () => {
395
- const schema = new BlobSchema({})
395
+ const schema = blob({})
396
396
 
397
397
  it('validates blob with large size', () => {
398
398
  const result = schema.safeParse({
@@ -457,7 +457,7 @@ describe('BlobSchema', () => {
457
457
 
458
458
  describe('combined options', () => {
459
459
  it('validates with strict and allowLegacy both true', () => {
460
- const schema = new BlobSchema({ strict: true, allowLegacy: true })
460
+ const schema = blob({ strict: true, allowLegacy: true })
461
461
 
462
462
  // Should accept strict BlobRef
463
463
  const blobRefResult = schema.safeParse({
@@ -486,7 +486,7 @@ describe('BlobSchema', () => {
486
486
  })
487
487
 
488
488
  it('validates with all options combined', () => {
489
- const schema = new BlobSchema({
489
+ const schema = blob({
490
490
  strict: true,
491
491
  allowLegacy: true,
492
492
  accept: ['image/jpeg'],
@@ -5,7 +5,8 @@ import {
5
5
  isBlobRef,
6
6
  isLegacyBlobRef,
7
7
  } from '@atproto/lex-data'
8
- import { Schema, ValidationResult, ValidatorContext } from '../core.js'
8
+ import { Schema, ValidationContext } from '../core.js'
9
+ import { memoizedOptions } from '../util/memoize.js'
9
10
 
10
11
  export type BlobSchemaOptions = BlobRefCheckOptions & {
11
12
  /**
@@ -25,27 +26,22 @@ export type BlobSchemaOptions = BlobRefCheckOptions & {
25
26
 
26
27
  export type { BlobRef, LegacyBlobRef }
27
28
 
28
- export type BlobSchemaOutput<Options> = Options extends { allowLegacy: true }
29
- ? BlobRef | LegacyBlobRef
30
- : BlobRef
31
-
32
- export class BlobSchema<O extends BlobSchemaOptions> extends Schema<
33
- BlobSchemaOutput<O>
29
+ export class BlobSchema<
30
+ const TOptions extends BlobSchemaOptions = NonNullable<unknown>,
31
+ > extends Schema<
32
+ TOptions extends { allowLegacy: true } ? BlobRef | LegacyBlobRef : BlobRef
34
33
  > {
35
- constructor(readonly options: O) {
34
+ constructor(readonly options?: TOptions) {
36
35
  super()
37
36
  }
38
37
 
39
- validateInContext(
40
- input: unknown,
41
- ctx: ValidatorContext,
42
- ): ValidationResult<BlobSchemaOutput<O>> {
38
+ validateInContext(input: unknown, ctx: ValidationContext) {
43
39
  const blob: null | BlobRef | LegacyBlobRef =
44
40
  (input as any)?.$type !== undefined
45
41
  ? isBlobRef(input, this.options)
46
42
  ? input
47
43
  : null
48
- : this.options.allowLegacy === true && isLegacyBlobRef(input)
44
+ : this.options?.allowLegacy === true && isLegacyBlobRef(input)
49
45
  ? input
50
46
  : null
51
47
 
@@ -53,21 +49,21 @@ export class BlobSchema<O extends BlobSchemaOptions> extends Schema<
53
49
  return ctx.issueInvalidType(input, 'blob')
54
50
  }
55
51
 
56
- const { accept } = this.options
52
+ const accept = this.options?.accept
57
53
  if (accept && !matchesMime(blob.mimeType, accept)) {
58
54
  return ctx.issueInvalidPropertyValue(blob, 'mimeType', accept)
59
55
  }
60
56
 
61
- const { maxSize } = this.options
57
+ const maxSize = this.options?.maxSize
62
58
  if (maxSize != null && 'size' in blob && blob.size > maxSize) {
63
59
  return ctx.issueTooBig(blob, 'blob', maxSize, blob.size)
64
60
  }
65
61
 
66
- return ctx.success(blob as BlobSchemaOutput<O>)
62
+ return ctx.success(blob)
67
63
  }
68
64
 
69
65
  matchesMime(mime: string): boolean {
70
- const { accept } = this.options
66
+ const accept = this.options?.accept
71
67
  if (!accept) return true
72
68
  return matchesMime(mime, accept)
73
69
  }
@@ -83,3 +79,9 @@ function matchesMime(mime: string, accepted: string[]): boolean {
83
79
  }
84
80
  return false
85
81
  }
82
+
83
+ export const blob = /*#__PURE__*/ memoizedOptions(function <
84
+ O extends BlobSchemaOptions = { allowLegacy?: false },
85
+ >(options?: O) {
86
+ return new BlobSchema(options)
87
+ })
@@ -1,9 +1,10 @@
1
1
  import { describe, expect, it } from 'vitest'
2
- import { BooleanSchema } from './boolean.js'
2
+ import { boolean } from './boolean.js'
3
+ import { withDefault } from './with-default.js'
3
4
 
4
5
  describe('BooleanSchema', () => {
5
6
  describe('basic validation', () => {
6
- const schema = new BooleanSchema()
7
+ const schema = boolean()
7
8
 
8
9
  it('validates true', () => {
9
10
  const result = schema.safeParse(true)
@@ -54,7 +55,7 @@ describe('BooleanSchema', () => {
54
55
 
55
56
  describe('with default value', () => {
56
57
  it('uses default value of true when input is undefined', () => {
57
- const schema = new BooleanSchema({ default: true })
58
+ const schema = withDefault(boolean(), true)
58
59
  const result = schema.safeParse(undefined)
59
60
  expect(result.success).toBe(true)
60
61
  if (result.success) {
@@ -63,7 +64,7 @@ describe('BooleanSchema', () => {
63
64
  })
64
65
 
65
66
  it('uses default value of false when input is undefined', () => {
66
- const schema = new BooleanSchema({ default: false })
67
+ const schema = withDefault(boolean(), false)
67
68
  const result = schema.safeParse(undefined)
68
69
  expect(result.success).toBe(true)
69
70
  if (result.success) {
@@ -72,7 +73,7 @@ describe('BooleanSchema', () => {
72
73
  })
73
74
 
74
75
  it('overrides default value with explicit true', () => {
75
- const schema = new BooleanSchema({ default: false })
76
+ const schema = withDefault(boolean(), false)
76
77
  const result = schema.safeParse(true)
77
78
  expect(result.success).toBe(true)
78
79
  if (result.success) {
@@ -81,7 +82,7 @@ describe('BooleanSchema', () => {
81
82
  })
82
83
 
83
84
  it('overrides default value with explicit false', () => {
84
- const schema = new BooleanSchema({ default: true })
85
+ const schema = withDefault(boolean(), true)
85
86
  const result = schema.safeParse(false)
86
87
  expect(result.success).toBe(true)
87
88
  if (result.success) {
@@ -90,14 +91,14 @@ describe('BooleanSchema', () => {
90
91
  })
91
92
 
92
93
  it('rejects invalid types even with default', () => {
93
- const schema = new BooleanSchema({ default: true })
94
+ const schema = withDefault(boolean(), true)
94
95
  const result = schema.safeParse('not a boolean')
95
96
  expect(result.success).toBe(false)
96
97
  })
97
98
  })
98
99
 
99
100
  describe('edge cases', () => {
100
- const schema = new BooleanSchema()
101
+ const schema = boolean()
101
102
 
102
103
  it('rejects Boolean object', () => {
103
104
  const result = schema.safeParse(new Boolean(true))
@@ -1,18 +1,8 @@
1
- import { Schema, ValidationResult, ValidatorContext } from '../core.js'
2
-
3
- export type BooleanSchemaOptions = {
4
- default?: boolean
5
- }
1
+ import { Schema, ValidationContext } from '../core.js'
2
+ import { memoizedOptions } from '../util/memoize.js'
6
3
 
7
4
  export class BooleanSchema extends Schema<boolean> {
8
- constructor(readonly options?: BooleanSchemaOptions) {
9
- super()
10
- }
11
-
12
- validateInContext(
13
- input: unknown = this.options?.default,
14
- ctx: ValidatorContext,
15
- ): ValidationResult<boolean> {
5
+ validateInContext(input: unknown, ctx: ValidationContext) {
16
6
  if (typeof input === 'boolean') {
17
7
  return ctx.success(input)
18
8
  }
@@ -20,3 +10,7 @@ export class BooleanSchema extends Schema<boolean> {
20
10
  return ctx.issueInvalidType(input, 'boolean')
21
11
  }
22
12
  }
13
+
14
+ export const boolean = /*#__PURE__*/ memoizedOptions(function () {
15
+ return new BooleanSchema()
16
+ })
@@ -1,9 +1,9 @@
1
1
  import { describe, expect, it } from 'vitest'
2
- import { BytesSchema } from './bytes.js'
2
+ import { bytes } from './bytes.js'
3
3
 
4
4
  describe('BytesSchema', () => {
5
5
  describe('basic validation', () => {
6
- const schema = new BytesSchema({})
6
+ const schema = bytes({})
7
7
 
8
8
  it('validates Uint8Array', () => {
9
9
  const result = schema.safeParse(new Uint8Array([0, 1, 2, 3]))
@@ -72,7 +72,7 @@ describe('BytesSchema', () => {
72
72
  })
73
73
 
74
74
  describe('minLength constraint', () => {
75
- const schema = new BytesSchema({ minLength: 3 })
75
+ const schema = bytes({ minLength: 3 })
76
76
 
77
77
  it('validates bytes at minimum length', () => {
78
78
  const result = schema.safeParse(new Uint8Array([0, 1, 2]))
@@ -96,7 +96,7 @@ describe('BytesSchema', () => {
96
96
  })
97
97
 
98
98
  describe('maxLength constraint', () => {
99
- const schema = new BytesSchema({ maxLength: 5 })
99
+ const schema = bytes({ maxLength: 5 })
100
100
 
101
101
  it('validates bytes at maximum length', () => {
102
102
  const result = schema.safeParse(new Uint8Array([0, 1, 2, 3, 4]))
@@ -120,7 +120,7 @@ describe('BytesSchema', () => {
120
120
  })
121
121
 
122
122
  describe('minLength and maxLength constraints', () => {
123
- const schema = new BytesSchema({ minLength: 2, maxLength: 5 })
123
+ const schema = bytes({ minLength: 2, maxLength: 5 })
124
124
 
125
125
  it('validates bytes within range', () => {
126
126
  const result = schema.safeParse(new Uint8Array([0, 1, 2]))
@@ -150,37 +150,37 @@ describe('BytesSchema', () => {
150
150
 
151
151
  describe('edge cases', () => {
152
152
  it('validates with minLength of 0', () => {
153
- const schema = new BytesSchema({ minLength: 0 })
153
+ const schema = bytes({ minLength: 0 })
154
154
  const result = schema.safeParse(new Uint8Array([]))
155
155
  expect(result.success).toBe(true)
156
156
  })
157
157
 
158
158
  it('validates with maxLength of 0', () => {
159
- const schema = new BytesSchema({ maxLength: 0 })
159
+ const schema = bytes({ maxLength: 0 })
160
160
  const result = schema.safeParse(new Uint8Array([]))
161
161
  expect(result.success).toBe(true)
162
162
  })
163
163
 
164
164
  it('rejects non-empty bytes with maxLength of 0', () => {
165
- const schema = new BytesSchema({ maxLength: 0 })
165
+ const schema = bytes({ maxLength: 0 })
166
166
  const result = schema.safeParse(new Uint8Array([0]))
167
167
  expect(result.success).toBe(false)
168
168
  })
169
169
 
170
170
  it('validates bytes with all zeros', () => {
171
- const schema = new BytesSchema({})
171
+ const schema = bytes({})
172
172
  const result = schema.safeParse(new Uint8Array([0, 0, 0, 0]))
173
173
  expect(result.success).toBe(true)
174
174
  })
175
175
 
176
176
  it('validates bytes with all 255s', () => {
177
- const schema = new BytesSchema({})
177
+ const schema = bytes({})
178
178
  const result = schema.safeParse(new Uint8Array([255, 255, 255, 255]))
179
179
  expect(result.success).toBe(true)
180
180
  })
181
181
 
182
182
  it('validates large byte arrays', () => {
183
- const schema = new BytesSchema({})
183
+ const schema = bytes({})
184
184
  const largeArray = new Uint8Array(10000)
185
185
  const result = schema.safeParse(largeArray)
186
186
  expect(result.success).toBe(true)
@@ -188,7 +188,7 @@ describe('BytesSchema', () => {
188
188
  })
189
189
 
190
190
  describe('TypedArray coercion', () => {
191
- const schema = new BytesSchema({})
191
+ const schema = bytes({})
192
192
 
193
193
  it('coerces Int8Array to Uint8Array', () => {
194
194
  const int8 = new Int8Array([1, 2, 3])
@@ -218,7 +218,7 @@ describe('BytesSchema', () => {
218
218
  })
219
219
 
220
220
  it('validates coerced TypedArray with length constraints', () => {
221
- const schema = new BytesSchema({ minLength: 2, maxLength: 10 })
221
+ const schema = bytes({ minLength: 2, maxLength: 10 })
222
222
  const int16 = new Int16Array([1, 2, 3]) // 6 bytes
223
223
  const result = schema.safeParse(int16)
224
224
  expect(result.success).toBe(true)
@@ -1,5 +1,6 @@
1
- import { asUint8Array } from '@atproto/lex-data'
2
- import { Schema, ValidationResult, ValidatorContext } from '../core.js'
1
+ import { asUint8Array, ifUint8Array } from '@atproto/lex-data'
2
+ import { Schema, ValidationContext } from '../core.js'
3
+ import { memoizedOptions } from '../util/memoize.js'
3
4
 
4
5
  export type BytesSchemaOptions = {
5
6
  minLength?: number
@@ -11,12 +12,10 @@ export class BytesSchema extends Schema<Uint8Array> {
11
12
  super()
12
13
  }
13
14
 
14
- validateInContext(
15
- input: unknown,
16
- ctx: ValidatorContext,
17
- ): ValidationResult<Uint8Array> {
18
- // Coerce different binary formats into Uint8Array
19
- const bytes = asUint8Array(input)
15
+ validateInContext(input: unknown, ctx: ValidationContext) {
16
+ // In "parse" mode, coerce different binary formats into Uint8Array
17
+ const bytes =
18
+ ctx.options.mode === 'parse' ? asUint8Array(input) : ifUint8Array(input)
20
19
  if (!bytes) {
21
20
  return ctx.issueInvalidType(input, 'bytes')
22
21
  }
@@ -34,3 +33,9 @@ export class BytesSchema extends Schema<Uint8Array> {
34
33
  return ctx.success(bytes)
35
34
  }
36
35
  }
36
+
37
+ export const bytes = /*#__PURE__*/ memoizedOptions(function (
38
+ options?: BytesSchemaOptions,
39
+ ) {
40
+ return new BytesSchema(options)
41
+ })
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
  import { parseCid } from '@atproto/lex-data'
3
- import { CidSchema } from './cid.js'
3
+ import { cid } from './cid.js'
4
4
 
5
5
  const cborCid = parseCid(
6
6
  'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a',
@@ -26,7 +26,7 @@ const sha512Cid = parseCid(
26
26
 
27
27
  describe('CidSchema', () => {
28
28
  describe('default mode (non-strict)', () => {
29
- const schema = new CidSchema({})
29
+ const schema = cid({})
30
30
 
31
31
  it('validates CID v1 with DAG-CBOR codec and SHA-256', () => {
32
32
  const result = schema.safeParse(cborCid)
@@ -80,7 +80,7 @@ describe('CidSchema', () => {
80
80
  })
81
81
 
82
82
  describe('strict mode', () => {
83
- const schema = new CidSchema({ flavor: 'dasl' })
83
+ const schema = cid({ flavor: 'dasl' })
84
84
 
85
85
  it('validates CID v1 with DAG-CBOR codec and SHA-256', () => {
86
86
  const result = schema.safeParse(cborCid)
package/src/schema/cid.ts CHANGED
@@ -1,23 +1,19 @@
1
- import { Cid, CidCheckOptions, InferCheckedCid, isCid } from '@atproto/lex-data'
2
- import { Schema, ValidationResult, ValidatorContext } from '../core.js'
1
+ import { CheckCidOptions, Cid, InferCheckedCid, isCid } from '@atproto/lex-data'
2
+ import { Schema, ValidationContext } from '../core.js'
3
+ import { memoizedOptions } from '../util/memoize.js'
3
4
 
4
5
  export type { Cid }
5
6
 
6
- export type CidSchemaOptions = CidCheckOptions
7
- export type CidSchemaOutput<TOptions extends CidSchemaOptions> =
8
- InferCheckedCid<TOptions>
7
+ export type CidSchemaOptions = CheckCidOptions
9
8
 
10
- export class CidSchema<TOptions extends CidSchemaOptions> extends Schema<
11
- CidSchemaOutput<TOptions>
12
- > {
13
- constructor(readonly options: TOptions) {
9
+ export class CidSchema<
10
+ const TOptions extends CidSchemaOptions = { flavor: undefined },
11
+ > extends Schema<InferCheckedCid<TOptions>> {
12
+ constructor(readonly options?: TOptions) {
14
13
  super()
15
14
  }
16
15
 
17
- validateInContext(
18
- input: unknown,
19
- ctx: ValidatorContext,
20
- ): ValidationResult<CidSchemaOutput<TOptions>> {
16
+ validateInContext(input: unknown, ctx: ValidationContext) {
21
17
  if (!isCid(input, this.options)) {
22
18
  return ctx.issueInvalidType(input, 'cid')
23
19
  }
@@ -25,3 +21,9 @@ export class CidSchema<TOptions extends CidSchemaOptions> extends Schema<
25
21
  return ctx.success(input)
26
22
  }
27
23
  }
24
+
25
+ export const cid = /*#__PURE__*/ memoizedOptions(function <
26
+ O extends CidSchemaOptions = NonNullable<unknown>,
27
+ >(options?: O) {
28
+ return new CidSchema(options)
29
+ })