@atproto/lexicon 0.0.3 → 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/dist/util.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ import { Lexicons } from './lexicons';
|
|
|
2
2
|
import { LexUserType, LexRefVariant, ValidationResult } from './types';
|
|
3
3
|
export declare function toLexUri(str: string, baseUri?: string): string;
|
|
4
4
|
export declare function validateOneOf(lexicons: Lexicons, path: string, def: LexRefVariant | LexUserType, value: unknown, mustBeObj?: boolean): ValidationResult;
|
|
5
|
-
export declare function assertValidOneOf(lexicons: Lexicons, path: string, def: LexRefVariant | LexUserType, value: unknown, mustBeObj?: boolean):
|
|
5
|
+
export declare function assertValidOneOf(lexicons: Lexicons, path: string, def: LexRefVariant | LexUserType, value: unknown, mustBeObj?: boolean): unknown;
|
|
6
6
|
export declare function toConcreteTypes(lexicons: Lexicons, def: LexRefVariant | LexUserType): LexUserType[];
|
package/dist/validation.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Lexicons } from './lexicons';
|
|
2
|
-
import { LexRecord, LexXrpcProcedure, LexXrpcQuery } from './types';
|
|
3
|
-
export declare function assertValidRecord(lexicons: Lexicons, def: LexRecord, value: unknown):
|
|
4
|
-
export declare function assertValidXrpcParams(lexicons: Lexicons, def: LexXrpcProcedure | LexXrpcQuery, value: unknown):
|
|
5
|
-
export declare function assertValidXrpcInput(lexicons: Lexicons, def: LexXrpcProcedure, value: unknown):
|
|
6
|
-
export declare function assertValidXrpcOutput(lexicons: Lexicons, def: LexXrpcProcedure | LexXrpcQuery, value: unknown):
|
|
2
|
+
import { LexRecord, LexXrpcProcedure, LexXrpcQuery, LexXrpcSubscription } from './types';
|
|
3
|
+
export declare function assertValidRecord(lexicons: Lexicons, def: LexRecord, value: unknown): unknown;
|
|
4
|
+
export declare function assertValidXrpcParams(lexicons: Lexicons, def: LexXrpcProcedure | LexXrpcQuery | LexXrpcSubscription, value: unknown): unknown;
|
|
5
|
+
export declare function assertValidXrpcInput(lexicons: Lexicons, def: LexXrpcProcedure, value: unknown): unknown;
|
|
6
|
+
export declare function assertValidXrpcOutput(lexicons: Lexicons, def: LexXrpcProcedure | LexXrpcQuery, value: unknown): unknown;
|
|
7
|
+
export declare function assertValidXrpcMessage(lexicons: Lexicons, def: LexXrpcSubscription, value: unknown): unknown;
|
|
@@ -1,6 +1,3 @@
|
|
|
1
1
|
import { Lexicons } from '../lexicons';
|
|
2
2
|
import { LexUserType, ValidationResult } from '../types';
|
|
3
3
|
export declare function blob(lexicons: Lexicons, path: string, def: LexUserType, value: unknown): ValidationResult;
|
|
4
|
-
export declare function image(lexicons: Lexicons, path: string, def: LexUserType, value: unknown): ValidationResult;
|
|
5
|
-
export declare function video(lexicons: Lexicons, path: string, def: LexUserType, value: unknown): ValidationResult;
|
|
6
|
-
export declare function audio(lexicons: Lexicons, path: string, def: LexUserType, value: unknown): ValidationResult;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Lexicons } from '../lexicons';
|
|
2
|
-
import { LexUserType, ValidationResult } from '../types';
|
|
2
|
+
import { LexArray, LexUserType, ValidationResult } from '../types';
|
|
3
3
|
export declare function validate(lexicons: Lexicons, path: string, def: LexUserType, value: unknown): ValidationResult;
|
|
4
|
-
export declare function array(lexicons: Lexicons, path: string, def:
|
|
4
|
+
export declare function array(lexicons: Lexicons, path: string, def: LexArray, value: unknown): ValidationResult;
|
|
5
5
|
export declare function object(lexicons: Lexicons, path: string, def: LexUserType, value: unknown): ValidationResult;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ValidationResult } from '../types';
|
|
2
|
+
export declare function datetime(path: string, value: string): ValidationResult;
|
|
3
|
+
export declare function uri(path: string, value: string): ValidationResult;
|
|
4
|
+
export declare function atUri(path: string, value: string): ValidationResult;
|
|
5
|
+
export declare function did(path: string, value: string): ValidationResult;
|
|
6
|
+
export declare function handle(path: string, value: string): ValidationResult;
|
|
7
|
+
export declare function atIdentifier(path: string, value: string): ValidationResult;
|
|
8
|
+
export declare function nsid(path: string, value: string): ValidationResult;
|
|
9
|
+
export declare function cid(path: string, value: string): ValidationResult;
|
|
@@ -2,8 +2,9 @@ import { Lexicons } from '../lexicons';
|
|
|
2
2
|
import { LexUserType, ValidationResult } from '../types';
|
|
3
3
|
export declare function validate(lexicons: Lexicons, path: string, def: LexUserType, value: unknown): ValidationResult;
|
|
4
4
|
export declare function boolean(lexicons: Lexicons, path: string, def: LexUserType, value: unknown): ValidationResult;
|
|
5
|
-
export declare function
|
|
5
|
+
export declare function float(lexicons: Lexicons, path: string, def: LexUserType, value: unknown): ValidationResult;
|
|
6
6
|
export declare function integer(lexicons: Lexicons, path: string, def: LexUserType, value: unknown): ValidationResult;
|
|
7
7
|
export declare function string(lexicons: Lexicons, path: string, def: LexUserType, value: unknown): ValidationResult;
|
|
8
|
-
export declare function
|
|
8
|
+
export declare function bytes(lexicons: Lexicons, path: string, def: LexUserType, value: unknown): ValidationResult;
|
|
9
|
+
export declare function cidLink(lexicons: Lexicons, path: string, def: LexUserType, value: unknown): ValidationResult;
|
|
9
10
|
export declare function unknown(lexicons: Lexicons, path: string, def: LexUserType, value: unknown): ValidationResult;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { Lexicons } from '../lexicons';
|
|
2
2
|
import { LexXrpcParameters, ValidationResult } from '../types';
|
|
3
|
-
export declare function params(lexicons: Lexicons, path: string, def: LexXrpcParameters,
|
|
3
|
+
export declare function params(lexicons: Lexicons, path: string, def: LexXrpcParameters, val: unknown): ValidationResult;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/lexicon",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "jest",
|
|
@@ -19,8 +19,12 @@
|
|
|
19
19
|
},
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
+
"@atproto/common-web": "*",
|
|
23
|
+
"@atproto/identifier": "*",
|
|
22
24
|
"@atproto/nsid": "*",
|
|
25
|
+
"@atproto/uri": "*",
|
|
23
26
|
"iso-datestring-validator": "^2.2.2",
|
|
27
|
+
"multiformats": "^9.6.4",
|
|
24
28
|
"zod": "^3.14.2"
|
|
25
29
|
}
|
|
26
30
|
}
|
package/src/blob-refs.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { check, ipldToJson, schema } from '@atproto/common-web'
|
|
2
|
+
import { CID } from 'multiformats/cid'
|
|
3
|
+
import { z } from 'zod'
|
|
4
|
+
|
|
5
|
+
export const typedJsonBlobRef = z
|
|
6
|
+
.object({
|
|
7
|
+
$type: z.literal('blob'),
|
|
8
|
+
ref: schema.cid,
|
|
9
|
+
mimeType: z.string(),
|
|
10
|
+
size: z.number(),
|
|
11
|
+
})
|
|
12
|
+
.strict()
|
|
13
|
+
export type TypedJsonBlobRef = z.infer<typeof typedJsonBlobRef>
|
|
14
|
+
|
|
15
|
+
export const untypedJsonBlobRef = z
|
|
16
|
+
.object({
|
|
17
|
+
cid: z.string(),
|
|
18
|
+
mimeType: z.string(),
|
|
19
|
+
})
|
|
20
|
+
.strict()
|
|
21
|
+
export type UntypedJsonBlobRef = z.infer<typeof untypedJsonBlobRef>
|
|
22
|
+
|
|
23
|
+
export const jsonBlobRef = z.union([typedJsonBlobRef, untypedJsonBlobRef])
|
|
24
|
+
export type JsonBlobRef = z.infer<typeof jsonBlobRef>
|
|
25
|
+
|
|
26
|
+
export class BlobRef {
|
|
27
|
+
public original: JsonBlobRef
|
|
28
|
+
|
|
29
|
+
constructor(
|
|
30
|
+
public ref: CID,
|
|
31
|
+
public mimeType: string,
|
|
32
|
+
public size: number,
|
|
33
|
+
original?: JsonBlobRef,
|
|
34
|
+
) {
|
|
35
|
+
this.original = original ?? {
|
|
36
|
+
$type: 'blob',
|
|
37
|
+
ref,
|
|
38
|
+
mimeType,
|
|
39
|
+
size,
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static asBlobRef(obj: unknown): BlobRef | null {
|
|
44
|
+
if (check.is(obj, jsonBlobRef)) {
|
|
45
|
+
return BlobRef.fromJsonRef(obj)
|
|
46
|
+
}
|
|
47
|
+
return null
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static fromJsonRef(json: JsonBlobRef): BlobRef {
|
|
51
|
+
if (check.is(json, typedJsonBlobRef)) {
|
|
52
|
+
return new BlobRef(json.ref, json.mimeType, json.size)
|
|
53
|
+
} else {
|
|
54
|
+
return new BlobRef(CID.parse(json.cid), json.mimeType, -1, json)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
ipld(): TypedJsonBlobRef {
|
|
59
|
+
return {
|
|
60
|
+
$type: 'blob',
|
|
61
|
+
ref: this.ref,
|
|
62
|
+
mimeType: this.mimeType,
|
|
63
|
+
size: this.size,
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
toJSON() {
|
|
68
|
+
return ipldToJson(this.ipld())
|
|
69
|
+
}
|
|
70
|
+
}
|
package/src/index.ts
CHANGED
package/src/lexicons.ts
CHANGED
|
@@ -13,12 +13,14 @@ import {
|
|
|
13
13
|
ValidationError,
|
|
14
14
|
isObj,
|
|
15
15
|
hasProp,
|
|
16
|
+
LexXrpcSubscription,
|
|
16
17
|
} from './types'
|
|
17
18
|
import {
|
|
18
19
|
assertValidRecord,
|
|
19
20
|
assertValidXrpcParams,
|
|
20
21
|
assertValidXrpcInput,
|
|
21
22
|
assertValidXrpcOutput,
|
|
23
|
+
assertValidXrpcMessage,
|
|
22
24
|
} from './validation'
|
|
23
25
|
import { toLexUri } from './util'
|
|
24
26
|
import * as ComplexValidators from './validators/complex'
|
|
@@ -158,7 +160,7 @@ export class Lexicons {
|
|
|
158
160
|
`Invalid $type: must be ${lexUri}, got ${$type}`,
|
|
159
161
|
)
|
|
160
162
|
}
|
|
161
|
-
assertValidRecord(this, def as LexRecord, value)
|
|
163
|
+
return assertValidRecord(this, def as LexRecord, value)
|
|
162
164
|
}
|
|
163
165
|
|
|
164
166
|
/**
|
|
@@ -166,8 +168,16 @@ export class Lexicons {
|
|
|
166
168
|
*/
|
|
167
169
|
assertValidXrpcParams(lexUri: string, value: unknown) {
|
|
168
170
|
lexUri = toLexUri(lexUri)
|
|
169
|
-
const def = this.getDefOrThrow(lexUri, [
|
|
170
|
-
|
|
171
|
+
const def = this.getDefOrThrow(lexUri, [
|
|
172
|
+
'query',
|
|
173
|
+
'procedure',
|
|
174
|
+
'subscription',
|
|
175
|
+
])
|
|
176
|
+
return assertValidXrpcParams(
|
|
177
|
+
this,
|
|
178
|
+
def as LexXrpcProcedure | LexXrpcQuery | LexXrpcSubscription,
|
|
179
|
+
value,
|
|
180
|
+
)
|
|
171
181
|
}
|
|
172
182
|
|
|
173
183
|
/**
|
|
@@ -176,7 +186,7 @@ export class Lexicons {
|
|
|
176
186
|
assertValidXrpcInput(lexUri: string, value: unknown) {
|
|
177
187
|
lexUri = toLexUri(lexUri)
|
|
178
188
|
const def = this.getDefOrThrow(lexUri, ['procedure'])
|
|
179
|
-
assertValidXrpcInput(this, def as LexXrpcProcedure, value)
|
|
189
|
+
return assertValidXrpcInput(this, def as LexXrpcProcedure, value)
|
|
180
190
|
}
|
|
181
191
|
|
|
182
192
|
/**
|
|
@@ -185,7 +195,28 @@ export class Lexicons {
|
|
|
185
195
|
assertValidXrpcOutput(lexUri: string, value: unknown) {
|
|
186
196
|
lexUri = toLexUri(lexUri)
|
|
187
197
|
const def = this.getDefOrThrow(lexUri, ['query', 'procedure'])
|
|
188
|
-
assertValidXrpcOutput(
|
|
198
|
+
return assertValidXrpcOutput(
|
|
199
|
+
this,
|
|
200
|
+
def as LexXrpcProcedure | LexXrpcQuery,
|
|
201
|
+
value,
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Validate xrpc subscription message and throw on any error.
|
|
207
|
+
*/
|
|
208
|
+
assertValidXrpcMessage<T = unknown>(lexUri: string, value: unknown): T {
|
|
209
|
+
lexUri = toLexUri(lexUri)
|
|
210
|
+
const def = this.getDefOrThrow(lexUri, ['subscription'])
|
|
211
|
+
return assertValidXrpcMessage(this, def as LexXrpcSubscription, value) as T
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Resolve a lex uri given a ref
|
|
216
|
+
*/
|
|
217
|
+
resolveLexUri(lexUri: string, ref: string) {
|
|
218
|
+
lexUri = toLexUri(lexUri)
|
|
219
|
+
return toLexUri(ref, lexUri)
|
|
189
220
|
}
|
|
190
221
|
}
|
|
191
222
|
|
package/src/serialize.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {
|
|
2
|
+
check,
|
|
3
|
+
IpldValue,
|
|
4
|
+
ipldToJson,
|
|
5
|
+
jsonToIpld,
|
|
6
|
+
JsonValue,
|
|
7
|
+
} from '@atproto/common-web'
|
|
8
|
+
import { CID } from 'multiformats/cid'
|
|
9
|
+
import { BlobRef, jsonBlobRef } from './blob-refs'
|
|
10
|
+
|
|
11
|
+
export type LexValue =
|
|
12
|
+
| IpldValue
|
|
13
|
+
| BlobRef
|
|
14
|
+
| Array<LexValue>
|
|
15
|
+
| { [key: string]: LexValue }
|
|
16
|
+
|
|
17
|
+
export type RepoRecord = Record<string, LexValue>
|
|
18
|
+
|
|
19
|
+
// @NOTE avoiding use of check.is() here only because it makes
|
|
20
|
+
// these implementations slow, and they often live in hot paths.
|
|
21
|
+
|
|
22
|
+
export const lexToIpld = (val: LexValue): IpldValue => {
|
|
23
|
+
// walk arrays
|
|
24
|
+
if (Array.isArray(val)) {
|
|
25
|
+
return val.map((item) => lexToIpld(item))
|
|
26
|
+
}
|
|
27
|
+
// objects
|
|
28
|
+
if (val && typeof val === 'object') {
|
|
29
|
+
// convert blobs, leaving the original encoding so that we don't change CIDs on re-encode
|
|
30
|
+
if (val instanceof BlobRef) {
|
|
31
|
+
return val.original
|
|
32
|
+
}
|
|
33
|
+
// retain cids & bytes
|
|
34
|
+
if (CID.asCID(val) || val instanceof Uint8Array) {
|
|
35
|
+
return val
|
|
36
|
+
}
|
|
37
|
+
// walk plain objects
|
|
38
|
+
const toReturn = {}
|
|
39
|
+
for (const key of Object.keys(val)) {
|
|
40
|
+
toReturn[key] = lexToIpld(val[key])
|
|
41
|
+
}
|
|
42
|
+
return toReturn
|
|
43
|
+
}
|
|
44
|
+
// pass through
|
|
45
|
+
return val
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const ipldToLex = (val: IpldValue): LexValue => {
|
|
49
|
+
// map arrays
|
|
50
|
+
if (Array.isArray(val)) {
|
|
51
|
+
return val.map((item) => ipldToLex(item))
|
|
52
|
+
}
|
|
53
|
+
// objects
|
|
54
|
+
if (val && typeof val === 'object') {
|
|
55
|
+
// convert blobs, using hints to avoid expensive is() check
|
|
56
|
+
if (
|
|
57
|
+
(val['$type'] === 'blob' ||
|
|
58
|
+
(typeof val['cid'] === 'string' &&
|
|
59
|
+
typeof val['mimeType'] === 'string')) &&
|
|
60
|
+
check.is(val, jsonBlobRef)
|
|
61
|
+
) {
|
|
62
|
+
return BlobRef.fromJsonRef(val)
|
|
63
|
+
}
|
|
64
|
+
// retain cids, bytes
|
|
65
|
+
if (CID.asCID(val) || val instanceof Uint8Array) {
|
|
66
|
+
return val
|
|
67
|
+
}
|
|
68
|
+
// map plain objects
|
|
69
|
+
const toReturn = {}
|
|
70
|
+
for (const key of Object.keys(val)) {
|
|
71
|
+
toReturn[key] = ipldToLex(val[key])
|
|
72
|
+
}
|
|
73
|
+
return toReturn
|
|
74
|
+
}
|
|
75
|
+
// pass through
|
|
76
|
+
return val
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const lexToJson = (val: LexValue): JsonValue => {
|
|
80
|
+
return ipldToJson(lexToIpld(val))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export const stringifyLex = (val: LexValue): string => {
|
|
84
|
+
return JSON.stringify(lexToJson(val))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export const jsonToLex = (val: JsonValue): LexValue => {
|
|
88
|
+
return ipldToLex(jsonToIpld(val))
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const jsonStringToLex = (val: string): LexValue => {
|
|
92
|
+
return jsonToLex(JSON.parse(val))
|
|
93
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -12,8 +12,8 @@ export const lexBoolean = z.object({
|
|
|
12
12
|
})
|
|
13
13
|
export type LexBoolean = z.infer<typeof lexBoolean>
|
|
14
14
|
|
|
15
|
-
export const
|
|
16
|
-
type: z.literal('
|
|
15
|
+
export const lexFloat = z.object({
|
|
16
|
+
type: z.literal('float'),
|
|
17
17
|
description: z.string().optional(),
|
|
18
18
|
default: z.number().optional(),
|
|
19
19
|
minimum: z.number().optional(),
|
|
@@ -21,7 +21,7 @@ export const lexNumber = z.object({
|
|
|
21
21
|
enum: z.number().array().optional(),
|
|
22
22
|
const: z.number().optional(),
|
|
23
23
|
})
|
|
24
|
-
export type
|
|
24
|
+
export type LexFloat = z.infer<typeof lexFloat>
|
|
25
25
|
|
|
26
26
|
export const lexInteger = z.object({
|
|
27
27
|
type: z.literal('integer'),
|
|
@@ -34,24 +34,33 @@ export const lexInteger = z.object({
|
|
|
34
34
|
})
|
|
35
35
|
export type LexInteger = z.infer<typeof lexInteger>
|
|
36
36
|
|
|
37
|
+
export const lexStringFormat = z.enum([
|
|
38
|
+
'datetime',
|
|
39
|
+
'uri',
|
|
40
|
+
'at-uri',
|
|
41
|
+
'did',
|
|
42
|
+
'handle',
|
|
43
|
+
'at-identifier',
|
|
44
|
+
'nsid',
|
|
45
|
+
'cid',
|
|
46
|
+
])
|
|
47
|
+
export type LexStringFormat = z.infer<typeof lexStringFormat>
|
|
48
|
+
|
|
37
49
|
export const lexString = z.object({
|
|
38
50
|
type: z.literal('string'),
|
|
51
|
+
format: lexStringFormat.optional(),
|
|
39
52
|
description: z.string().optional(),
|
|
40
53
|
default: z.string().optional(),
|
|
41
54
|
minLength: z.number().int().optional(),
|
|
42
55
|
maxLength: z.number().int().optional(),
|
|
56
|
+
minGraphemes: z.number().int().optional(),
|
|
57
|
+
maxGraphemes: z.number().int().optional(),
|
|
43
58
|
enum: z.string().array().optional(),
|
|
44
59
|
const: z.string().optional(),
|
|
45
60
|
knownValues: z.string().array().optional(),
|
|
46
61
|
})
|
|
47
62
|
export type LexString = z.infer<typeof lexString>
|
|
48
63
|
|
|
49
|
-
export const lexDatetime = z.object({
|
|
50
|
-
type: z.literal('datetime'),
|
|
51
|
-
description: z.string().optional(),
|
|
52
|
-
})
|
|
53
|
-
export type LexDatetime = z.infer<typeof lexDatetime>
|
|
54
|
-
|
|
55
64
|
export const lexUnknown = z.object({
|
|
56
65
|
type: z.literal('unknown'),
|
|
57
66
|
description: z.string().optional(),
|
|
@@ -60,14 +69,33 @@ export type LexUnknown = z.infer<typeof lexUnknown>
|
|
|
60
69
|
|
|
61
70
|
export const lexPrimitive = z.union([
|
|
62
71
|
lexBoolean,
|
|
63
|
-
|
|
72
|
+
lexFloat,
|
|
64
73
|
lexInteger,
|
|
65
74
|
lexString,
|
|
66
|
-
lexDatetime,
|
|
67
75
|
lexUnknown,
|
|
68
76
|
])
|
|
69
77
|
export type LexPrimitive = z.infer<typeof lexPrimitive>
|
|
70
78
|
|
|
79
|
+
// ipld types
|
|
80
|
+
// =
|
|
81
|
+
|
|
82
|
+
export const lexBytes = z.object({
|
|
83
|
+
type: z.literal('bytes'),
|
|
84
|
+
description: z.string().optional(),
|
|
85
|
+
maxLength: z.number().optional(),
|
|
86
|
+
minLength: z.number().optional(),
|
|
87
|
+
})
|
|
88
|
+
export type LexBytes = z.infer<typeof lexBytes>
|
|
89
|
+
|
|
90
|
+
export const lexCidLink = z.object({
|
|
91
|
+
type: z.literal('cid-link'),
|
|
92
|
+
description: z.string().optional(),
|
|
93
|
+
})
|
|
94
|
+
export type LexCidLink = z.infer<typeof lexCidLink>
|
|
95
|
+
|
|
96
|
+
export const lexIpldType = z.union([lexBytes, lexCidLink])
|
|
97
|
+
export type LexIpldType = z.infer<typeof lexIpldType>
|
|
98
|
+
|
|
71
99
|
// references
|
|
72
100
|
// =
|
|
73
101
|
|
|
@@ -100,51 +128,25 @@ export const lexBlob = z.object({
|
|
|
100
128
|
})
|
|
101
129
|
export type LexBlob = z.infer<typeof lexBlob>
|
|
102
130
|
|
|
103
|
-
export const lexImage = z.object({
|
|
104
|
-
type: z.literal('image'),
|
|
105
|
-
description: z.string().optional(),
|
|
106
|
-
accept: z.string().array().optional(),
|
|
107
|
-
maxSize: z.number().optional(),
|
|
108
|
-
maxWidth: z.number().int().optional(),
|
|
109
|
-
maxHeight: z.number().int().optional(),
|
|
110
|
-
})
|
|
111
|
-
export type LexImage = z.infer<typeof lexImage>
|
|
112
|
-
|
|
113
|
-
export const lexVideo = z.object({
|
|
114
|
-
type: z.literal('video'),
|
|
115
|
-
description: z.string().optional(),
|
|
116
|
-
accept: z.string().array().optional(),
|
|
117
|
-
maxSize: z.number().optional(),
|
|
118
|
-
maxWidth: z.number().int().optional(),
|
|
119
|
-
maxHeight: z.number().int().optional(),
|
|
120
|
-
maxLength: z.number().int().optional(),
|
|
121
|
-
})
|
|
122
|
-
export type LexVideo = z.infer<typeof lexVideo>
|
|
123
|
-
|
|
124
|
-
export const lexAudio = z.object({
|
|
125
|
-
type: z.literal('audio'),
|
|
126
|
-
description: z.string().optional(),
|
|
127
|
-
accept: z.string().array().optional(),
|
|
128
|
-
maxSize: z.number().optional(),
|
|
129
|
-
maxLength: z.number().int().optional(),
|
|
130
|
-
})
|
|
131
|
-
export type LexAudio = z.infer<typeof lexAudio>
|
|
132
|
-
|
|
133
|
-
export const lexBlobVariant = z.union([lexBlob, lexImage, lexVideo, lexAudio])
|
|
134
|
-
export type LexBlobVariant = z.infer<typeof lexBlobVariant>
|
|
135
|
-
|
|
136
131
|
// complex types
|
|
137
132
|
// =
|
|
138
133
|
|
|
139
134
|
export const lexArray = z.object({
|
|
140
135
|
type: z.literal('array'),
|
|
141
136
|
description: z.string().optional(),
|
|
142
|
-
items: z.union([lexPrimitive,
|
|
137
|
+
items: z.union([lexPrimitive, lexIpldType, lexBlob, lexRefVariant]),
|
|
143
138
|
minLength: z.number().int().optional(),
|
|
144
139
|
maxLength: z.number().int().optional(),
|
|
145
140
|
})
|
|
146
141
|
export type LexArray = z.infer<typeof lexArray>
|
|
147
142
|
|
|
143
|
+
export const lexPrimitiveArray = lexArray.merge(
|
|
144
|
+
z.object({
|
|
145
|
+
items: lexPrimitive,
|
|
146
|
+
}),
|
|
147
|
+
)
|
|
148
|
+
export type LexPrimitiveArray = z.infer<typeof lexPrimitiveArray>
|
|
149
|
+
|
|
148
150
|
export const lexToken = z.object({
|
|
149
151
|
type: z.literal('token'),
|
|
150
152
|
description: z.string().optional(),
|
|
@@ -155,8 +157,11 @@ export const lexObject = z.object({
|
|
|
155
157
|
type: z.literal('object'),
|
|
156
158
|
description: z.string().optional(),
|
|
157
159
|
required: z.string().array().optional(),
|
|
160
|
+
nullable: z.string().array().optional(),
|
|
158
161
|
properties: z
|
|
159
|
-
.record(
|
|
162
|
+
.record(
|
|
163
|
+
z.union([lexRefVariant, lexIpldType, lexArray, lexBlob, lexPrimitive]),
|
|
164
|
+
)
|
|
160
165
|
.optional(),
|
|
161
166
|
})
|
|
162
167
|
export type LexObject = z.infer<typeof lexObject>
|
|
@@ -168,7 +173,7 @@ export const lexXrpcParameters = z.object({
|
|
|
168
173
|
type: z.literal('params'),
|
|
169
174
|
description: z.string().optional(),
|
|
170
175
|
required: z.string().array().optional(),
|
|
171
|
-
properties: z.record(lexPrimitive),
|
|
176
|
+
properties: z.record(z.union([lexPrimitive, lexPrimitiveArray])),
|
|
172
177
|
})
|
|
173
178
|
export type LexXrpcParameters = z.infer<typeof lexXrpcParameters>
|
|
174
179
|
|
|
@@ -179,6 +184,14 @@ export const lexXrpcBody = z.object({
|
|
|
179
184
|
})
|
|
180
185
|
export type LexXrpcBody = z.infer<typeof lexXrpcBody>
|
|
181
186
|
|
|
187
|
+
export const lexXrpcSubscriptionMessage = z.object({
|
|
188
|
+
description: z.string().optional(),
|
|
189
|
+
schema: z.union([lexRefVariant, lexObject]).optional(),
|
|
190
|
+
})
|
|
191
|
+
export type LexXrpcSubscriptionMessage = z.infer<
|
|
192
|
+
typeof lexXrpcSubscriptionMessage
|
|
193
|
+
>
|
|
194
|
+
|
|
182
195
|
export const lexXrpcError = z.object({
|
|
183
196
|
name: z.string(),
|
|
184
197
|
description: z.string().optional(),
|
|
@@ -204,6 +217,16 @@ export const lexXrpcProcedure = z.object({
|
|
|
204
217
|
})
|
|
205
218
|
export type LexXrpcProcedure = z.infer<typeof lexXrpcProcedure>
|
|
206
219
|
|
|
220
|
+
export const lexXrpcSubscription = z.object({
|
|
221
|
+
type: z.literal('subscription'),
|
|
222
|
+
description: z.string().optional(),
|
|
223
|
+
parameters: lexXrpcParameters.optional(),
|
|
224
|
+
message: lexXrpcSubscriptionMessage.optional(),
|
|
225
|
+
infos: lexXrpcError.array().optional(),
|
|
226
|
+
errors: lexXrpcError.array().optional(),
|
|
227
|
+
})
|
|
228
|
+
export type LexXrpcSubscription = z.infer<typeof lexXrpcSubscription>
|
|
229
|
+
|
|
207
230
|
// database
|
|
208
231
|
// =
|
|
209
232
|
|
|
@@ -223,21 +246,20 @@ export const lexUserType = z.union([
|
|
|
223
246
|
|
|
224
247
|
lexXrpcQuery,
|
|
225
248
|
lexXrpcProcedure,
|
|
249
|
+
lexXrpcSubscription,
|
|
226
250
|
|
|
227
251
|
lexBlob,
|
|
228
|
-
lexImage,
|
|
229
|
-
lexVideo,
|
|
230
|
-
lexAudio,
|
|
231
252
|
|
|
232
253
|
lexArray,
|
|
233
254
|
lexToken,
|
|
234
255
|
lexObject,
|
|
235
256
|
|
|
236
257
|
lexBoolean,
|
|
237
|
-
|
|
258
|
+
lexFloat,
|
|
238
259
|
lexInteger,
|
|
239
260
|
lexString,
|
|
240
|
-
|
|
261
|
+
lexBytes,
|
|
262
|
+
lexCidLink,
|
|
241
263
|
lexUnknown,
|
|
242
264
|
])
|
|
243
265
|
export type LexUserType = z.infer<typeof lexUserType>
|
|
@@ -259,11 +281,12 @@ export const lexiconDoc = z
|
|
|
259
281
|
defId !== 'main' &&
|
|
260
282
|
(def.type === 'record' ||
|
|
261
283
|
def.type === 'procedure' ||
|
|
262
|
-
def.type === 'query'
|
|
284
|
+
def.type === 'query' ||
|
|
285
|
+
def.type === 'subscription')
|
|
263
286
|
) {
|
|
264
287
|
ctx.addIssue({
|
|
265
288
|
code: z.ZodIssueCode.custom,
|
|
266
|
-
message: `Records, procedures, and
|
|
289
|
+
message: `Records, procedures, queries, and subscriptions must be the main definition.`,
|
|
267
290
|
})
|
|
268
291
|
}
|
|
269
292
|
}
|
|
@@ -308,10 +331,15 @@ export class LexiconDocMalformedError extends Error {
|
|
|
308
331
|
}
|
|
309
332
|
}
|
|
310
333
|
|
|
311
|
-
export
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
334
|
+
export type ValidationResult =
|
|
335
|
+
| {
|
|
336
|
+
success: true
|
|
337
|
+
value: unknown
|
|
338
|
+
}
|
|
339
|
+
| {
|
|
340
|
+
success: false
|
|
341
|
+
error: ValidationError
|
|
342
|
+
}
|
|
315
343
|
|
|
316
344
|
export class ValidationError extends Error {}
|
|
317
345
|
export class InvalidLexiconError extends Error {}
|
package/src/util.ts
CHANGED
|
@@ -49,7 +49,7 @@ export function validateOneOf(
|
|
|
49
49
|
),
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
return { success: true }
|
|
52
|
+
return { success: true, value }
|
|
53
53
|
} else {
|
|
54
54
|
concreteDefs = toConcreteTypes(lexicons, {
|
|
55
55
|
type: 'ref',
|
|
@@ -88,9 +88,8 @@ export function assertValidOneOf(
|
|
|
88
88
|
mustBeObj = false,
|
|
89
89
|
) {
|
|
90
90
|
const res = validateOneOf(lexicons, path, def, value, mustBeObj)
|
|
91
|
-
if (!res.success)
|
|
92
|
-
|
|
93
|
-
}
|
|
91
|
+
if (!res.success) throw res.error
|
|
92
|
+
return res.value
|
|
94
93
|
}
|
|
95
94
|
|
|
96
95
|
export function toConcreteTypes(
|