@atproto/lexicon 0.0.4 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/blob-refs.d.ts +67 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3072 -392
- package/dist/index.js.map +4 -4
- package/dist/lexicons.d.ts +6 -4
- package/dist/serialize.d.ts +12 -0
- package/dist/types.d.ts +24498 -15979
- package/dist/util.d.ts +1 -1
- package/dist/validation.d.ts +6 -5
- package/dist/validators/blob.d.ts +0 -3
- package/dist/validators/complex.d.ts +2 -2
- package/dist/validators/formats.d.ts +9 -0
- package/dist/validators/primitives.d.ts +3 -2
- package/dist/validators/xrpc.d.ts +1 -1
- package/package.json +5 -1
- package/src/blob-refs.ts +70 -0
- package/src/index.ts +2 -0
- package/src/lexicons.ts +36 -5
- package/src/serialize.ts +93 -0
- package/src/types.ts +86 -58
- package/src/util.ts +3 -4
- package/src/validation.ts +28 -4
- package/src/validators/blob.ts +5 -43
- package/src/validators/complex.ts +33 -32
- package/src/validators/formats.ts +107 -0
- package/src/validators/primitives.ts +116 -41
- package/src/validators/xrpc.ts +29 -29
- package/tests/_scaffolds/lexicons.ts +198 -23
- package/tests/general.test.ts +365 -154
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.json +3 -1
package/tests/general.test.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CID } from 'multiformats/cid'
|
|
1
2
|
import { Lexicons } from '../src/index'
|
|
2
3
|
import LexiconDocs from './_scaffolds/lexicons'
|
|
3
4
|
|
|
@@ -40,22 +41,30 @@ describe('General validation', () => {
|
|
|
40
41
|
object: { boolean: true },
|
|
41
42
|
array: ['one', 'two'],
|
|
42
43
|
boolean: true,
|
|
43
|
-
|
|
44
|
+
float: 123.45,
|
|
44
45
|
integer: 123,
|
|
45
46
|
string: 'string',
|
|
46
47
|
},
|
|
47
48
|
array: ['one', 'two'],
|
|
48
49
|
boolean: true,
|
|
49
|
-
|
|
50
|
+
float: 123.45,
|
|
50
51
|
integer: 123,
|
|
51
52
|
string: 'string',
|
|
52
53
|
datetime: new Date().toISOString(),
|
|
54
|
+
atUri: 'at://did:web:example.com/com.example.test/self',
|
|
55
|
+
did: 'did:web:example.com',
|
|
56
|
+
cid: 'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a',
|
|
57
|
+
bytes: new Uint8Array([0, 1, 2, 3]),
|
|
58
|
+
cidLink: CID.parse(
|
|
59
|
+
'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a',
|
|
60
|
+
),
|
|
53
61
|
})
|
|
54
62
|
expect(res.success).toBe(true)
|
|
55
63
|
}
|
|
56
64
|
{
|
|
57
65
|
const res = lex.validate('com.example.kitchenSink', {})
|
|
58
66
|
expect(res.success).toBe(false)
|
|
67
|
+
if (res.success) throw new Error('Asserted')
|
|
59
68
|
expect(res.error?.message).toBe('Record must have the property "object"')
|
|
60
69
|
}
|
|
61
70
|
})
|
|
@@ -65,7 +74,7 @@ describe('General validation', () => {
|
|
|
65
74
|
object: { boolean: true },
|
|
66
75
|
array: ['one', 'two'],
|
|
67
76
|
boolean: true,
|
|
68
|
-
|
|
77
|
+
float: 123.45,
|
|
69
78
|
integer: 123,
|
|
70
79
|
string: 'string',
|
|
71
80
|
})
|
|
@@ -74,6 +83,7 @@ describe('General validation', () => {
|
|
|
74
83
|
{
|
|
75
84
|
const res = lex.validate('com.example.kitchenSink#object', {})
|
|
76
85
|
expect(res.success).toBe(false)
|
|
86
|
+
if (res.success) throw new Error('Asserted')
|
|
77
87
|
expect(res.error?.message).toBe('Object must have the property "object"')
|
|
78
88
|
}
|
|
79
89
|
})
|
|
@@ -82,24 +92,29 @@ describe('General validation', () => {
|
|
|
82
92
|
describe('Record validation', () => {
|
|
83
93
|
const lex = new Lexicons(LexiconDocs)
|
|
84
94
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
object: {
|
|
89
|
-
object: { boolean: true },
|
|
90
|
-
array: ['one', 'two'],
|
|
91
|
-
boolean: true,
|
|
92
|
-
number: 123.45,
|
|
93
|
-
integer: 123,
|
|
94
|
-
string: 'string',
|
|
95
|
-
},
|
|
95
|
+
const passingSink = {
|
|
96
|
+
$type: 'com.example.kitchenSink',
|
|
97
|
+
object: {
|
|
98
|
+
object: { boolean: true },
|
|
96
99
|
array: ['one', 'two'],
|
|
97
100
|
boolean: true,
|
|
98
|
-
|
|
101
|
+
float: 123.45,
|
|
99
102
|
integer: 123,
|
|
100
103
|
string: 'string',
|
|
101
|
-
|
|
102
|
-
|
|
104
|
+
},
|
|
105
|
+
array: ['one', 'two'],
|
|
106
|
+
boolean: true,
|
|
107
|
+
float: 123.45,
|
|
108
|
+
integer: 123,
|
|
109
|
+
string: 'string',
|
|
110
|
+
bytes: new Uint8Array([0, 1, 2, 3]),
|
|
111
|
+
cidLink: CID.parse(
|
|
112
|
+
'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a',
|
|
113
|
+
),
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
it('Passes valid schemas', () => {
|
|
117
|
+
lex.assertValidRecord('com.example.kitchenSink', passingSink)
|
|
103
118
|
})
|
|
104
119
|
|
|
105
120
|
it('Fails invalid input types', () => {
|
|
@@ -129,10 +144,23 @@ describe('Record validation', () => {
|
|
|
129
144
|
$type: 'com.example.kitchenSink',
|
|
130
145
|
array: ['one', 'two'],
|
|
131
146
|
boolean: true,
|
|
132
|
-
|
|
147
|
+
float: 123.45,
|
|
133
148
|
integer: 123,
|
|
134
149
|
string: 'string',
|
|
135
150
|
datetime: new Date().toISOString(),
|
|
151
|
+
atUri: 'at://did:web:example.com/com.example.test/self',
|
|
152
|
+
did: 'did:web:example.com',
|
|
153
|
+
cid: 'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a',
|
|
154
|
+
bytes: new Uint8Array([0, 1, 2, 3]),
|
|
155
|
+
cidLink: CID.parse(
|
|
156
|
+
'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a',
|
|
157
|
+
),
|
|
158
|
+
}),
|
|
159
|
+
).toThrow('Record must have the property "object"')
|
|
160
|
+
expect(() =>
|
|
161
|
+
lex.assertValidRecord('com.example.kitchenSink', {
|
|
162
|
+
...passingSink,
|
|
163
|
+
object: undefined,
|
|
136
164
|
}),
|
|
137
165
|
).toThrow('Record must have the property "object"')
|
|
138
166
|
})
|
|
@@ -140,130 +168,55 @@ describe('Record validation', () => {
|
|
|
140
168
|
it('Fails incorrect types', () => {
|
|
141
169
|
expect(() =>
|
|
142
170
|
lex.assertValidRecord('com.example.kitchenSink', {
|
|
143
|
-
|
|
171
|
+
...passingSink,
|
|
144
172
|
object: {
|
|
173
|
+
...passingSink.object,
|
|
145
174
|
object: { boolean: '1234' },
|
|
146
|
-
array: ['one', 'two'],
|
|
147
|
-
boolean: true,
|
|
148
|
-
number: 123.45,
|
|
149
|
-
integer: 123,
|
|
150
|
-
string: 'string',
|
|
151
175
|
},
|
|
152
|
-
array: ['one', 'two'],
|
|
153
|
-
boolean: true,
|
|
154
|
-
number: 123.45,
|
|
155
|
-
integer: 123,
|
|
156
|
-
string: 'string',
|
|
157
|
-
datetime: new Date().toISOString(),
|
|
158
176
|
}),
|
|
159
177
|
).toThrow('Record/object/object/boolean must be a boolean')
|
|
160
178
|
expect(() =>
|
|
161
179
|
lex.assertValidRecord('com.example.kitchenSink', {
|
|
162
|
-
|
|
180
|
+
...passingSink,
|
|
163
181
|
object: true,
|
|
164
|
-
array: ['one', 'two'],
|
|
165
|
-
boolean: true,
|
|
166
|
-
number: 123.45,
|
|
167
|
-
integer: 123,
|
|
168
|
-
string: 'string',
|
|
169
|
-
datetime: new Date().toISOString(),
|
|
170
182
|
}),
|
|
171
183
|
).toThrow('Record/object must be an object')
|
|
172
184
|
expect(() =>
|
|
173
185
|
lex.assertValidRecord('com.example.kitchenSink', {
|
|
174
|
-
|
|
175
|
-
object: {
|
|
176
|
-
object: { boolean: true },
|
|
177
|
-
array: ['one', 'two'],
|
|
178
|
-
boolean: true,
|
|
179
|
-
number: 123.45,
|
|
180
|
-
integer: 123,
|
|
181
|
-
string: 'string',
|
|
182
|
-
},
|
|
186
|
+
...passingSink,
|
|
183
187
|
array: 1234,
|
|
184
|
-
boolean: true,
|
|
185
|
-
number: 123.45,
|
|
186
|
-
integer: 123,
|
|
187
|
-
string: 'string',
|
|
188
|
-
datetime: new Date().toISOString(),
|
|
189
188
|
}),
|
|
190
189
|
).toThrow('Record/array must be an array')
|
|
191
190
|
expect(() =>
|
|
192
191
|
lex.assertValidRecord('com.example.kitchenSink', {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
object: { boolean: true },
|
|
196
|
-
array: ['one', 'two'],
|
|
197
|
-
boolean: true,
|
|
198
|
-
number: 123.45,
|
|
199
|
-
integer: 123,
|
|
200
|
-
string: 'string',
|
|
201
|
-
},
|
|
202
|
-
array: ['one', 'two'],
|
|
203
|
-
boolean: true,
|
|
204
|
-
number: 'string',
|
|
205
|
-
integer: 123,
|
|
206
|
-
string: 'string',
|
|
207
|
-
datetime: new Date().toISOString(),
|
|
192
|
+
...passingSink,
|
|
193
|
+
float: 'string',
|
|
208
194
|
}),
|
|
209
|
-
).toThrow('Record/
|
|
195
|
+
).toThrow('Record/float must be a number')
|
|
210
196
|
expect(() =>
|
|
211
197
|
lex.assertValidRecord('com.example.kitchenSink', {
|
|
212
|
-
|
|
213
|
-
object: {
|
|
214
|
-
object: { boolean: true },
|
|
215
|
-
array: ['one', 'two'],
|
|
216
|
-
boolean: true,
|
|
217
|
-
number: 123.45,
|
|
218
|
-
integer: 123,
|
|
219
|
-
string: 'string',
|
|
220
|
-
},
|
|
221
|
-
array: ['one', 'two'],
|
|
222
|
-
boolean: true,
|
|
223
|
-
number: 123.45,
|
|
198
|
+
...passingSink,
|
|
224
199
|
integer: true,
|
|
225
|
-
string: 'string',
|
|
226
|
-
datetime: new Date().toISOString(),
|
|
227
200
|
}),
|
|
228
201
|
).toThrow('Record/integer must be a number')
|
|
229
202
|
expect(() =>
|
|
230
203
|
lex.assertValidRecord('com.example.kitchenSink', {
|
|
231
|
-
|
|
232
|
-
object: {
|
|
233
|
-
object: { boolean: true },
|
|
234
|
-
array: ['one', 'two'],
|
|
235
|
-
boolean: true,
|
|
236
|
-
number: 123.45,
|
|
237
|
-
integer: 123,
|
|
238
|
-
string: 'string',
|
|
239
|
-
},
|
|
240
|
-
array: ['one', 'two'],
|
|
241
|
-
boolean: true,
|
|
242
|
-
number: 123.45,
|
|
243
|
-
integer: 123,
|
|
204
|
+
...passingSink,
|
|
244
205
|
string: {},
|
|
245
|
-
datetime: new Date().toISOString(),
|
|
246
206
|
}),
|
|
247
207
|
).toThrow('Record/string must be a string')
|
|
248
208
|
expect(() =>
|
|
249
209
|
lex.assertValidRecord('com.example.kitchenSink', {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
},
|
|
259
|
-
array: ['one', 'two'],
|
|
260
|
-
boolean: true,
|
|
261
|
-
number: 123.45,
|
|
262
|
-
integer: 123,
|
|
263
|
-
string: 'string',
|
|
264
|
-
datetime: 1234,
|
|
210
|
+
...passingSink,
|
|
211
|
+
bytes: 1234,
|
|
212
|
+
}),
|
|
213
|
+
).toThrow('Record/bytes must be a byte array')
|
|
214
|
+
expect(() =>
|
|
215
|
+
lex.assertValidRecord('com.example.kitchenSink', {
|
|
216
|
+
...passingSink,
|
|
217
|
+
cidLink: 'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a',
|
|
265
218
|
}),
|
|
266
|
-
).toThrow('Record/
|
|
219
|
+
).toThrow('Record/cidLink must be a CID')
|
|
267
220
|
})
|
|
268
221
|
|
|
269
222
|
it('Handles optional properties correctly', () => {
|
|
@@ -272,6 +225,27 @@ describe('Record validation', () => {
|
|
|
272
225
|
})
|
|
273
226
|
})
|
|
274
227
|
|
|
228
|
+
it('Handles default properties correctly', () => {
|
|
229
|
+
const result = lex.assertValidRecord('com.example.default', {
|
|
230
|
+
$type: 'com.example.default',
|
|
231
|
+
object: {},
|
|
232
|
+
})
|
|
233
|
+
expect(result).toEqual({
|
|
234
|
+
$type: 'com.example.default',
|
|
235
|
+
boolean: false,
|
|
236
|
+
integer: 0,
|
|
237
|
+
float: 0,
|
|
238
|
+
string: '',
|
|
239
|
+
object: {
|
|
240
|
+
boolean: true,
|
|
241
|
+
integer: 1,
|
|
242
|
+
float: 1.5,
|
|
243
|
+
string: 'x',
|
|
244
|
+
},
|
|
245
|
+
})
|
|
246
|
+
expect(result).not.toHaveProperty('datetime')
|
|
247
|
+
})
|
|
248
|
+
|
|
275
249
|
it('Handles unions correctly', () => {
|
|
276
250
|
lex.assertValidRecord('com.example.union', {
|
|
277
251
|
$type: 'com.example.union',
|
|
@@ -280,7 +254,7 @@ describe('Record validation', () => {
|
|
|
280
254
|
object: { boolean: true },
|
|
281
255
|
array: ['one', 'two'],
|
|
282
256
|
boolean: true,
|
|
283
|
-
|
|
257
|
+
float: 123.45,
|
|
284
258
|
integer: 123,
|
|
285
259
|
string: 'string',
|
|
286
260
|
},
|
|
@@ -355,6 +329,21 @@ describe('Record validation', () => {
|
|
|
355
329
|
).toThrow('Record/array must not have more than 4 elements')
|
|
356
330
|
})
|
|
357
331
|
|
|
332
|
+
it('Applies array item constraints', () => {
|
|
333
|
+
expect(() =>
|
|
334
|
+
lex.assertValidRecord('com.example.arrayLength', {
|
|
335
|
+
$type: 'com.example.arrayLength',
|
|
336
|
+
array: [1, '2', 3],
|
|
337
|
+
}),
|
|
338
|
+
).toThrow('Record/array/1 must be a number')
|
|
339
|
+
expect(() =>
|
|
340
|
+
lex.assertValidRecord('com.example.arrayLength', {
|
|
341
|
+
$type: 'com.example.arrayLength',
|
|
342
|
+
array: [1, undefined, 3],
|
|
343
|
+
}),
|
|
344
|
+
).toThrow('Record/array/1 must be a number')
|
|
345
|
+
})
|
|
346
|
+
|
|
358
347
|
it('Applies boolean const constraint', () => {
|
|
359
348
|
lex.assertValidRecord('com.example.boolConst', {
|
|
360
349
|
$type: 'com.example.boolConst',
|
|
@@ -368,49 +357,49 @@ describe('Record validation', () => {
|
|
|
368
357
|
).toThrow('Record/boolean must be false')
|
|
369
358
|
})
|
|
370
359
|
|
|
371
|
-
it('Applies
|
|
372
|
-
lex.assertValidRecord('com.example.
|
|
373
|
-
$type: 'com.example.
|
|
374
|
-
|
|
360
|
+
it('Applies float range constraint', () => {
|
|
361
|
+
lex.assertValidRecord('com.example.floatRange', {
|
|
362
|
+
$type: 'com.example.floatRange',
|
|
363
|
+
float: 2.5,
|
|
375
364
|
})
|
|
376
365
|
expect(() =>
|
|
377
|
-
lex.assertValidRecord('com.example.
|
|
378
|
-
$type: 'com.example.
|
|
379
|
-
|
|
366
|
+
lex.assertValidRecord('com.example.floatRange', {
|
|
367
|
+
$type: 'com.example.floatRange',
|
|
368
|
+
float: 1,
|
|
380
369
|
}),
|
|
381
|
-
).toThrow('Record/
|
|
370
|
+
).toThrow('Record/float can not be less than 2')
|
|
382
371
|
expect(() =>
|
|
383
|
-
lex.assertValidRecord('com.example.
|
|
384
|
-
$type: 'com.example.
|
|
385
|
-
|
|
372
|
+
lex.assertValidRecord('com.example.floatRange', {
|
|
373
|
+
$type: 'com.example.floatRange',
|
|
374
|
+
float: 5,
|
|
386
375
|
}),
|
|
387
|
-
).toThrow('Record/
|
|
376
|
+
).toThrow('Record/float can not be greater than 4')
|
|
388
377
|
})
|
|
389
378
|
|
|
390
|
-
it('Applies
|
|
391
|
-
lex.assertValidRecord('com.example.
|
|
392
|
-
$type: 'com.example.
|
|
393
|
-
|
|
379
|
+
it('Applies float enum constraint', () => {
|
|
380
|
+
lex.assertValidRecord('com.example.floatEnum', {
|
|
381
|
+
$type: 'com.example.floatEnum',
|
|
382
|
+
float: 1.5,
|
|
394
383
|
})
|
|
395
384
|
expect(() =>
|
|
396
|
-
lex.assertValidRecord('com.example.
|
|
397
|
-
$type: 'com.example.
|
|
398
|
-
|
|
385
|
+
lex.assertValidRecord('com.example.floatEnum', {
|
|
386
|
+
$type: 'com.example.floatEnum',
|
|
387
|
+
float: 0,
|
|
399
388
|
}),
|
|
400
|
-
).toThrow('Record/
|
|
389
|
+
).toThrow('Record/float must be one of (1|1.5|2)')
|
|
401
390
|
})
|
|
402
391
|
|
|
403
|
-
it('Applies
|
|
404
|
-
lex.assertValidRecord('com.example.
|
|
405
|
-
$type: 'com.example.
|
|
406
|
-
|
|
392
|
+
it('Applies float const constraint', () => {
|
|
393
|
+
lex.assertValidRecord('com.example.floatConst', {
|
|
394
|
+
$type: 'com.example.floatConst',
|
|
395
|
+
float: 0,
|
|
407
396
|
})
|
|
408
397
|
expect(() =>
|
|
409
|
-
lex.assertValidRecord('com.example.
|
|
410
|
-
$type: 'com.example.
|
|
411
|
-
|
|
398
|
+
lex.assertValidRecord('com.example.floatConst', {
|
|
399
|
+
$type: 'com.example.floatConst',
|
|
400
|
+
float: 1,
|
|
412
401
|
}),
|
|
413
|
-
).toThrow('Record/
|
|
402
|
+
).toThrow('Record/float must be 0')
|
|
414
403
|
})
|
|
415
404
|
|
|
416
405
|
it('Applies integer range constraint', () => {
|
|
@@ -484,6 +473,31 @@ describe('Record validation', () => {
|
|
|
484
473
|
string: '12345',
|
|
485
474
|
}),
|
|
486
475
|
).toThrow('Record/string must not be longer than 4 characters')
|
|
476
|
+
expect(() =>
|
|
477
|
+
lex.assertValidRecord('com.example.stringLength', {
|
|
478
|
+
$type: 'com.example.stringLength',
|
|
479
|
+
string: '👨👩👧👧',
|
|
480
|
+
}),
|
|
481
|
+
).toThrow('Record/string must not be longer than 4 characters')
|
|
482
|
+
})
|
|
483
|
+
|
|
484
|
+
it('Applies grapheme string length constraint', () => {
|
|
485
|
+
lex.assertValidRecord('com.example.stringLengthGrapheme', {
|
|
486
|
+
$type: 'com.example.stringLengthGrapheme',
|
|
487
|
+
string: '12👨👩👧👧',
|
|
488
|
+
})
|
|
489
|
+
expect(() =>
|
|
490
|
+
lex.assertValidRecord('com.example.stringLengthGrapheme', {
|
|
491
|
+
$type: 'com.example.stringLengthGrapheme',
|
|
492
|
+
string: '👨👩👧👧',
|
|
493
|
+
}),
|
|
494
|
+
).toThrow('Record/string must not be shorter than 2 graphemes')
|
|
495
|
+
expect(() =>
|
|
496
|
+
lex.assertValidRecord('com.example.stringLengthGrapheme', {
|
|
497
|
+
$type: 'com.example.stringLengthGrapheme',
|
|
498
|
+
string: '12345',
|
|
499
|
+
}),
|
|
500
|
+
).toThrow('Record/string must not be longer than 4 graphemes')
|
|
487
501
|
})
|
|
488
502
|
|
|
489
503
|
it('Applies string enum constraint', () => {
|
|
@@ -537,36 +551,224 @@ describe('Record validation', () => {
|
|
|
537
551
|
}),
|
|
538
552
|
).toThrow('Record/datetime must be an iso8601 formatted datetime')
|
|
539
553
|
})
|
|
554
|
+
|
|
555
|
+
it('Applies uri formatting constraint', () => {
|
|
556
|
+
for (const uri of [
|
|
557
|
+
'https://example.com',
|
|
558
|
+
'https://example.com/with/path',
|
|
559
|
+
'https://example.com/with/path?and=query',
|
|
560
|
+
'at://bsky.social',
|
|
561
|
+
'did:example:test',
|
|
562
|
+
]) {
|
|
563
|
+
lex.assertValidRecord('com.example.uri', {
|
|
564
|
+
$type: 'com.example.uri',
|
|
565
|
+
uri,
|
|
566
|
+
})
|
|
567
|
+
}
|
|
568
|
+
expect(() =>
|
|
569
|
+
lex.assertValidRecord('com.example.uri', {
|
|
570
|
+
$type: 'com.example.uri',
|
|
571
|
+
uri: 'not a uri',
|
|
572
|
+
}),
|
|
573
|
+
).toThrow('Record/uri must be a uri')
|
|
574
|
+
})
|
|
575
|
+
|
|
576
|
+
it('Applies at-uri formatting constraint', () => {
|
|
577
|
+
lex.assertValidRecord('com.example.atUri', {
|
|
578
|
+
$type: 'com.example.atUri',
|
|
579
|
+
atUri: 'at://did:web:example.com/com.example.test/self',
|
|
580
|
+
})
|
|
581
|
+
expect(() =>
|
|
582
|
+
lex.assertValidRecord('com.example.atUri', {
|
|
583
|
+
$type: 'com.example.atUri',
|
|
584
|
+
atUri: 'http://not-atproto.com',
|
|
585
|
+
}),
|
|
586
|
+
).toThrow('Record/atUri must be a valid at-uri')
|
|
587
|
+
})
|
|
588
|
+
|
|
589
|
+
it('Applies did formatting constraint', () => {
|
|
590
|
+
lex.assertValidRecord('com.example.did', {
|
|
591
|
+
$type: 'com.example.did',
|
|
592
|
+
did: 'did:web:example.com',
|
|
593
|
+
})
|
|
594
|
+
lex.assertValidRecord('com.example.did', {
|
|
595
|
+
$type: 'com.example.did',
|
|
596
|
+
did: 'did:plc:12345678abcdefghijklmnop',
|
|
597
|
+
})
|
|
598
|
+
|
|
599
|
+
expect(() =>
|
|
600
|
+
lex.assertValidRecord('com.example.did', {
|
|
601
|
+
$type: 'com.example.did',
|
|
602
|
+
did: 'bad did',
|
|
603
|
+
}),
|
|
604
|
+
).toThrow('Record/did must be a valid did')
|
|
605
|
+
expect(() =>
|
|
606
|
+
lex.assertValidRecord('com.example.did', {
|
|
607
|
+
$type: 'com.example.did',
|
|
608
|
+
did: 'did:short',
|
|
609
|
+
}),
|
|
610
|
+
).toThrow('Record/did must be a valid did')
|
|
611
|
+
})
|
|
612
|
+
|
|
613
|
+
it('Applies handle formatting constraint', () => {
|
|
614
|
+
lex.assertValidRecord('com.example.handle', {
|
|
615
|
+
$type: 'com.example.handle',
|
|
616
|
+
handle: 'test.bsky.social',
|
|
617
|
+
})
|
|
618
|
+
lex.assertValidRecord('com.example.handle', {
|
|
619
|
+
$type: 'com.example.handle',
|
|
620
|
+
handle: 'bsky.test',
|
|
621
|
+
})
|
|
622
|
+
|
|
623
|
+
expect(() =>
|
|
624
|
+
lex.assertValidRecord('com.example.handle', {
|
|
625
|
+
$type: 'com.example.handle',
|
|
626
|
+
handle: 'bad handle',
|
|
627
|
+
}),
|
|
628
|
+
).toThrow('Record/handle must be a valid handle')
|
|
629
|
+
expect(() =>
|
|
630
|
+
lex.assertValidRecord('com.example.handle', {
|
|
631
|
+
$type: 'com.example.handle',
|
|
632
|
+
handle: '-bad-.test',
|
|
633
|
+
}),
|
|
634
|
+
).toThrow('Record/handle must be a valid handle')
|
|
635
|
+
})
|
|
636
|
+
|
|
637
|
+
it('Applies at-identifier formatting constraint', () => {
|
|
638
|
+
lex.assertValidRecord('com.example.atIdentifier', {
|
|
639
|
+
$type: 'com.example.atIdentifier',
|
|
640
|
+
atIdentifier: 'bsky.test',
|
|
641
|
+
})
|
|
642
|
+
lex.assertValidRecord('com.example.atIdentifier', {
|
|
643
|
+
$type: 'com.example.atIdentifier',
|
|
644
|
+
atIdentifier: 'did:plc:12345678abcdefghijklmnop',
|
|
645
|
+
})
|
|
646
|
+
|
|
647
|
+
expect(() =>
|
|
648
|
+
lex.assertValidRecord('com.example.atIdentifier', {
|
|
649
|
+
$type: 'com.example.atIdentifier',
|
|
650
|
+
atIdentifier: 'bad id',
|
|
651
|
+
}),
|
|
652
|
+
).toThrow('Record/atIdentifier must be a valid did or a handle')
|
|
653
|
+
expect(() =>
|
|
654
|
+
lex.assertValidRecord('com.example.atIdentifier', {
|
|
655
|
+
$type: 'com.example.atIdentifier',
|
|
656
|
+
atIdentifier: '-bad-.test',
|
|
657
|
+
}),
|
|
658
|
+
).toThrow('Record/atIdentifier must be a valid did or a handle')
|
|
659
|
+
})
|
|
660
|
+
|
|
661
|
+
it('Applies nsid formatting constraint', () => {
|
|
662
|
+
lex.assertValidRecord('com.example.nsid', {
|
|
663
|
+
$type: 'com.example.nsid',
|
|
664
|
+
nsid: 'com.atproto.test',
|
|
665
|
+
})
|
|
666
|
+
lex.assertValidRecord('com.example.nsid', {
|
|
667
|
+
$type: 'com.example.nsid',
|
|
668
|
+
nsid: 'app.bsky.nested.test',
|
|
669
|
+
})
|
|
670
|
+
|
|
671
|
+
expect(() =>
|
|
672
|
+
lex.assertValidRecord('com.example.nsid', {
|
|
673
|
+
$type: 'com.example.nsid',
|
|
674
|
+
nsid: 'bad nsid',
|
|
675
|
+
}),
|
|
676
|
+
).toThrow('Record/nsid must be a valid nsid')
|
|
677
|
+
expect(() =>
|
|
678
|
+
lex.assertValidRecord('com.example.nsid', {
|
|
679
|
+
$type: 'com.example.nsid',
|
|
680
|
+
nsid: 'com.bad-.foo',
|
|
681
|
+
}),
|
|
682
|
+
).toThrow('Record/nsid must be a valid nsid')
|
|
683
|
+
})
|
|
684
|
+
|
|
685
|
+
it('Applies cid formatting constraint', () => {
|
|
686
|
+
lex.assertValidRecord('com.example.cid', {
|
|
687
|
+
$type: 'com.example.cid',
|
|
688
|
+
cid: 'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a',
|
|
689
|
+
})
|
|
690
|
+
expect(() =>
|
|
691
|
+
lex.assertValidRecord('com.example.cid', {
|
|
692
|
+
$type: 'com.example.cid',
|
|
693
|
+
cid: 'abapsdofiuwrpoiasdfuaspdfoiu',
|
|
694
|
+
}),
|
|
695
|
+
).toThrow('Record/cid must be a cid string')
|
|
696
|
+
})
|
|
697
|
+
|
|
698
|
+
it('Applies bytes length constraints', () => {
|
|
699
|
+
lex.assertValidRecord('com.example.byteLength', {
|
|
700
|
+
$type: 'com.example.byteLength',
|
|
701
|
+
bytes: new Uint8Array([1, 2, 3]),
|
|
702
|
+
})
|
|
703
|
+
expect(() =>
|
|
704
|
+
lex.assertValidRecord('com.example.byteLength', {
|
|
705
|
+
$type: 'com.example.byteLength',
|
|
706
|
+
bytes: new Uint8Array([1]),
|
|
707
|
+
}),
|
|
708
|
+
).toThrow('Record/bytes must not be smaller than 2 bytes')
|
|
709
|
+
expect(() =>
|
|
710
|
+
lex.assertValidRecord('com.example.byteLength', {
|
|
711
|
+
$type: 'com.example.byteLength',
|
|
712
|
+
bytes: new Uint8Array([1, 2, 3, 4, 5]),
|
|
713
|
+
}),
|
|
714
|
+
).toThrow('Record/bytes must not be larger than 4 bytes')
|
|
715
|
+
})
|
|
540
716
|
})
|
|
541
717
|
|
|
542
718
|
describe('XRPC parameter validation', () => {
|
|
543
719
|
const lex = new Lexicons(LexiconDocs)
|
|
544
720
|
|
|
545
721
|
it('Passes valid parameters', () => {
|
|
546
|
-
lex.assertValidXrpcParams('com.example.query', {
|
|
722
|
+
const queryResult = lex.assertValidXrpcParams('com.example.query', {
|
|
723
|
+
boolean: true,
|
|
724
|
+
float: 123.45,
|
|
725
|
+
integer: 123,
|
|
726
|
+
string: 'string',
|
|
727
|
+
array: ['x', 'y'],
|
|
728
|
+
})
|
|
729
|
+
expect(queryResult).toEqual({
|
|
730
|
+
boolean: true,
|
|
731
|
+
float: 123.45,
|
|
732
|
+
integer: 123,
|
|
733
|
+
string: 'string',
|
|
734
|
+
array: ['x', 'y'],
|
|
735
|
+
def: 0,
|
|
736
|
+
})
|
|
737
|
+
const paramResult = lex.assertValidXrpcParams('com.example.procedure', {
|
|
547
738
|
boolean: true,
|
|
548
|
-
|
|
739
|
+
float: 123.45,
|
|
549
740
|
integer: 123,
|
|
550
741
|
string: 'string',
|
|
742
|
+
array: ['x', 'y'],
|
|
743
|
+
def: 1,
|
|
551
744
|
})
|
|
552
|
-
|
|
745
|
+
expect(paramResult).toEqual({
|
|
553
746
|
boolean: true,
|
|
554
|
-
|
|
747
|
+
float: 123.45,
|
|
555
748
|
integer: 123,
|
|
556
749
|
string: 'string',
|
|
750
|
+
array: ['x', 'y'],
|
|
751
|
+
def: 1,
|
|
557
752
|
})
|
|
558
753
|
})
|
|
559
754
|
|
|
560
755
|
it('Handles required correctly', () => {
|
|
561
756
|
lex.assertValidXrpcParams('com.example.query', {
|
|
562
757
|
boolean: true,
|
|
563
|
-
|
|
758
|
+
float: 123.45,
|
|
564
759
|
integer: 123,
|
|
565
760
|
})
|
|
566
761
|
expect(() =>
|
|
567
762
|
lex.assertValidXrpcParams('com.example.query', {
|
|
568
763
|
boolean: true,
|
|
569
|
-
|
|
764
|
+
float: 123.45,
|
|
765
|
+
}),
|
|
766
|
+
).toThrow('Params must have the property "integer"')
|
|
767
|
+
expect(() =>
|
|
768
|
+
lex.assertValidXrpcParams('com.example.query', {
|
|
769
|
+
boolean: true,
|
|
770
|
+
float: 123.45,
|
|
771
|
+
integer: undefined,
|
|
570
772
|
}),
|
|
571
773
|
).toThrow('Params must have the property "integer"')
|
|
572
774
|
})
|
|
@@ -575,7 +777,7 @@ describe('XRPC parameter validation', () => {
|
|
|
575
777
|
expect(() =>
|
|
576
778
|
lex.assertValidXrpcParams('com.example.query', {
|
|
577
779
|
boolean: 'string',
|
|
578
|
-
|
|
780
|
+
float: 123.45,
|
|
579
781
|
integer: 123,
|
|
580
782
|
string: 'string',
|
|
581
783
|
}),
|
|
@@ -583,11 +785,20 @@ describe('XRPC parameter validation', () => {
|
|
|
583
785
|
expect(() =>
|
|
584
786
|
lex.assertValidXrpcParams('com.example.procedure', {
|
|
585
787
|
boolean: true,
|
|
586
|
-
|
|
788
|
+
float: true,
|
|
789
|
+
integer: 123,
|
|
790
|
+
string: 'string',
|
|
791
|
+
}),
|
|
792
|
+
).toThrow('float must be a number')
|
|
793
|
+
expect(() =>
|
|
794
|
+
lex.assertValidXrpcParams('com.example.query', {
|
|
795
|
+
boolean: true,
|
|
796
|
+
float: 123.45,
|
|
587
797
|
integer: 123,
|
|
588
798
|
string: 'string',
|
|
799
|
+
array: 'x',
|
|
589
800
|
}),
|
|
590
|
-
).toThrow('
|
|
801
|
+
).toThrow('array must be an array')
|
|
591
802
|
})
|
|
592
803
|
})
|
|
593
804
|
|
|
@@ -599,7 +810,7 @@ describe('XRPC input validation', () => {
|
|
|
599
810
|
object: { boolean: true },
|
|
600
811
|
array: ['one', 'two'],
|
|
601
812
|
boolean: true,
|
|
602
|
-
|
|
813
|
+
float: 123.45,
|
|
603
814
|
integer: 123,
|
|
604
815
|
string: 'string',
|
|
605
816
|
})
|
|
@@ -612,7 +823,7 @@ describe('XRPC input validation', () => {
|
|
|
612
823
|
object: { boolean: 'string' },
|
|
613
824
|
array: ['one', 'two'],
|
|
614
825
|
boolean: true,
|
|
615
|
-
|
|
826
|
+
float: 123.45,
|
|
616
827
|
integer: 123,
|
|
617
828
|
string: 'string',
|
|
618
829
|
}),
|
|
@@ -631,7 +842,7 @@ describe('XRPC output validation', () => {
|
|
|
631
842
|
object: { boolean: true },
|
|
632
843
|
array: ['one', 'two'],
|
|
633
844
|
boolean: true,
|
|
634
|
-
|
|
845
|
+
float: 123.45,
|
|
635
846
|
integer: 123,
|
|
636
847
|
string: 'string',
|
|
637
848
|
})
|
|
@@ -639,7 +850,7 @@ describe('XRPC output validation', () => {
|
|
|
639
850
|
object: { boolean: true },
|
|
640
851
|
array: ['one', 'two'],
|
|
641
852
|
boolean: true,
|
|
642
|
-
|
|
853
|
+
float: 123.45,
|
|
643
854
|
integer: 123,
|
|
644
855
|
string: 'string',
|
|
645
856
|
})
|
|
@@ -652,7 +863,7 @@ describe('XRPC output validation', () => {
|
|
|
652
863
|
object: { boolean: 'string' },
|
|
653
864
|
array: ['one', 'two'],
|
|
654
865
|
boolean: true,
|
|
655
|
-
|
|
866
|
+
float: 123.45,
|
|
656
867
|
integer: 123,
|
|
657
868
|
string: 'string',
|
|
658
869
|
}),
|