@atproto/lex-schema 0.0.2 → 0.0.3

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 (289) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/dist/core/$type.d.ts +6 -3
  3. package/dist/core/$type.d.ts.map +1 -1
  4. package/dist/core/$type.js +1 -0
  5. package/dist/core/$type.js.map +1 -1
  6. package/dist/core/record-key.d.ts +3 -3
  7. package/dist/core/record-key.d.ts.map +1 -1
  8. package/dist/core/record-key.js +12 -6
  9. package/dist/core/record-key.js.map +1 -1
  10. package/dist/core/result.d.ts.map +1 -1
  11. package/dist/core/result.js +6 -0
  12. package/dist/core/result.js.map +1 -1
  13. package/dist/core/string-format.d.ts +30 -27
  14. package/dist/core/string-format.d.ts.map +1 -1
  15. package/dist/core/string-format.js +56 -42
  16. package/dist/core/string-format.js.map +1 -1
  17. package/dist/core/types.d.ts +9 -1
  18. package/dist/core/types.d.ts.map +1 -1
  19. package/dist/core/types.js.map +1 -1
  20. package/dist/external.d.ts +31 -28
  21. package/dist/external.d.ts.map +1 -1
  22. package/dist/external.js +33 -17
  23. package/dist/external.js.map +1 -1
  24. package/dist/schema/_parameters.d.ts +2 -2
  25. package/dist/schema/_parameters.d.ts.map +1 -1
  26. package/dist/schema/array.d.ts +5 -6
  27. package/dist/schema/array.d.ts.map +1 -1
  28. package/dist/schema/array.js +5 -6
  29. package/dist/schema/array.js.map +1 -1
  30. package/dist/schema/blob.d.ts +2 -3
  31. package/dist/schema/blob.d.ts.map +1 -1
  32. package/dist/schema/blob.js +1 -2
  33. package/dist/schema/blob.js.map +1 -1
  34. package/dist/schema/boolean.d.ts +4 -5
  35. package/dist/schema/boolean.d.ts.map +1 -1
  36. package/dist/schema/boolean.js +2 -3
  37. package/dist/schema/boolean.js.map +1 -1
  38. package/dist/schema/bytes.d.ts +3 -4
  39. package/dist/schema/bytes.d.ts.map +1 -1
  40. package/dist/schema/bytes.js +2 -3
  41. package/dist/schema/bytes.js.map +1 -1
  42. package/dist/schema/cid.d.ts +13 -6
  43. package/dist/schema/cid.d.ts.map +1 -1
  44. package/dist/schema/cid.js +2 -4
  45. package/dist/schema/cid.js.map +1 -1
  46. package/dist/schema/custom.d.ts +3 -4
  47. package/dist/schema/custom.d.ts.map +1 -1
  48. package/dist/schema/custom.js +4 -3
  49. package/dist/schema/custom.js.map +1 -1
  50. package/dist/schema/dict.d.ts +3 -3
  51. package/dist/schema/dict.d.ts.map +1 -1
  52. package/dist/schema/dict.js +1 -1
  53. package/dist/schema/dict.js.map +1 -1
  54. package/dist/schema/discriminated-union.d.ts +15 -24
  55. package/dist/schema/discriminated-union.d.ts.map +1 -1
  56. package/dist/schema/discriminated-union.js +40 -64
  57. package/dist/schema/discriminated-union.js.map +1 -1
  58. package/dist/schema/enum.d.ts +8 -4
  59. package/dist/schema/enum.d.ts.map +1 -1
  60. package/dist/schema/enum.js +5 -3
  61. package/dist/schema/enum.js.map +1 -1
  62. package/dist/schema/integer.d.ts +3 -4
  63. package/dist/schema/integer.d.ts.map +1 -1
  64. package/dist/schema/integer.js +3 -4
  65. package/dist/schema/integer.js.map +1 -1
  66. package/dist/schema/intersection.d.ts +22 -14
  67. package/dist/schema/intersection.d.ts.map +1 -1
  68. package/dist/schema/intersection.js +12 -22
  69. package/dist/schema/intersection.js.map +1 -1
  70. package/dist/schema/literal.d.ts +7 -3
  71. package/dist/schema/literal.d.ts.map +1 -1
  72. package/dist/schema/literal.js +5 -3
  73. package/dist/schema/literal.js.map +1 -1
  74. package/dist/schema/never.d.ts +2 -2
  75. package/dist/schema/never.d.ts.map +1 -1
  76. package/dist/schema/never.js +1 -1
  77. package/dist/schema/never.js.map +1 -1
  78. package/dist/schema/null.d.ts +2 -3
  79. package/dist/schema/null.d.ts.map +1 -1
  80. package/dist/schema/null.js +1 -2
  81. package/dist/schema/null.js.map +1 -1
  82. package/dist/schema/nullable.d.ts +7 -0
  83. package/dist/schema/nullable.d.ts.map +1 -0
  84. package/dist/schema/nullable.js +19 -0
  85. package/dist/schema/nullable.js.map +1 -0
  86. package/dist/schema/object.d.ts +10 -44
  87. package/dist/schema/object.d.ts.map +1 -1
  88. package/dist/schema/object.js +10 -46
  89. package/dist/schema/object.js.map +1 -1
  90. package/dist/schema/optional.d.ts +7 -0
  91. package/dist/schema/optional.d.ts.map +1 -0
  92. package/dist/schema/optional.js +25 -0
  93. package/dist/schema/optional.js.map +1 -0
  94. package/dist/schema/params.d.ts +14 -19
  95. package/dist/schema/params.d.ts.map +1 -1
  96. package/dist/schema/params.js +10 -24
  97. package/dist/schema/params.js.map +1 -1
  98. package/dist/schema/payload.d.ts +4 -4
  99. package/dist/schema/payload.d.ts.map +1 -1
  100. package/dist/schema/payload.js.map +1 -1
  101. package/dist/schema/permission-set.d.ts +6 -6
  102. package/dist/schema/permission-set.d.ts.map +1 -1
  103. package/dist/schema/permission-set.js +1 -2
  104. package/dist/schema/permission-set.js.map +1 -1
  105. package/dist/schema/permission.d.ts +0 -1
  106. package/dist/schema/permission.d.ts.map +1 -1
  107. package/dist/schema/permission.js +0 -1
  108. package/dist/schema/permission.js.map +1 -1
  109. package/dist/schema/procedure.d.ts +8 -9
  110. package/dist/schema/procedure.d.ts.map +1 -1
  111. package/dist/schema/procedure.js +0 -1
  112. package/dist/schema/procedure.js.map +1 -1
  113. package/dist/schema/query.d.ts +7 -8
  114. package/dist/schema/query.d.ts.map +1 -1
  115. package/dist/schema/query.js +0 -1
  116. package/dist/schema/query.js.map +1 -1
  117. package/dist/schema/record.d.ts +34 -28
  118. package/dist/schema/record.d.ts.map +1 -1
  119. package/dist/schema/record.js +1 -2
  120. package/dist/schema/record.js.map +1 -1
  121. package/dist/schema/ref.d.ts +2 -3
  122. package/dist/schema/ref.d.ts.map +1 -1
  123. package/dist/schema/ref.js +1 -2
  124. package/dist/schema/ref.js.map +1 -1
  125. package/dist/schema/refine.d.ts +18 -0
  126. package/dist/schema/refine.d.ts.map +1 -0
  127. package/dist/schema/refine.js +33 -0
  128. package/dist/schema/refine.js.map +1 -0
  129. package/dist/schema/regexp.d.ts +7 -0
  130. package/dist/schema/regexp.d.ts.map +1 -0
  131. package/dist/schema/regexp.js +22 -0
  132. package/dist/schema/regexp.js.map +1 -0
  133. package/dist/schema/string.d.ts +4 -8
  134. package/dist/schema/string.d.ts.map +1 -1
  135. package/dist/schema/string.js +6 -3
  136. package/dist/schema/string.js.map +1 -1
  137. package/dist/schema/subscription.d.ts +7 -6
  138. package/dist/schema/subscription.d.ts.map +1 -1
  139. package/dist/schema/subscription.js.map +1 -1
  140. package/dist/schema/token.d.ts +2 -3
  141. package/dist/schema/token.d.ts.map +1 -1
  142. package/dist/schema/token.js +1 -2
  143. package/dist/schema/token.js.map +1 -1
  144. package/dist/schema/typed-object.d.ts +29 -27
  145. package/dist/schema/typed-object.d.ts.map +1 -1
  146. package/dist/schema/typed-object.js +1 -2
  147. package/dist/schema/typed-object.js.map +1 -1
  148. package/dist/schema/typed-ref.d.ts +2 -2
  149. package/dist/schema/typed-ref.d.ts.map +1 -1
  150. package/dist/schema/typed-ref.js +1 -1
  151. package/dist/schema/typed-ref.js.map +1 -1
  152. package/dist/schema/typed-union.d.ts +3 -4
  153. package/dist/schema/typed-union.d.ts.map +1 -1
  154. package/dist/schema/typed-union.js +3 -10
  155. package/dist/schema/typed-union.js.map +1 -1
  156. package/dist/schema/union.d.ts +2 -2
  157. package/dist/schema/union.d.ts.map +1 -1
  158. package/dist/schema/union.js +1 -1
  159. package/dist/schema/union.js.map +1 -1
  160. package/dist/schema/unknown-object.d.ts +2 -3
  161. package/dist/schema/unknown-object.d.ts.map +1 -1
  162. package/dist/schema/unknown-object.js +1 -2
  163. package/dist/schema/unknown-object.js.map +1 -1
  164. package/dist/schema/unknown.d.ts +2 -2
  165. package/dist/schema/unknown.d.ts.map +1 -1
  166. package/dist/schema/unknown.js +1 -1
  167. package/dist/schema/unknown.js.map +1 -1
  168. package/dist/schema.d.ts +4 -0
  169. package/dist/schema.d.ts.map +1 -1
  170. package/dist/schema.js +6 -1
  171. package/dist/schema.js.map +1 -1
  172. package/dist/util/array-agg.d.ts.map +1 -1
  173. package/dist/util/array-agg.js +1 -0
  174. package/dist/util/array-agg.js.map +1 -1
  175. package/dist/util/lazy-property.d.ts +2 -0
  176. package/dist/util/lazy-property.d.ts.map +1 -0
  177. package/dist/util/lazy-property.js +14 -0
  178. package/dist/util/lazy-property.js.map +1 -0
  179. package/dist/validation/schema.d.ts +24 -0
  180. package/dist/validation/schema.d.ts.map +1 -0
  181. package/dist/validation/schema.js +57 -0
  182. package/dist/validation/schema.js.map +1 -0
  183. package/dist/validation/validation-error.d.ts +3 -3
  184. package/dist/validation/validation-error.d.ts.map +1 -1
  185. package/dist/validation/validation-error.js +32 -4
  186. package/dist/validation/validation-error.js.map +1 -1
  187. package/dist/validation/validation-issue.d.ts +32 -24
  188. package/dist/validation/validation-issue.d.ts.map +1 -1
  189. package/dist/validation/validation-issue.js +136 -92
  190. package/dist/validation/validation-issue.js.map +1 -1
  191. package/dist/validation/validator.d.ts +20 -50
  192. package/dist/validation/validator.d.ts.map +1 -1
  193. package/dist/validation/validator.js +40 -134
  194. package/dist/validation/validator.js.map +1 -1
  195. package/dist/validation.d.ts +1 -0
  196. package/dist/validation.d.ts.map +1 -1
  197. package/dist/validation.js +1 -0
  198. package/dist/validation.js.map +1 -1
  199. package/package.json +8 -4
  200. package/src/core/$type.ts +7 -4
  201. package/src/core/record-key.ts +12 -5
  202. package/src/core/result.ts +6 -0
  203. package/src/core/string-format.ts +97 -61
  204. package/src/core/types.ts +12 -6
  205. package/src/external.ts +92 -70
  206. package/src/schema/_parameters.test.ts +416 -0
  207. package/src/schema/array.test.ts +237 -0
  208. package/src/schema/array.ts +17 -11
  209. package/src/schema/blob.test.ts +506 -0
  210. package/src/schema/blob.ts +3 -5
  211. package/src/schema/boolean.test.ts +116 -0
  212. package/src/schema/boolean.ts +5 -7
  213. package/src/schema/bytes.test.ts +226 -0
  214. package/src/schema/bytes.ts +4 -6
  215. package/src/schema/cid.test.ts +155 -0
  216. package/src/schema/cid.ts +14 -8
  217. package/src/schema/custom.test.ts +413 -0
  218. package/src/schema/custom.ts +10 -8
  219. package/src/schema/dict.test.ts +198 -0
  220. package/src/schema/dict.ts +6 -8
  221. package/src/schema/discriminated-union.test.ts +675 -0
  222. package/src/schema/discriminated-union.ts +68 -95
  223. package/src/schema/enum.test.ts +396 -0
  224. package/src/schema/enum.ts +12 -5
  225. package/src/schema/integer.test.ts +312 -0
  226. package/src/schema/integer.ts +5 -7
  227. package/src/schema/intersection.test.ts +32 -0
  228. package/src/schema/intersection.ts +37 -40
  229. package/src/schema/literal.test.ts +531 -0
  230. package/src/schema/literal.ts +12 -5
  231. package/src/schema/never.test.ts +174 -0
  232. package/src/schema/never.ts +3 -10
  233. package/src/schema/null.test.ts +79 -0
  234. package/src/schema/null.ts +3 -5
  235. package/src/schema/nullable.test.ts +480 -0
  236. package/src/schema/nullable.ts +23 -0
  237. package/src/schema/object.test.ts +47 -115
  238. package/src/schema/object.ts +19 -123
  239. package/src/schema/optional.test.ts +485 -0
  240. package/src/schema/optional.ts +31 -0
  241. package/src/schema/params.test.ts +582 -0
  242. package/src/schema/params.ts +37 -55
  243. package/src/schema/payload.test.ts +345 -0
  244. package/src/schema/payload.ts +5 -5
  245. package/src/schema/permission-set.test.ts +679 -0
  246. package/src/schema/permission-set.ts +6 -8
  247. package/src/schema/permission.test.ts +536 -0
  248. package/src/schema/permission.ts +0 -2
  249. package/src/schema/procedure.test.ts +443 -0
  250. package/src/schema/procedure.ts +11 -13
  251. package/src/schema/query.test.ts +408 -0
  252. package/src/schema/query.ts +9 -11
  253. package/src/schema/record.test.ts +694 -0
  254. package/src/schema/record.ts +38 -36
  255. package/src/schema/ref.test.ts +365 -0
  256. package/src/schema/ref.ts +8 -5
  257. package/src/schema/refine.test.ts +578 -0
  258. package/src/schema/refine.ts +85 -0
  259. package/src/schema/regexp.test.ts +580 -0
  260. package/src/schema/regexp.ts +22 -0
  261. package/src/schema/string.test.ts +612 -0
  262. package/src/schema/string.ts +11 -17
  263. package/src/schema/subscription.test.ts +689 -0
  264. package/src/schema/subscription.ts +13 -8
  265. package/src/schema/token.test.ts +428 -0
  266. package/src/schema/token.ts +3 -5
  267. package/src/schema/typed-object.test.ts +612 -0
  268. package/src/schema/typed-object.ts +23 -20
  269. package/src/schema/typed-ref.test.ts +823 -0
  270. package/src/schema/typed-ref.ts +10 -5
  271. package/src/schema/typed-union.test.ts +378 -0
  272. package/src/schema/typed-union.ts +6 -15
  273. package/src/schema/union.test.ts +200 -0
  274. package/src/schema/union.ts +5 -4
  275. package/src/schema/unknown-object.test.ts +592 -0
  276. package/src/schema/unknown-object.ts +3 -5
  277. package/src/schema/unknown.test.ts +312 -0
  278. package/src/schema/unknown.ts +3 -3
  279. package/src/schema.ts +7 -1
  280. package/src/util/array-agg.ts +1 -0
  281. package/src/util/lazy-property.ts +14 -0
  282. package/src/validation/schema.ts +92 -0
  283. package/src/validation/validation-error.ts +60 -9
  284. package/src/validation/validation-issue.ts +141 -144
  285. package/src/validation/validator.ts +67 -206
  286. package/src/validation.ts +1 -0
  287. package/tsconfig.build.json +12 -0
  288. package/tsconfig.json +7 -0
  289. package/tsconfig.tests.json +9 -0
