functionalscript 0.24.0 → 0.25.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/fs/asserts/proof.f.d.ts +8 -0
- package/fs/asserts/proof.f.js +51 -0
- package/fs/bnf/data/proof.f.js +7 -17
- package/fs/bnf/module.f.d.ts +10 -0
- package/fs/bnf/module.f.js +10 -0
- package/fs/bnf/testlib.f.js +4 -9
- package/fs/ci/common/module.f.d.ts +2 -0
- package/fs/ci/common/module.f.js +4 -1
- package/fs/ci/config/module.f.d.ts +2 -2
- package/fs/ci/config/module.f.js +2 -2
- package/fs/ci/module.f.d.ts +1 -2
- package/fs/ci/module.f.js +10 -8
- package/fs/ci/node/module.f.js +4 -2
- package/fs/ci/proof.f.js +8 -5
- package/fs/crypto/sha2/module.f.js +32 -36
- package/fs/crypto/vdf/module.f.d.ts +21 -0
- package/fs/crypto/vdf/module.f.js +57 -0
- package/fs/crypto/vdf/proof.f.d.ts +32 -0
- package/fs/crypto/vdf/proof.f.js +135 -0
- package/fs/json/module.f.d.ts +25 -9
- package/fs/json/module.f.js +25 -3
- package/fs/json/rpc/module.f.d.ts +109 -0
- package/fs/json/rpc/module.f.js +84 -0
- package/fs/json/rpc/proof.f.d.ts +35 -0
- package/fs/json/rpc/proof.f.js +68 -0
- package/fs/json/schema/module.f.d.ts +76 -0
- package/fs/json/schema/module.f.js +112 -0
- package/fs/json/schema/proof.f.d.ts +33 -0
- package/fs/json/schema/proof.f.js +71 -0
- package/fs/mcp/module.f.d.ts +88 -0
- package/fs/mcp/module.f.js +69 -0
- package/fs/sul/level/literal/proof.f.d.ts +1 -0
- package/fs/sul/level/literal/proof.f.js +6 -0
- package/fs/types/array/module.f.d.ts +7 -0
- package/fs/types/array/module.f.js +7 -0
- package/fs/types/prime_field/module.f.d.ts +8 -0
- package/fs/types/prime_field/module.f.js +37 -5
- package/fs/types/prime_field/proof.f.d.ts +3 -0
- package/fs/types/prime_field/proof.f.js +27 -2
- package/fs/types/rtti/parse/module.f.d.ts +28 -0
- package/fs/types/rtti/parse/module.f.js +35 -5
- package/fs/types/rtti/ts/module.f.d.ts +46 -3
- package/fs/types/rtti/validate/module.f.js +5 -0
- package/package.json +3 -3
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { sloth, p } from "./module.f.js";
|
|
2
|
+
const { eval: evalVdf, verify, modSqrt, quadRes } = sloth;
|
|
3
|
+
// `eval(steps)(x)` expected values for {@link p}; same Sloth algorithm as
|
|
4
|
+
// https://github.com/hyperhyperspace/pulsar/blob/main/src/model/SlothVDF.ts and
|
|
5
|
+
// https://github.com/jose-compu/dignity.js/blob/main/src/security/sloth-vdf.js
|
|
6
|
+
const sampleX = 123456789n;
|
|
7
|
+
const largeX = 12345678901234567890n;
|
|
8
|
+
const smallX = 42n;
|
|
9
|
+
const nonResidue = 2n;
|
|
10
|
+
const sampleY = 72412151236937799598582816305571618206681207952550127764586725290711141789888684237028784568532880529360450375677852568362636821341317217048062977639333459511661887862128325859969604061461913896412260750881385045152117694320409864730924775539555636460819549547999218170813228857928921642957426089461925313163n;
|
|
11
|
+
const smallY = 145151597037272685697451525487035431973338817762329243361437778785747534269376083577375382484815474368317818719265551745910148543423765263685177263740373969289084400977118144482329577335929842301331443392042760708529572252015473334998752211959790788326970269713683808382892472572910797612141527200051803670965n;
|
|
12
|
+
const y6 = 116287514643100261336025249676072556421566393377742705567032370320583145555855278910304225489766306768040386612082033279417845047304479679877515174322332386599890348932893235091525789175564701751964775040887336849457197662999383850490808701700264064812615988837073981567599117932005435532913423970502774287312n;
|
|
13
|
+
const y4 = 64401150265223443694244964595084197237814157534040219819342647664782563317539559768554855806938965782018778040933157632467146168153951260465261118025222264314070274636967492909984790708532033331622332323767105919809000393624013423095812833452440384602112677364631962445309757177309466319657219548312354433189n;
|
|
14
|
+
export const proof = {
|
|
15
|
+
p: {
|
|
16
|
+
matchesField: () => {
|
|
17
|
+
if (sloth.p !== p) {
|
|
18
|
+
throw [sloth.p, p];
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
eval: {
|
|
23
|
+
steps100: () => {
|
|
24
|
+
const y = evalVdf(100n)(sampleX);
|
|
25
|
+
if (y !== sampleY) {
|
|
26
|
+
throw [y, sampleY];
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
steps10: () => {
|
|
30
|
+
const y = evalVdf(10n)(smallX);
|
|
31
|
+
if (y !== smallY) {
|
|
32
|
+
throw [y, smallY];
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
steps6: () => {
|
|
36
|
+
const y = evalVdf(6n)(largeX);
|
|
37
|
+
if (y !== y6) {
|
|
38
|
+
throw [y, y6];
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
steps4: () => {
|
|
42
|
+
const y = evalVdf(4n)(smallX);
|
|
43
|
+
if (y !== y4) {
|
|
44
|
+
throw [y, y4];
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
zeroSteps: () => {
|
|
48
|
+
const y = evalVdf(0n)(sampleX);
|
|
49
|
+
if (y !== sampleX % p) {
|
|
50
|
+
throw [y, sampleX % p];
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
negativeSteps: () => {
|
|
54
|
+
const y = evalVdf(-1n)(sampleX);
|
|
55
|
+
if (y !== null) {
|
|
56
|
+
throw y;
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
verify: {
|
|
61
|
+
steps100: () => {
|
|
62
|
+
if (!verify(100n)(sampleX)(sampleY)) {
|
|
63
|
+
throw false;
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
steps10: () => {
|
|
67
|
+
if (!verify(10n)(smallX)(smallY)) {
|
|
68
|
+
throw false;
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
steps6: () => {
|
|
72
|
+
if (!verify(6n)(largeX)(y6)) {
|
|
73
|
+
throw false;
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
steps4: () => {
|
|
77
|
+
if (!verify(4n)(smallX)(y4)) {
|
|
78
|
+
throw false;
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
tampered: () => {
|
|
82
|
+
if (verify(4n)(smallX)((y4 + 1n) % p)) {
|
|
83
|
+
throw (y4 + 1n) % p;
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
wrongY: () => {
|
|
87
|
+
if (verify(100n)(sampleX)(sampleY + 1n)) {
|
|
88
|
+
throw sampleY + 1n;
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
zeroSteps: () => {
|
|
92
|
+
if (!verify(0n)(sampleX)(sampleX % p)) {
|
|
93
|
+
throw [sampleX % p];
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
negativeSteps: () => {
|
|
97
|
+
if (verify(-1n)(sampleX)(sampleY)) {
|
|
98
|
+
throw sampleY;
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
invalidY: () => {
|
|
102
|
+
if (verify(100n)(sampleX)(0n)) {
|
|
103
|
+
throw 0n;
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
modSqrt: {
|
|
108
|
+
roundTrip: () => {
|
|
109
|
+
const x = 999n;
|
|
110
|
+
if (!verify(1n)(x)(modSqrt(x))) {
|
|
111
|
+
throw modSqrt(x);
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
nonResidue: () => {
|
|
115
|
+
if (quadRes(nonResidue)) {
|
|
116
|
+
throw nonResidue;
|
|
117
|
+
}
|
|
118
|
+
if (!verify(1n)(nonResidue)(modSqrt(nonResidue))) {
|
|
119
|
+
throw modSqrt(nonResidue);
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
quadRes: {
|
|
124
|
+
one: () => {
|
|
125
|
+
if (!quadRes(1n)) {
|
|
126
|
+
throw 1n;
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
nonResidue: () => {
|
|
130
|
+
if (quadRes(nonResidue)) {
|
|
131
|
+
throw nonResidue;
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
};
|
package/fs/json/module.f.d.ts
CHANGED
|
@@ -1,18 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* JSON
|
|
3
|
-
* `setProperty` for immutable nested updates
|
|
4
|
-
*
|
|
2
|
+
* JSON value types, rtti schemas, and utilities: `serialize`, `stringify`,
|
|
3
|
+
* `parse`, and `setProperty` for immutable nested updates.
|
|
4
|
+
*
|
|
5
|
+
* The JSON value types (`Unknown`, `Primitive`) are derived from the rtti
|
|
6
|
+
* schemas defined here, so the schema is the single source of truth — no
|
|
7
|
+
* hand-written types to keep in sync.
|
|
5
8
|
*
|
|
6
9
|
* @module
|
|
7
10
|
*/
|
|
8
11
|
import { type List } from '../types/list/module.f.ts';
|
|
9
12
|
import { type Entry as ObjectEntry } from '../types/object/module.f.ts';
|
|
10
|
-
type
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
import type { Ts } from '../types/rtti/ts/module.f.ts';
|
|
14
|
+
/** rtti schema matching any JSON primitive: `null`, `boolean`, `number`, or `string`. */
|
|
15
|
+
export declare const primitive: import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>;
|
|
16
|
+
/**
|
|
17
|
+
* rtti schema matching any JSON value: a primitive, an array of JSON values,
|
|
18
|
+
* or an object whose values are JSON values. Self-referential via a thunk;
|
|
19
|
+
* rtti instantiates array/record item validators lazily so recursion terminates
|
|
20
|
+
* on acyclic input.
|
|
21
|
+
*
|
|
22
|
+
* A struct field typed `unknown` is **required when present** — unlike rtti
|
|
23
|
+
* core's `unknown`, the JSON `unknown` excludes `undefined`.
|
|
24
|
+
*/
|
|
25
|
+
export declare const unknown: () => readonly ["or", import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>, import("../types/rtti/module.f.ts").Type1<"record", () => readonly ["or", import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>, import("../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>]>, import("../types/rtti/module.f.ts").Type1<"array", () => readonly ["or", import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>, import("../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>]>];
|
|
26
|
+
/** rtti schema matching a JSON object: `{ readonly [k: string]: Unknown }`. */
|
|
27
|
+
export declare const object: import("../types/rtti/module.f.ts").Type1<"record", () => readonly ["or", import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>, import("../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>]>;
|
|
28
|
+
/** rtti schema matching a JSON array: `readonly Unknown[]`. */
|
|
29
|
+
export declare const array: import("../types/rtti/module.f.ts").Type1<"array", () => readonly ["or", import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>, import("../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>]>;
|
|
30
|
+
export type Primitive = Ts<typeof primitive>;
|
|
31
|
+
export type Unknown = Ts<typeof unknown>;
|
|
16
32
|
export declare const setProperty: (value: Unknown) => (path: List<string>) => (src: Unknown) => Unknown;
|
|
17
33
|
export type Entry = ObjectEntry<Unknown>;
|
|
18
34
|
type Entries = List<Entry>;
|
package/fs/json/module.f.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* JSON
|
|
3
|
-
* `setProperty` for immutable nested updates
|
|
4
|
-
*
|
|
2
|
+
* JSON value types, rtti schemas, and utilities: `serialize`, `stringify`,
|
|
3
|
+
* `parse`, and `setProperty` for immutable nested updates.
|
|
4
|
+
*
|
|
5
|
+
* The JSON value types (`Unknown`, `Primitive`) are derived from the rtti
|
|
6
|
+
* schemas defined here, so the schema is the single source of truth — no
|
|
7
|
+
* hand-written types to keep in sync.
|
|
5
8
|
*
|
|
6
9
|
* @module
|
|
7
10
|
*/
|
|
@@ -10,6 +13,25 @@ import { concat } from "../types/string/module.f.js";
|
|
|
10
13
|
import { at } from "../types/object/module.f.js";
|
|
11
14
|
import { compose, fn } from "../types/function/module.f.js";
|
|
12
15
|
import { objectWrap, arrayWrap, stringSerialize, numberSerialize, nullSerialize, boolSerialize } from "./serializer/module.f.js";
|
|
16
|
+
import { boolean as rttiBoolean, number as rttiNumber, string as rttiString, or, record, array as rttiArray } from "../types/rtti/module.f.js";
|
|
17
|
+
// ── rtti schemas ──────────────────────────────────────────────────────────────
|
|
18
|
+
/** rtti schema matching any JSON primitive: `null`, `boolean`, `number`, or `string`. */
|
|
19
|
+
export const primitive = or(null, rttiBoolean, rttiNumber, rttiString);
|
|
20
|
+
/**
|
|
21
|
+
* rtti schema matching any JSON value: a primitive, an array of JSON values,
|
|
22
|
+
* or an object whose values are JSON values. Self-referential via a thunk;
|
|
23
|
+
* rtti instantiates array/record item validators lazily so recursion terminates
|
|
24
|
+
* on acyclic input.
|
|
25
|
+
*
|
|
26
|
+
* A struct field typed `unknown` is **required when present** — unlike rtti
|
|
27
|
+
* core's `unknown`, the JSON `unknown` excludes `undefined`.
|
|
28
|
+
*/
|
|
29
|
+
export const unknown = () => ['or', primitive, object, array];
|
|
30
|
+
/** rtti schema matching a JSON object: `{ readonly [k: string]: Unknown }`. */
|
|
31
|
+
export const object = record(unknown);
|
|
32
|
+
/** rtti schema matching a JSON array: `readonly Unknown[]`. */
|
|
33
|
+
export const array = rttiArray(unknown);
|
|
34
|
+
// ── JSON utilities ────────────────────────────────────────────────────────────
|
|
13
35
|
const { entries } = Object;
|
|
14
36
|
export const setProperty = value => {
|
|
15
37
|
const f = path => src => {
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { Ts } from '../../types/rtti/ts/module.f.ts';
|
|
2
|
+
import type { Result } from '../../types/result/module.f.ts';
|
|
3
|
+
import { type Unknown } from '../module.f.ts';
|
|
4
|
+
/** Request/response identifier: a string, a number, or `null`. */
|
|
5
|
+
declare const id: import("../../types/rtti/module.f.ts").Or<[import("../../types/rtti/module.f.ts").String, import("../../types/rtti/module.f.ts").Number, null]>;
|
|
6
|
+
/**
|
|
7
|
+
* A request or notification envelope. `id` present → request (a response is
|
|
8
|
+
* expected); `id` absent → notification (no response). `params` is optional.
|
|
9
|
+
*/
|
|
10
|
+
export declare const request: {
|
|
11
|
+
readonly jsonrpc: "2.0";
|
|
12
|
+
readonly method: import("../../types/rtti/module.f.ts").String;
|
|
13
|
+
readonly params: import("../../types/rtti/module.f.ts").Or<readonly [() => readonly ["or", import("../../types/rtti/module.f.ts").Or<[null, import("../../types/rtti/module.f.ts").Boolean, import("../../types/rtti/module.f.ts").Number, import("../../types/rtti/module.f.ts").String]>, import("../../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>], undefined]>;
|
|
14
|
+
readonly id: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").Or<[import("../../types/rtti/module.f.ts").String, import("../../types/rtti/module.f.ts").Number, null]>, undefined]>;
|
|
15
|
+
};
|
|
16
|
+
/** The JSON-RPC error object. */
|
|
17
|
+
export declare const error: {
|
|
18
|
+
readonly code: import("../../types/rtti/module.f.ts").Number;
|
|
19
|
+
readonly message: import("../../types/rtti/module.f.ts").String;
|
|
20
|
+
readonly data: import("../../types/rtti/module.f.ts").Or<readonly [() => readonly ["or", import("../../types/rtti/module.f.ts").Or<[null, import("../../types/rtti/module.f.ts").Boolean, import("../../types/rtti/module.f.ts").Number, import("../../types/rtti/module.f.ts").String]>, import("../../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>], undefined]>;
|
|
21
|
+
};
|
|
22
|
+
export type Id = Ts<typeof id>;
|
|
23
|
+
export type Request = Ts<typeof request>;
|
|
24
|
+
export type RpcError = Ts<typeof error>;
|
|
25
|
+
export declare const successResponse: {
|
|
26
|
+
readonly jsonrpc: "2.0";
|
|
27
|
+
readonly result: () => readonly ["or", import("../../types/rtti/module.f.ts").Or<[null, import("../../types/rtti/module.f.ts").Boolean, import("../../types/rtti/module.f.ts").Number, import("../../types/rtti/module.f.ts").String]>, import("../../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>];
|
|
28
|
+
readonly id: import("../../types/rtti/module.f.ts").Or<[import("../../types/rtti/module.f.ts").String, import("../../types/rtti/module.f.ts").Number, null]>;
|
|
29
|
+
};
|
|
30
|
+
export declare const errorResponse: {
|
|
31
|
+
readonly jsonrpc: "2.0";
|
|
32
|
+
readonly error: {
|
|
33
|
+
readonly code: import("../../types/rtti/module.f.ts").Number;
|
|
34
|
+
readonly message: import("../../types/rtti/module.f.ts").String;
|
|
35
|
+
readonly data: import("../../types/rtti/module.f.ts").Or<readonly [() => readonly ["or", import("../../types/rtti/module.f.ts").Or<[null, import("../../types/rtti/module.f.ts").Boolean, import("../../types/rtti/module.f.ts").Number, import("../../types/rtti/module.f.ts").String]>, import("../../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>], undefined]>;
|
|
36
|
+
};
|
|
37
|
+
readonly id: import("../../types/rtti/module.f.ts").Or<[import("../../types/rtti/module.f.ts").String, import("../../types/rtti/module.f.ts").Number, null]>;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* A response envelope: either a success (`result`) or an error (`error`).
|
|
41
|
+
* Derived from the rtti schema via `Ts<>` — the same declaration is the
|
|
42
|
+
* runtime decoder and the static type, with no drift. rtti structs are open
|
|
43
|
+
* (extra keys allowed), so "result XOR error" is not enforced at runtime; in
|
|
44
|
+
* practice the dispatcher only ever constructs one or the other.
|
|
45
|
+
*/
|
|
46
|
+
export declare const response: import("../../types/rtti/module.f.ts").Or<[{
|
|
47
|
+
readonly jsonrpc: "2.0";
|
|
48
|
+
readonly result: () => readonly ["or", import("../../types/rtti/module.f.ts").Or<[null, import("../../types/rtti/module.f.ts").Boolean, import("../../types/rtti/module.f.ts").Number, import("../../types/rtti/module.f.ts").String]>, import("../../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>];
|
|
49
|
+
readonly id: import("../../types/rtti/module.f.ts").Or<[import("../../types/rtti/module.f.ts").String, import("../../types/rtti/module.f.ts").Number, null]>;
|
|
50
|
+
}, {
|
|
51
|
+
readonly jsonrpc: "2.0";
|
|
52
|
+
readonly error: {
|
|
53
|
+
readonly code: import("../../types/rtti/module.f.ts").Number;
|
|
54
|
+
readonly message: import("../../types/rtti/module.f.ts").String;
|
|
55
|
+
readonly data: import("../../types/rtti/module.f.ts").Or<readonly [() => readonly ["or", import("../../types/rtti/module.f.ts").Or<[null, import("../../types/rtti/module.f.ts").Boolean, import("../../types/rtti/module.f.ts").Number, import("../../types/rtti/module.f.ts").String]>, import("../../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>], undefined]>;
|
|
56
|
+
};
|
|
57
|
+
readonly id: import("../../types/rtti/module.f.ts").Or<[import("../../types/rtti/module.f.ts").String, import("../../types/rtti/module.f.ts").Number, null]>;
|
|
58
|
+
}]>;
|
|
59
|
+
export type Response = Ts<typeof response>;
|
|
60
|
+
/** Decodes an untrusted value as a JSON-RPC request / notification. */
|
|
61
|
+
export declare const decodeRequest: import("../../types/rtti/common/module.f.ts").Validate<{
|
|
62
|
+
readonly jsonrpc: "2.0";
|
|
63
|
+
readonly method: import("../../types/rtti/module.f.ts").String;
|
|
64
|
+
readonly params: import("../../types/rtti/module.f.ts").Or<readonly [() => readonly ["or", import("../../types/rtti/module.f.ts").Or<[null, import("../../types/rtti/module.f.ts").Boolean, import("../../types/rtti/module.f.ts").Number, import("../../types/rtti/module.f.ts").String]>, import("../../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>], undefined]>;
|
|
65
|
+
readonly id: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").Or<[import("../../types/rtti/module.f.ts").String, import("../../types/rtti/module.f.ts").Number, null]>, undefined]>;
|
|
66
|
+
}>;
|
|
67
|
+
/** A method implementation: maps `params` to a result or an `RpcError`. */
|
|
68
|
+
export type Handler = (params: Unknown | undefined) => Result<Unknown, RpcError>;
|
|
69
|
+
/** A `method` name → `Handler` map. */
|
|
70
|
+
export type Handlers = {
|
|
71
|
+
readonly [method: string]: Handler;
|
|
72
|
+
};
|
|
73
|
+
/** Builds an `RpcError` with the given `code` and `message` (no `data`). */
|
|
74
|
+
export declare const rpcError: (code: number) => (message: string) => RpcError;
|
|
75
|
+
export declare const parseError: import("../../types/rtti/ts/module.f.ts").StructTs<{
|
|
76
|
+
readonly code: import("../../types/rtti/module.f.ts").Number;
|
|
77
|
+
readonly message: import("../../types/rtti/module.f.ts").String;
|
|
78
|
+
readonly data: import("../../types/rtti/module.f.ts").Or<readonly [() => readonly ["or", import("../../types/rtti/module.f.ts").Or<[null, import("../../types/rtti/module.f.ts").Boolean, import("../../types/rtti/module.f.ts").Number, import("../../types/rtti/module.f.ts").String]>, import("../../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>], undefined]>;
|
|
79
|
+
}>;
|
|
80
|
+
export declare const invalidRequest: import("../../types/rtti/ts/module.f.ts").StructTs<{
|
|
81
|
+
readonly code: import("../../types/rtti/module.f.ts").Number;
|
|
82
|
+
readonly message: import("../../types/rtti/module.f.ts").String;
|
|
83
|
+
readonly data: import("../../types/rtti/module.f.ts").Or<readonly [() => readonly ["or", import("../../types/rtti/module.f.ts").Or<[null, import("../../types/rtti/module.f.ts").Boolean, import("../../types/rtti/module.f.ts").Number, import("../../types/rtti/module.f.ts").String]>, import("../../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>], undefined]>;
|
|
84
|
+
}>;
|
|
85
|
+
export declare const methodNotFound: import("../../types/rtti/ts/module.f.ts").StructTs<{
|
|
86
|
+
readonly code: import("../../types/rtti/module.f.ts").Number;
|
|
87
|
+
readonly message: import("../../types/rtti/module.f.ts").String;
|
|
88
|
+
readonly data: import("../../types/rtti/module.f.ts").Or<readonly [() => readonly ["or", import("../../types/rtti/module.f.ts").Or<[null, import("../../types/rtti/module.f.ts").Boolean, import("../../types/rtti/module.f.ts").Number, import("../../types/rtti/module.f.ts").String]>, import("../../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>], undefined]>;
|
|
89
|
+
}>;
|
|
90
|
+
export declare const invalidParams: import("../../types/rtti/ts/module.f.ts").StructTs<{
|
|
91
|
+
readonly code: import("../../types/rtti/module.f.ts").Number;
|
|
92
|
+
readonly message: import("../../types/rtti/module.f.ts").String;
|
|
93
|
+
readonly data: import("../../types/rtti/module.f.ts").Or<readonly [() => readonly ["or", import("../../types/rtti/module.f.ts").Or<[null, import("../../types/rtti/module.f.ts").Boolean, import("../../types/rtti/module.f.ts").Number, import("../../types/rtti/module.f.ts").String]>, import("../../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>], undefined]>;
|
|
94
|
+
}>;
|
|
95
|
+
export declare const internalError: import("../../types/rtti/ts/module.f.ts").StructTs<{
|
|
96
|
+
readonly code: import("../../types/rtti/module.f.ts").Number;
|
|
97
|
+
readonly message: import("../../types/rtti/module.f.ts").String;
|
|
98
|
+
readonly data: import("../../types/rtti/module.f.ts").Or<readonly [() => readonly ["or", import("../../types/rtti/module.f.ts").Or<[null, import("../../types/rtti/module.f.ts").Boolean, import("../../types/rtti/module.f.ts").Number, import("../../types/rtti/module.f.ts").String]>, import("../../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>], undefined]>;
|
|
99
|
+
}>;
|
|
100
|
+
/**
|
|
101
|
+
* Dispatches an already-parsed JSON-RPC value against `handlers`.
|
|
102
|
+
*
|
|
103
|
+
* - invalid envelope → `Invalid Request` (`-32600`) with `id: null`
|
|
104
|
+
* - notification (no `id`) → `null` (never a response)
|
|
105
|
+
* - unknown method → `Method not found` (`-32601`)
|
|
106
|
+
* - otherwise the handler's `ok` / `error` result becomes a success / error response
|
|
107
|
+
*/
|
|
108
|
+
export declare const dispatch: (handlers: Handlers) => (value: Unknown) => Response | null;
|
|
109
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC 2.0 envelopes and a pure dispatcher.
|
|
3
|
+
*
|
|
4
|
+
* The envelopes are rtti schemas, so one declaration yields both a runtime
|
|
5
|
+
* decoder (`validate(request)`) and the static type (`Ts<typeof request>`) — no
|
|
6
|
+
* drift between them. The dispatcher is pure: it maps an already-parsed request
|
|
7
|
+
* value to a response value (or `null` for a notification) and performs no I/O.
|
|
8
|
+
*
|
|
9
|
+
* Out of scope here (follow-ups): transports — stdio / HTTP framing — over
|
|
10
|
+
* `fs/effects/node`, and concrete method sets such as MCP (i665-mcp), which layer
|
|
11
|
+
* on top of `dispatch`.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import { number, string, or, option } from "../../types/rtti/module.f.js";
|
|
16
|
+
import { validate } from "../../types/rtti/validate/module.f.js";
|
|
17
|
+
import { unknown } from "../module.f.js";
|
|
18
|
+
const jsonrpc = '2.0';
|
|
19
|
+
/** Request/response identifier: a string, a number, or `null`. */
|
|
20
|
+
const id = or(string, number, null);
|
|
21
|
+
/**
|
|
22
|
+
* A request or notification envelope. `id` present → request (a response is
|
|
23
|
+
* expected); `id` absent → notification (no response). `params` is optional.
|
|
24
|
+
*/
|
|
25
|
+
export const request = {
|
|
26
|
+
jsonrpc,
|
|
27
|
+
method: string,
|
|
28
|
+
params: option(unknown),
|
|
29
|
+
id: option(id),
|
|
30
|
+
};
|
|
31
|
+
/** The JSON-RPC error object. */
|
|
32
|
+
export const error = {
|
|
33
|
+
code: number,
|
|
34
|
+
message: string,
|
|
35
|
+
data: option(unknown),
|
|
36
|
+
};
|
|
37
|
+
export const successResponse = { jsonrpc, result: unknown, id };
|
|
38
|
+
export const errorResponse = { jsonrpc, error, id };
|
|
39
|
+
/**
|
|
40
|
+
* A response envelope: either a success (`result`) or an error (`error`).
|
|
41
|
+
* Derived from the rtti schema via `Ts<>` — the same declaration is the
|
|
42
|
+
* runtime decoder and the static type, with no drift. rtti structs are open
|
|
43
|
+
* (extra keys allowed), so "result XOR error" is not enforced at runtime; in
|
|
44
|
+
* practice the dispatcher only ever constructs one or the other.
|
|
45
|
+
*/
|
|
46
|
+
export const response = or(successResponse, errorResponse);
|
|
47
|
+
/** Decodes an untrusted value as a JSON-RPC request / notification. */
|
|
48
|
+
export const decodeRequest = validate(request);
|
|
49
|
+
/** Builds an `RpcError` with the given `code` and `message` (no `data`). */
|
|
50
|
+
export const rpcError = (code) => (message) => ({ code, message });
|
|
51
|
+
// The standard JSON-RPC 2.0 errors.
|
|
52
|
+
export const parseError = rpcError(-32700)('Parse error');
|
|
53
|
+
export const invalidRequest = rpcError(-32600)('Invalid Request');
|
|
54
|
+
export const methodNotFound = rpcError(-32601)('Method not found');
|
|
55
|
+
export const invalidParams = rpcError(-32602)('Invalid params');
|
|
56
|
+
export const internalError = rpcError(-32603)('Internal error');
|
|
57
|
+
const errorResponseOf = (id) => (e) => ({ jsonrpc, error: e, id });
|
|
58
|
+
/**
|
|
59
|
+
* Dispatches an already-parsed JSON-RPC value against `handlers`.
|
|
60
|
+
*
|
|
61
|
+
* - invalid envelope → `Invalid Request` (`-32600`) with `id: null`
|
|
62
|
+
* - notification (no `id`) → `null` (never a response)
|
|
63
|
+
* - unknown method → `Method not found` (`-32601`)
|
|
64
|
+
* - otherwise the handler's `ok` / `error` result becomes a success / error response
|
|
65
|
+
*/
|
|
66
|
+
export const dispatch = (handlers) => (value) => {
|
|
67
|
+
const decoded = decodeRequest(value);
|
|
68
|
+
if (decoded[0] === 'error') {
|
|
69
|
+
return errorResponseOf(null)(invalidRequest);
|
|
70
|
+
}
|
|
71
|
+
const message = decoded[1];
|
|
72
|
+
const id = message.id;
|
|
73
|
+
if (id === undefined) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
const handler = handlers[message.method];
|
|
77
|
+
if (handler === undefined) {
|
|
78
|
+
return errorResponseOf(id)(methodNotFound);
|
|
79
|
+
}
|
|
80
|
+
const result = handler(message.params);
|
|
81
|
+
return result[0] === 'ok'
|
|
82
|
+
? { jsonrpc, result: result[1], id }
|
|
83
|
+
: errorResponseOf(id)(result[1]);
|
|
84
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export declare const proof: {
|
|
2
|
+
schema: {
|
|
3
|
+
request: {
|
|
4
|
+
full: () => void;
|
|
5
|
+
notification: () => void;
|
|
6
|
+
nullId: () => void;
|
|
7
|
+
stringId: () => void;
|
|
8
|
+
badVersion: () => void;
|
|
9
|
+
missingMethod: () => void;
|
|
10
|
+
badId: () => void;
|
|
11
|
+
notObject: () => void;
|
|
12
|
+
};
|
|
13
|
+
error: {
|
|
14
|
+
ok: () => void;
|
|
15
|
+
withData: () => void;
|
|
16
|
+
missingMessage: () => void;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
errors: {
|
|
20
|
+
factory: () => void;
|
|
21
|
+
parseError: () => void;
|
|
22
|
+
invalidRequest: () => void;
|
|
23
|
+
methodNotFound: () => void;
|
|
24
|
+
invalidParams: () => void;
|
|
25
|
+
internalError: () => void;
|
|
26
|
+
};
|
|
27
|
+
dispatch: {
|
|
28
|
+
success: () => void;
|
|
29
|
+
paramsPassed: () => void;
|
|
30
|
+
handlerError: () => void;
|
|
31
|
+
methodNotFound: () => void;
|
|
32
|
+
invalidRequest: () => void;
|
|
33
|
+
notification: () => void;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { assert, assertEq } from "../../asserts/module.f.js";
|
|
2
|
+
import { ok, error } from "../../types/result/module.f.js";
|
|
3
|
+
import { validate } from "../../types/rtti/validate/module.f.js";
|
|
4
|
+
import { error as errorSchema, decodeRequest, dispatch, rpcError, parseError, invalidRequest, methodNotFound, invalidParams, internalError, } from "./module.f.js";
|
|
5
|
+
const isOk = (r) => r[0] === 'ok';
|
|
6
|
+
const handlers = {
|
|
7
|
+
ping: () => ok('pong'),
|
|
8
|
+
echo: params => ok(params ?? null),
|
|
9
|
+
boom: () => error(invalidParams),
|
|
10
|
+
};
|
|
11
|
+
const d = dispatch(handlers);
|
|
12
|
+
export const proof = {
|
|
13
|
+
schema: {
|
|
14
|
+
request: {
|
|
15
|
+
full: () => assert(isOk(decodeRequest({ jsonrpc: '2.0', method: 'm', params: [1], id: 1 }))),
|
|
16
|
+
notification: () => assert(isOk(decodeRequest({ jsonrpc: '2.0', method: 'm' }))),
|
|
17
|
+
nullId: () => assert(isOk(decodeRequest({ jsonrpc: '2.0', method: 'm', id: null }))),
|
|
18
|
+
stringId: () => assert(isOk(decodeRequest({ jsonrpc: '2.0', method: 'm', id: 'abc' }))),
|
|
19
|
+
badVersion: () => assert(!isOk(decodeRequest({ jsonrpc: '1.0', method: 'm', id: 1 }))),
|
|
20
|
+
missingMethod: () => assert(!isOk(decodeRequest({ jsonrpc: '2.0', id: 1 }))),
|
|
21
|
+
badId: () => assert(!isOk(decodeRequest({ jsonrpc: '2.0', method: 'm', id: true }))),
|
|
22
|
+
notObject: () => assert(!isOk(decodeRequest(42))),
|
|
23
|
+
},
|
|
24
|
+
error: {
|
|
25
|
+
ok: () => assert(isOk(validate(errorSchema)({ code: -1, message: 'x' }))),
|
|
26
|
+
withData: () => assert(isOk(validate(errorSchema)({ code: -1, message: 'x', data: [1, 2] }))),
|
|
27
|
+
missingMessage: () => assert(!isOk(validate(errorSchema)({ code: -1 }))),
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
errors: {
|
|
31
|
+
factory: () => {
|
|
32
|
+
const e = rpcError(-7)('boom');
|
|
33
|
+
assertEq(e.code, -7);
|
|
34
|
+
assertEq(e.message, 'boom');
|
|
35
|
+
},
|
|
36
|
+
parseError: () => { assertEq(parseError.code, -32700); assertEq(parseError.message, 'Parse error'); },
|
|
37
|
+
invalidRequest: () => { assertEq(invalidRequest.code, -32600); assertEq(invalidRequest.message, 'Invalid Request'); },
|
|
38
|
+
methodNotFound: () => { assertEq(methodNotFound.code, -32601); assertEq(methodNotFound.message, 'Method not found'); },
|
|
39
|
+
invalidParams: () => { assertEq(invalidParams.code, -32602); assertEq(invalidParams.message, 'Invalid params'); },
|
|
40
|
+
internalError: () => { assertEq(internalError.code, -32603); assertEq(internalError.message, 'Internal error'); },
|
|
41
|
+
},
|
|
42
|
+
dispatch: {
|
|
43
|
+
success: () => {
|
|
44
|
+
const r = d({ jsonrpc: '2.0', method: 'ping', id: 1 });
|
|
45
|
+
assert(r !== null && 'result' in r && r.result === 'pong' && r.id === 1);
|
|
46
|
+
},
|
|
47
|
+
paramsPassed: () => {
|
|
48
|
+
const r = d({ jsonrpc: '2.0', method: 'echo', params: 'hi', id: 2 });
|
|
49
|
+
assert(r !== null && 'result' in r && r.result === 'hi');
|
|
50
|
+
},
|
|
51
|
+
handlerError: () => {
|
|
52
|
+
const r = d({ jsonrpc: '2.0', method: 'boom', id: 3 });
|
|
53
|
+
assert(r !== null && 'error' in r && r.error.code === -32602 && r.id === 3);
|
|
54
|
+
},
|
|
55
|
+
methodNotFound: () => {
|
|
56
|
+
const r = d({ jsonrpc: '2.0', method: 'nope', id: 4 });
|
|
57
|
+
assert(r !== null && 'error' in r && r.error.code === -32601);
|
|
58
|
+
},
|
|
59
|
+
invalidRequest: () => {
|
|
60
|
+
const r = d({ jsonrpc: '1.0', method: 'ping', id: 5 });
|
|
61
|
+
assert(r !== null && 'error' in r && r.error.code === -32600 && r.id === null);
|
|
62
|
+
},
|
|
63
|
+
notification: () => {
|
|
64
|
+
const r = d({ jsonrpc: '2.0', method: 'ping' });
|
|
65
|
+
assertEq(r, null);
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts an rtti schema to a JSON Schema (draft 2020-12) object.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the visitor structure of `fs/types/rtti/ts/module.f.ts` (`printer` / `toTs`),
|
|
5
|
+
* but emits a JSON Schema object instead of a TypeScript type string.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import { type Type as RttiType } from '../../types/rtti/module.f.ts';
|
|
10
|
+
import type { Ts, WithOut } from '../../types/rtti/ts/module.f.ts';
|
|
11
|
+
declare const unknownThunk: () => readonly ["const", {
|
|
12
|
+
readonly type: import("../../types/rtti/module.f.ts").Or<["boolean", "number", "string", "integer", "array", "object", undefined]>;
|
|
13
|
+
readonly const: import("../../types/rtti/module.f.ts").Or<readonly [() => readonly ["or", import("../../types/rtti/module.f.ts").Or<[null, import("../../types/rtti/module.f.ts").Boolean, import("../../types/rtti/module.f.ts").Number, import("../../types/rtti/module.f.ts").String]>, import("../../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>], undefined]>;
|
|
14
|
+
readonly not: import("../../types/rtti/module.f.ts").Or<readonly [WithOut<() => readonly ["const", /*elided*/ any], UnknownConst>, undefined]>;
|
|
15
|
+
readonly anyOf: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").Type1<"array", WithOut<() => readonly ["const", /*elided*/ any], UnknownConst>>, undefined]>;
|
|
16
|
+
readonly items: import("../../types/rtti/module.f.ts").Or<[WithOut<() => readonly ["const", /*elided*/ any], UnknownConst>, false, undefined]>;
|
|
17
|
+
readonly prefixItems: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").Type1<"array", WithOut<() => readonly ["const", /*elided*/ any], UnknownConst>>, undefined]>;
|
|
18
|
+
readonly properties: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").Type1<"record", WithOut<() => readonly ["const", /*elided*/ any], UnknownConst>>, undefined]>;
|
|
19
|
+
readonly required: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").Type1<"array", import("../../types/rtti/module.f.ts").String>, undefined]>;
|
|
20
|
+
readonly additionalProperties: import("../../types/rtti/module.f.ts").Or<readonly [WithOut<() => readonly ["const", /*elided*/ any], UnknownConst>, undefined]>;
|
|
21
|
+
}];
|
|
22
|
+
/** rtti schema for a JSON Schema (draft 2020-12) document. */
|
|
23
|
+
export declare const unknown: WithOut<typeof unknownThunk, UnknownConst>;
|
|
24
|
+
/** A JSON Schema (draft 2020-12) document — the subset of keywords that `toJsonSchema` emits. */
|
|
25
|
+
export type Unknown = Ts<typeof unknown>;
|
|
26
|
+
declare const unknownConst: {
|
|
27
|
+
readonly type: import("../../types/rtti/module.f.ts").Or<["boolean", "number", "string", "integer", "array", "object", undefined]>;
|
|
28
|
+
readonly const: import("../../types/rtti/module.f.ts").Or<readonly [() => readonly ["or", import("../../types/rtti/module.f.ts").Or<[null, import("../../types/rtti/module.f.ts").Boolean, import("../../types/rtti/module.f.ts").Number, import("../../types/rtti/module.f.ts").String]>, import("../../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>], undefined]>;
|
|
29
|
+
readonly not: import("../../types/rtti/module.f.ts").Or<readonly [WithOut<() => readonly ["const", /*elided*/ any], UnknownConst>, undefined]>;
|
|
30
|
+
readonly anyOf: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").Type1<"array", WithOut<() => readonly ["const", /*elided*/ any], UnknownConst>>, undefined]>;
|
|
31
|
+
readonly items: import("../../types/rtti/module.f.ts").Or<[WithOut<() => readonly ["const", /*elided*/ any], UnknownConst>, false, undefined]>;
|
|
32
|
+
readonly prefixItems: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").Type1<"array", WithOut<() => readonly ["const", /*elided*/ any], UnknownConst>>, undefined]>;
|
|
33
|
+
readonly properties: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").Type1<"record", WithOut<() => readonly ["const", /*elided*/ any], UnknownConst>>, undefined]>;
|
|
34
|
+
readonly required: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").Type1<"array", import("../../types/rtti/module.f.ts").String>, undefined]>;
|
|
35
|
+
readonly additionalProperties: import("../../types/rtti/module.f.ts").Or<readonly [WithOut<() => readonly ["const", /*elided*/ any], UnknownConst>, undefined]>;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Hand-written base type used as the `$out` annotation on `unknown`.
|
|
39
|
+
*
|
|
40
|
+
* The `?` markers are required even though `Ts<>` already includes `undefined`
|
|
41
|
+
* in each field type. Without `?`, `Unknown = UnknownConst` would require all
|
|
42
|
+
* 9 fields to be present in every object literal returned by `toJsonSchema`,
|
|
43
|
+
* because TypeScript distinguishes "field absent" (`?`) from "field present but
|
|
44
|
+
* undefined" (`T | undefined`). JSON Schema objects only include the fields
|
|
45
|
+
* they need, so all fields must be optional.
|
|
46
|
+
*/
|
|
47
|
+
type UnknownConst = {
|
|
48
|
+
readonly type?: Ts<typeof unknownConst.type>;
|
|
49
|
+
readonly const?: Ts<typeof unknownConst.const>;
|
|
50
|
+
readonly not?: Ts<typeof unknownConst.not>;
|
|
51
|
+
readonly anyOf?: Ts<typeof unknownConst.anyOf>;
|
|
52
|
+
readonly items?: Ts<typeof unknownConst.items>;
|
|
53
|
+
readonly prefixItems?: Ts<typeof unknownConst.prefixItems>;
|
|
54
|
+
readonly properties?: Ts<typeof unknownConst.properties>;
|
|
55
|
+
readonly required?: Ts<typeof unknownConst.required>;
|
|
56
|
+
readonly additionalProperties?: Ts<typeof unknownConst.additionalProperties>;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Converts an rtti `Type` to a JSON Schema (draft 2020-12) object.
|
|
60
|
+
*
|
|
61
|
+
* | rtti | JSON Schema |
|
|
62
|
+
* |-----------------------------------------------|-------------------------------------------------------------------------------------|
|
|
63
|
+
* | `boolean` / `number` / `string` | `{ "type": "..." }` |
|
|
64
|
+
* | `bigint` | `{ "type": "integer" }` (lossy; JSON integers are IEEE-754 doubles) |
|
|
65
|
+
* | `unknown` | `{}` (always-true schema) |
|
|
66
|
+
* | primitive const (`42`, `'x'`, `true`, `null`) | `{ "const": <value> }` |
|
|
67
|
+
* | `bigint` const | `{ "const": Number(value) }` (lossy for \|value\| > MAX_SAFE_INTEGER) |
|
|
68
|
+
* | `undefined` const | `{ "not": {} }` (no JSON value satisfies this) |
|
|
69
|
+
* | struct `{ a: T, … }` | `{ "type": "object", "properties": { "a": …T… }, "required": [non-optional keys] }` |
|
|
70
|
+
* | tuple `[A, B]` | `{ "type": "array", "prefixItems": […A…, …B…], "items": false }` |
|
|
71
|
+
* | `array(T)` | `{ "type": "array", "items": …T… }` |
|
|
72
|
+
* | `record(T)` | `{ "type": "object", "additionalProperties": …T… }` |
|
|
73
|
+
* | `or(...types)` | `{ "anyOf": […each…] }` |
|
|
74
|
+
*/
|
|
75
|
+
export declare const toJsonSchema: (rtti: RttiType) => Unknown;
|
|
76
|
+
export {};
|