@@ -0,0 +1,226 @@
1
+ import { BytesSchema } from './bytes.js'
2
+
3
+ describe('BytesSchema', () => {
4
+ describe('basic validation', () => {
5
+ const schema = new BytesSchema({})
6
+
7
+ it('validates Uint8Array', () => {
8
+ const result = schema.safeParse(new Uint8Array([0, 1, 2, 3]))
9
+ expect(result.success).toBe(true)
10
+ })
11
+
12
+ it('validates empty Uint8Array', () => {
13
+ const result = schema.safeParse(new Uint8Array([]))
14
+ expect(result.success).toBe(true)
15
+ })
16
+
17
+ it('validates ArrayBuffer', () => {
18
+ const buffer = new ArrayBuffer(4)
19
+ const result = schema.safeParse(buffer)
20
+ expect(result.success).toBe(true)
21
+ })
22
+
23
+ it('validates TypedArray views', () => {
24
+ const int8 = new Int8Array([1, 2, 3])
25
+ const result = schema.safeParse(int8)
26
+ expect(result.success).toBe(true)
27
+ })
28
+
29
+ it('validates Uint16Array', () => {
30
+ const uint16 = new Uint16Array([1, 2, 3])
31
+ const result = schema.safeParse(uint16)
32
+ expect(result.success).toBe(true)
33
+ })
34
+
35
+ it('validates DataView', () => {
36
+ const buffer = new ArrayBuffer(4)
37
+ const dataView = new DataView(buffer)
38
+ const result = schema.safeParse(dataView)
39
+ expect(result.success).toBe(true)
40
+ })
41
+
42
+ it('rejects strings', () => {
43
+ const result = schema.safeParse('not bytes')
44
+ expect(result.success).toBe(false)
45
+ })
46
+
47
+ it('rejects numbers', () => {
48
+ const result = schema.safeParse(123)
49
+ expect(result.success).toBe(false)
50
+ })
51
+
52
+ it('rejects objects', () => {
53
+ const result = schema.safeParse({ data: [1, 2, 3] })
54
+ expect(result.success).toBe(false)
55
+ })
56
+
57
+ it('rejects arrays', () => {
58
+ const result = schema.safeParse([1, 2, 3])
59
+ expect(result.success).toBe(false)
60
+ })
61
+
62
+ it('rejects null', () => {
63
+ const result = schema.safeParse(null)
64
+ expect(result.success).toBe(false)
65
+ })
66
+
67
+ it('rejects undefined', () => {
68
+ const result = schema.safeParse(undefined)
69
+ expect(result.success).toBe(false)
70
+ })
71
+ })
72
+
73
+ describe('minLength constraint', () => {
74
+ const schema = new BytesSchema({ minLength: 3 })
75
+
76
+ it('validates bytes at minimum length', () => {
77
+ const result = schema.safeParse(new Uint8Array([0, 1, 2]))
78
+ expect(result.success).toBe(true)
79
+ })
80
+
81
+ it('validates bytes above minimum length', () => {
82
+ const result = schema.safeParse(new Uint8Array([0, 1, 2, 3, 4]))
83
+ expect(result.success).toBe(true)
84
+ })
85
+
86
+ it('rejects bytes below minimum length', () => {
87
+ const result = schema.safeParse(new Uint8Array([0, 1]))
88
+ expect(result.success).toBe(false)
89
+ })
90
+
91
+ it('rejects empty bytes when minLength is set', () => {
92
+ const result = schema.safeParse(new Uint8Array([]))
93
+ expect(result.success).toBe(false)
94
+ })
95
+ })
96
+
97
+ describe('maxLength constraint', () => {
98
+ const schema = new BytesSchema({ maxLength: 5 })
99
+
100
+ it('validates bytes at maximum length', () => {
101
+ const result = schema.safeParse(new Uint8Array([0, 1, 2, 3, 4]))
102
+ expect(result.success).toBe(true)
103
+ })
104
+
105
+ it('validates bytes below maximum length', () => {
106
+ const result = schema.safeParse(new Uint8Array([0, 1, 2]))
107
+ expect(result.success).toBe(true)
108
+ })
109
+
110
+ it('validates empty bytes when only maxLength is set', () => {
111
+ const result = schema.safeParse(new Uint8Array([]))
112
+ expect(result.success).toBe(true)
113
+ })
114
+
115
+ it('rejects bytes above maximum length', () => {
116
+ const result = schema.safeParse(new Uint8Array([0, 1, 2, 3, 4, 5]))
117
+ expect(result.success).toBe(false)
118
+ })
119
+ })
120
+
121
+ describe('minLength and maxLength constraints', () => {
122
+ const schema = new BytesSchema({ minLength: 2, maxLength: 5 })
123
+
124
+ it('validates bytes within range', () => {
125
+ const result = schema.safeParse(new Uint8Array([0, 1, 2]))
126
+ expect(result.success).toBe(true)
127
+ })
128
+
129
+ it('validates bytes at minimum length', () => {
130
+ const result = schema.safeParse(new Uint8Array([0, 1]))
131
+ expect(result.success).toBe(true)
132
+ })
133
+
134
+ it('validates bytes at maximum length', () => {
135
+ const result = schema.safeParse(new Uint8Array([0, 1, 2, 3, 4]))
136
+ expect(result.success).toBe(true)
137
+ })
138
+
139
+ it('rejects bytes below minimum length', () => {
140
+ const result = schema.safeParse(new Uint8Array([0]))
141
+ expect(result.success).toBe(false)
142
+ })
143
+
144
+ it('rejects bytes above maximum length', () => {
145
+ const result = schema.safeParse(new Uint8Array([0, 1, 2, 3, 4, 5]))
146
+ expect(result.success).toBe(false)
147
+ })
148
+ })
149
+
150
+ describe('edge cases', () => {
151
+ it('validates with minLength of 0', () => {
152
+ const schema = new BytesSchema({ minLength: 0 })
153
+ const result = schema.safeParse(new Uint8Array([]))
154
+ expect(result.success).toBe(true)
155
+ })
156
+
157
+ it('validates with maxLength of 0', () => {
158
+ const schema = new BytesSchema({ maxLength: 0 })
159
+ const result = schema.safeParse(new Uint8Array([]))
160
+ expect(result.success).toBe(true)
161
+ })
162
+
163
+ it('rejects non-empty bytes with maxLength of 0', () => {
164
+ const schema = new BytesSchema({ maxLength: 0 })
165
+ const result = schema.safeParse(new Uint8Array([0]))
166
+ expect(result.success).toBe(false)
167
+ })
168
+
169
+ it('validates bytes with all zeros', () => {
170
+ const schema = new BytesSchema({})
171
+ const result = schema.safeParse(new Uint8Array([0, 0, 0, 0]))
172
+ expect(result.success).toBe(true)
173
+ })
174
+
175
+ it('validates bytes with all 255s', () => {
176
+ const schema = new BytesSchema({})
177
+ const result = schema.safeParse(new Uint8Array([255, 255, 255, 255]))
178
+ expect(result.success).toBe(true)
179
+ })
180
+
181
+ it('validates large byte arrays', () => {
182
+ const schema = new BytesSchema({})
183
+ const largeArray = new Uint8Array(10000)
184
+ const result = schema.safeParse(largeArray)
185
+ expect(result.success).toBe(true)
186
+ })
187
+ })
188
+
189
+ describe('TypedArray coercion', () => {
190
+ const schema = new BytesSchema({})
191
+
192
+ it('coerces Int8Array to Uint8Array', () => {
193
+ const int8 = new Int8Array([1, 2, 3])
194
+ const result = schema.safeParse(int8)
195
+ expect(result.success).toBe(true)
196
+ if (result.success) {
197
+ expect(result.value).toBeInstanceOf(Uint8Array)
198
+ }
199
+ })
200
+
201
+ it('coerces Uint16Array to Uint8Array', () => {
202
+ const uint16 = new Uint16Array([256, 512])
203
+ const result = schema.safeParse(uint16)
204
+ expect(result.success).toBe(true)
205
+ if (result.success) {
206
+ expect(result.value).toBeInstanceOf(Uint8Array)
207
+ }
208
+ })
209
+
210
+ it('coerces Float32Array to Uint8Array', () => {
211
+ const float32 = new Float32Array([1.5, 2.5])
212
+ const result = schema.safeParse(float32)
213
+ expect(result.success).toBe(true)
214
+ if (result.success) {
215
+ expect(result.value).toBeInstanceOf(Uint8Array)
216
+ }
217
+ })
218
+
219
+ it('validates coerced TypedArray with length constraints', () => {
220
+ const schema = new BytesSchema({ minLength: 2, maxLength: 10 })
221
+ const int16 = new Int16Array([1, 2, 3]) // 6 bytes
222
+ const result = schema.safeParse(int16)
223
+ expect(result.success).toBe(true)
224
+ })
225
+ })
226
+ })
@@ -1,19 +1,17 @@
1
1
  import { asUint8Array } from '@atproto/lex-data'
2
- import { ValidationResult, Validator, ValidatorContext } from '../validation.js'
2
+ import { Schema, ValidationResult, ValidatorContext } from '../validation.js'
3
3
 
4
4
  export type BytesSchemaOptions = {
5
5
  minLength?: number
6
6
  maxLength?: number
7
7
  }
8
8
 
9
- export class BytesSchema extends Validator<Uint8Array> {
10
- readonly lexiconType = 'bytes' as const
11
-
12
- constructor(readonly options: BytesSchemaOptions) {
9
+ export class BytesSchema extends Schema<Uint8Array> {
10
+ constructor(readonly options: BytesSchemaOptions = {}) {
13
11
  super()
14
12
  }
15
13
 
16
- override validateInContext(
14
+ validateInContext(
17
15
  input: unknown,
18
16
  ctx: ValidatorContext,
19
17
  ): ValidationResult<Uint8Array> {
@@ -0,0 +1,155 @@
1
+ import { parseCid } from '@atproto/lex-data'
2
+ import { CidSchema } from './cid.js'
3
+
4
+ describe('CidSchema', () => {
5
+ describe('default mode (non-strict)', () => {
6
+ const schema = new CidSchema()
7
+
8
+ it('validates CID v1 with DAG-CBOR codec and SHA-256', () => {
9
+ const cid = parseCid(
10
+ 'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a',
11
+ )
12
+ const result = schema.safeParse(cid)
13
+ expect(result.success).toBe(true)
14
+ })
15
+
16
+ it('validates CID v1 with raw binary codec', () => {
17
+ const cid = parseCid(
18
+ 'bafkreifjjcie6lypi6ny7amxnfftagclbuxndqonfipmb64f2km2devei4',
19
+ )
20
+ const result = schema.safeParse(cid)
21
+ expect(result.success).toBe(true)
22
+ })
23
+
24
+ it('validates CID v0', () => {
25
+ const cid = parseCid('QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB')
26
+ const result = schema.safeParse(cid)
27
+ expect(result.success).toBe(true)
28
+ })
29
+
30
+ it('validates multiple different CIDs', () => {
31
+ const cids = [
32
+ parseCid('bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a'),
33
+ parseCid('bafyreigoxt64qghytzkr6ik7qvtzc7lyytiq5xbbrokbxjows2wp7vmo6q'),
34
+ parseCid('bafyreiaizynclnqiolq7byfpjjtgqzn4sfrsgn7z2hhf6bo4utdwkin7ke'),
35
+ parseCid('bafyreifd4w4tcr5tluxz7osjtnofffvtsmgdqcfrfi6evjde4pl27lrjpy'),
36
+ ]
37
+
38
+ for (const cid of cids) {
39
+ const result = schema.safeParse(cid)
40
+ expect(result.success).toBe(true)
41
+ }
42
+ })
43
+
44
+ it('rejects non-CID objects', () => {
45
+ const result = schema.safeParse({ not: 'a cid' })
46
+ expect(result.success).toBe(false)
47
+ })
48
+
49
+ it('rejects strings', () => {
50
+ const result = schema.safeParse(
51
+ 'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a',
52
+ )
53
+ expect(result.success).toBe(false)
54
+ })
55
+
56
+ it('rejects numbers', () => {
57
+ const result = schema.safeParse(123)
58
+ expect(result.success).toBe(false)
59
+ })
60
+
61
+ it('rejects null', () => {
62
+ const result = schema.safeParse(null)
63
+ expect(result.success).toBe(false)
64
+ })
65
+
66
+ it('rejects undefined', () => {
67
+ const result = schema.safeParse(undefined)
68
+ expect(result.success).toBe(false)
69
+ })
70
+
71
+ it('rejects arrays', () => {
72
+ const result = schema.safeParse([])
73
+ expect(result.success).toBe(false)
74
+ })
75
+
76
+ it('rejects booleans', () => {
77
+ const result = schema.safeParse(true)
78
+ expect(result.success).toBe(false)
79
+ })
80
+ })
81
+
82
+ describe('strict mode', () => {
83
+ const schema = new CidSchema({ strict: true })
84
+
85
+ it('validates CID v1 with DAG-CBOR codec and SHA-256', () => {
86
+ const cid = parseCid(
87
+ 'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a',
88
+ )
89
+ const result = schema.safeParse(cid)
90
+ expect(result.success).toBe(true)
91
+ })
92
+
93
+ it('validates CID v1 with raw binary codec and SHA-256', () => {
94
+ const cid = parseCid(
95
+ 'bafkreifjjcie6lypi6ny7amxnfftagclbuxndqonfipmb64f2km2devei4',
96
+ )
97
+ const result = schema.safeParse(cid)
98
+ expect(result.success).toBe(true)
99
+ })
100
+
101
+ it('rejects CID v0', () => {
102
+ const cid = parseCid('QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB')
103
+ const result = schema.safeParse(cid)
104
+ expect(result.success).toBe(false)
105
+ })
106
+
107
+ it('rejects CID v1 with non-standard codec', () => {
108
+ // Using git-raw codec (0x78) instead of DAG-CBOR or raw binary
109
+ const cid = parseCid(
110
+ 'bafybeigvgzoolc3drupxhlevdp2ugqcrbcsqfmcek2zxiw5wctk3xjpjwy',
111
+ )
112
+ const result = schema.safeParse(cid)
113
+ expect(result.success).toBe(false)
114
+ })
115
+
116
+ it('rejects CID v1 with non-SHA-256 hash', () => {
117
+ // Using SHA-512 (0x13) instead of SHA-256
118
+ const cid = parseCid(
119
+ 'bafybgqfcn3rz4mdzywp2jb6mjvpdq24rxjvbmdcmizrjdgx2ujjpvj4kxf4d62ywrzm6njk44cxhha4pj3bkvqz2esfgrm7mdkdcqcxjibf7c',
120
+ )
121
+ const result = schema.safeParse(cid)
122
+ expect(result.success).toBe(false)
123
+ })
124
+
125
+ it('rejects non-CID objects', () => {
126
+ const result = schema.safeParse({ not: 'a cid' })
127
+ expect(result.success).toBe(false)
128
+ })
129
+
130
+ it('rejects strings', () => {
131
+ const result = schema.safeParse(
132
+ 'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a',
133
+ )
134
+ expect(result.success).toBe(false)
135
+ })
136
+
137
+ it('rejects null', () => {
138
+ const result = schema.safeParse(null)
139
+ expect(result.success).toBe(false)
140
+ })
141
+ })
142
+
143
+ describe('options', () => {
144
+ it('stores the provided options', () => {
145
+ const options = { strict: true }
146
+ const schema = new CidSchema(options)
147
+ expect(schema.options).toEqual(options)
148
+ })
149
+
150
+ it('defaults to empty options', () => {
151
+ const schema = new CidSchema()
152
+ expect(schema.options).toEqual({})
153
+ })
154
+ })
155
+ })
package/src/schema/cid.ts CHANGED
@@ -1,23 +1,29 @@
1
- import { CID, isCid } from '@atproto/lex-data'
2
- import { ValidationResult, Validator, ValidatorContext } from '../validation.js'
1
+ import { Cid, isCid } from '@atproto/lex-data'
2
+ import { Schema, ValidationResult, ValidatorContext } from '../validation.js'
3
3
 
4
- export { CID }
4
+ export type { Cid }
5
5
 
6
6
  export type CidSchemaOptions = {
7
+ /**
8
+ * In strict mode, only CID with the following properties are accepted:
9
+ * - version: 1
10
+ * - codec: raw binary (0x55) or DAG-CBOR (0x71)
11
+ * - hash function: SHA-256 (0x12)
12
+ *
13
+ * @default false
14
+ */
7
15
  strict?: boolean
8
16
  }
9
17
 
10
- export class CidSchema extends Validator<CID> {
11
- readonly lexiconType = 'cid-link' as const
12
-
18
+ export class CidSchema extends Schema<Cid> {
13
19
  constructor(readonly options: CidSchemaOptions = {}) {
14
20
  super()
15
21
  }
16
22
 
17
- override validateInContext(
23
+ validateInContext(
18
24
  input: unknown,
19
25
  ctx: ValidatorContext,
20
- ): ValidationResult<CID> {
26
+ ): ValidationResult<Cid> {
21
27
  if (!isCid(input, this.options)) {
22
28
  return ctx.issueInvalidType(input, 'cid')
23
29
  }