@silvermoon-work/ipfs-payload 0.0.0-stage → 0.1.0-rc.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/LICENSE +21 -0
- package/README.md +102 -2
- package/dist/content-ref.d.ts +9 -0
- package/dist/content-ref.d.ts.map +1 -0
- package/dist/content-ref.js +19 -0
- package/dist/content-ref.js.map +1 -0
- package/dist/contract.d.ts +9 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +280 -0
- package/dist/contract.js.map +1 -0
- package/dist/dag-cbor.d.ts +7 -0
- package/dist/dag-cbor.d.ts.map +1 -0
- package/dist/dag-cbor.js +36 -0
- package/dist/dag-cbor.js.map +1 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +192 -0
- package/dist/index.js.map +1 -0
- package/dist/paths.d.ts +20 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +161 -0
- package/dist/paths.js.map +1 -0
- package/dist/reference.d.ts +15 -0
- package/dist/reference.d.ts.map +1 -0
- package/dist/reference.js +14 -0
- package/dist/reference.js.map +1 -0
- package/dist/schema.d.ts +6 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +196 -0
- package/dist/schema.js.map +1 -0
- package/dist/typebox.d.ts +3 -0
- package/dist/typebox.d.ts.map +1 -0
- package/dist/typebox.js +3 -0
- package/dist/typebox.js.map +1 -0
- package/dist/value.d.ts +25 -0
- package/dist/value.d.ts.map +1 -0
- package/dist/value.js +103 -0
- package/dist/value.js.map +1 -0
- package/package.json +56 -3
package/dist/index.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import * as dagCbor from "@ipld/dag-cbor";
|
|
2
|
+
import { asNativeCID, encodeDagCbor } from "./dag-cbor.js";
|
|
3
|
+
import { CID } from "multiformats/cid";
|
|
4
|
+
import { sha256 } from "multiformats/hashes/sha2";
|
|
5
|
+
import { inspectTaskSchema } from "./contract.js";
|
|
6
|
+
import { ContentRef } from "./content-ref.js";
|
|
7
|
+
import { formatCidPath, locate, parseCidPath } from "./paths.js";
|
|
8
|
+
import { inspectSchema } from "./schema.js";
|
|
9
|
+
import { Budget, snapshot } from "./value.js";
|
|
10
|
+
export { addContentRefKeyword, inspectTaskSchema } from "./contract.js";
|
|
11
|
+
export { ContentRef } from "./content-ref.js";
|
|
12
|
+
export { parseCidPath } from "./paths.js";
|
|
13
|
+
export { Budget, defaultPayloadLimits } from "./value.js";
|
|
14
|
+
function sameLocations(a, b) {
|
|
15
|
+
if (a.size !== b.size || [...a.keys()].some((path) => !b.has(path)))
|
|
16
|
+
throw new Error("CID paths do not exactly match the content references.");
|
|
17
|
+
}
|
|
18
|
+
function inspector(options) {
|
|
19
|
+
if (options.inspect)
|
|
20
|
+
return options.inspect;
|
|
21
|
+
if (options.validate)
|
|
22
|
+
return (schema, data, budget) => inspectTaskSchema(schema, data, budget, options.validate);
|
|
23
|
+
return inspectSchema;
|
|
24
|
+
}
|
|
25
|
+
function checked(input, schema, budget, options = {}) {
|
|
26
|
+
const value = snapshot(input, budget);
|
|
27
|
+
if (!value ||
|
|
28
|
+
typeof value !== "object" ||
|
|
29
|
+
Array.isArray(value) ||
|
|
30
|
+
Object.keys(value).length !== 2 ||
|
|
31
|
+
!Object.hasOwn(value, "data") ||
|
|
32
|
+
!Object.hasOwn(value, "cidPaths") ||
|
|
33
|
+
!Array.isArray(value.cidPaths))
|
|
34
|
+
throw new Error("Expected an IpfsPayload with exactly data and cidPaths.");
|
|
35
|
+
const data = value.data;
|
|
36
|
+
const cidPaths = value.cidPaths;
|
|
37
|
+
budget.bytes(value);
|
|
38
|
+
if (cidPaths.length > budget.limits.maxPaths)
|
|
39
|
+
throw new Error("CID path count capacity exceeded.");
|
|
40
|
+
const contract = schema === undefined ? undefined : inspector(options)(schema, data, budget);
|
|
41
|
+
const references = new Map();
|
|
42
|
+
const seen = new Set();
|
|
43
|
+
for (const path of cidPaths) {
|
|
44
|
+
if (typeof path !== "string")
|
|
45
|
+
throw new Error("CID paths must be strings.");
|
|
46
|
+
const ast = parseCidPath(path, budget.limits);
|
|
47
|
+
const normalized = formatCidPath(ast);
|
|
48
|
+
if (seen.has(normalized))
|
|
49
|
+
throw new Error("Duplicate CID path.");
|
|
50
|
+
seen.add(normalized);
|
|
51
|
+
const matches = locate(data, ast, budget);
|
|
52
|
+
if (contract && matches.size === 0 && !contract.rules.has(normalized))
|
|
53
|
+
throw new Error("CID path is not declared by the schema.");
|
|
54
|
+
for (const [location, cid] of matches) {
|
|
55
|
+
if (references.has(location))
|
|
56
|
+
throw new Error("Overlapping CID paths.");
|
|
57
|
+
if (typeof cid !== "string")
|
|
58
|
+
throw new Error("A CID path must select CID strings.");
|
|
59
|
+
references.set(location, CID.parse(cid));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (contract)
|
|
63
|
+
sameLocations(references, contract.expected);
|
|
64
|
+
return { payload: { data, cidPaths: cidPaths }, references };
|
|
65
|
+
}
|
|
66
|
+
/** Encode ContentRef instances without a contract; lookalike strings stay ordinary. */
|
|
67
|
+
export function encodeReferences(value, options = {}) {
|
|
68
|
+
const budget = new Budget(options.limits);
|
|
69
|
+
const actual = new Map();
|
|
70
|
+
const data = snapshot(value, budget, (input, path) => {
|
|
71
|
+
if (!(input instanceof ContentRef))
|
|
72
|
+
return undefined;
|
|
73
|
+
actual.set(path, input.cid);
|
|
74
|
+
return { value: input.cid.toString() };
|
|
75
|
+
});
|
|
76
|
+
budget.bytes(data);
|
|
77
|
+
const cidPaths = [...actual.keys()].sort();
|
|
78
|
+
const result = { data, cidPaths };
|
|
79
|
+
checked(result, undefined, budget, options);
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
/** Encode author values according to their contract; strings and lookalike objects stay ordinary. */
|
|
83
|
+
export function encodePayload(schema, value, options = {}) {
|
|
84
|
+
const budget = new Budget(options.limits);
|
|
85
|
+
const actual = new Map();
|
|
86
|
+
const data = snapshot(value, budget, (input, path) => {
|
|
87
|
+
if (!(input instanceof ContentRef))
|
|
88
|
+
return undefined;
|
|
89
|
+
actual.set(path, input.cid);
|
|
90
|
+
return { value: input.cid.toString() };
|
|
91
|
+
});
|
|
92
|
+
budget.bytes(data);
|
|
93
|
+
const { expected } = inspector(options)(schema, data, budget);
|
|
94
|
+
sameLocations(actual, expected);
|
|
95
|
+
const cidPaths = [];
|
|
96
|
+
const covered = new Set();
|
|
97
|
+
for (const candidate of new Set(expected.values())) {
|
|
98
|
+
const matches = locate(data, parseCidPath(candidate, budget.limits), budget);
|
|
99
|
+
if ([...matches.keys()].some((path) => !expected.has(path) || covered.has(path)))
|
|
100
|
+
continue;
|
|
101
|
+
if (!matches.size)
|
|
102
|
+
continue;
|
|
103
|
+
cidPaths.push(candidate);
|
|
104
|
+
for (const path of matches.keys())
|
|
105
|
+
covered.add(path);
|
|
106
|
+
}
|
|
107
|
+
for (const path of expected.keys())
|
|
108
|
+
if (!covered.has(path))
|
|
109
|
+
cidPaths.push(path);
|
|
110
|
+
cidPaths.sort();
|
|
111
|
+
const result = { data, cidPaths };
|
|
112
|
+
// Generated metadata follows the very same limits and strict checks as received metadata.
|
|
113
|
+
checked(result, schema, budget, options);
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
export function validatePayload(payload, schema, options = {}) {
|
|
117
|
+
return checked(payload, schema, new Budget(options.limits), options).payload;
|
|
118
|
+
}
|
|
119
|
+
export function decodePayload(payload, schema, options = {}) {
|
|
120
|
+
const budget = new Budget(options.limits);
|
|
121
|
+
const verified = checked(payload, schema, budget, options);
|
|
122
|
+
return snapshot(verified.payload.data, budget, (_value, path) => {
|
|
123
|
+
const cid = verified.references.get(path);
|
|
124
|
+
return cid ? { value: ContentRef.fromCID(cid) } : undefined;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/** The DAG envelope preserves metadata, but reference positions contain real IPLD CID links. */
|
|
128
|
+
export function toDagPayload(payload, schema, options = {}) {
|
|
129
|
+
const budget = new Budget(options.limits);
|
|
130
|
+
const verified = checked(payload, schema, budget, options);
|
|
131
|
+
return {
|
|
132
|
+
data: snapshot(verified.payload.data, budget, (_value, path) => {
|
|
133
|
+
const cid = verified.references.get(path);
|
|
134
|
+
return cid ? { value: cid } : undefined;
|
|
135
|
+
}),
|
|
136
|
+
cidPaths: verified.payload.cidPaths,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
export function fromDagPayload(value, schema, options = {}) {
|
|
140
|
+
const budget = new Budget(options.limits);
|
|
141
|
+
const actual = new Map();
|
|
142
|
+
const json = snapshot(value, budget, (input, path) => {
|
|
143
|
+
const cid = asNativeCID(input);
|
|
144
|
+
if (!cid)
|
|
145
|
+
return undefined;
|
|
146
|
+
actual.set(path, cid);
|
|
147
|
+
return { value: cid.toString() };
|
|
148
|
+
});
|
|
149
|
+
const verified = checked(json, schema, budget, options);
|
|
150
|
+
const expected = new Map([...verified.references].map(([path, cid]) => [`$["data"]${path.slice(1)}`, cid]));
|
|
151
|
+
sameLocations(actual, expected);
|
|
152
|
+
return verified.payload;
|
|
153
|
+
}
|
|
154
|
+
export async function encodePayloadBlock(payload, schema, options = {}) {
|
|
155
|
+
const bytes = encodeDagCbor(toDagPayload(payload, schema, options));
|
|
156
|
+
if (bytes.byteLength > new Budget(options.limits).limits.maxBytes)
|
|
157
|
+
throw new Error("Payload block byte capacity exceeded.");
|
|
158
|
+
return { bytes, cid: CID.createV1(dagCbor.code, await sha256.digest(bytes)) };
|
|
159
|
+
}
|
|
160
|
+
export async function decodePayloadBlock(bytes, schema, options = {}) {
|
|
161
|
+
if (!(bytes instanceof Uint8Array) ||
|
|
162
|
+
bytes.byteLength > new Budget(options.limits).limits.maxBytes)
|
|
163
|
+
throw new Error("Payload block byte capacity exceeded.");
|
|
164
|
+
const owned = Uint8Array.from(bytes);
|
|
165
|
+
if (options.cid) {
|
|
166
|
+
const cid = CID.createV1(dagCbor.code, await sha256.digest(owned));
|
|
167
|
+
if (!cid.equals(options.cid))
|
|
168
|
+
throw new Error("Payload CID verification failed.");
|
|
169
|
+
}
|
|
170
|
+
const value = dagCbor.decode(owned);
|
|
171
|
+
const payload = fromDagPayload(value, schema, options);
|
|
172
|
+
const canonical = encodeDagCbor(toDagPayload(payload, schema, options));
|
|
173
|
+
if (canonical.length !== owned.length || canonical.some((byte, i) => byte !== owned[i]))
|
|
174
|
+
throw new Error("Non-canonical DAG-CBOR payload.");
|
|
175
|
+
return payload;
|
|
176
|
+
}
|
|
177
|
+
/** Trusted Task-dialect bridge: snapshot/path conversion plus full Schema validation. */
|
|
178
|
+
export function compileTrustedContract(schema, options = {}) {
|
|
179
|
+
const inspect = (source, data, budget) => inspectTaskSchema(source, data, budget, options.validate);
|
|
180
|
+
const bound = { ...options, inspect };
|
|
181
|
+
return {
|
|
182
|
+
schema,
|
|
183
|
+
encode: (value) => encodePayload(schema, value, bound),
|
|
184
|
+
decode: (payload) => decodePayload(payload, schema, bound),
|
|
185
|
+
validate: (payload) => validatePayload(payload, schema, bound),
|
|
186
|
+
toDag: (payload) => toDagPayload(payload, schema, bound),
|
|
187
|
+
fromDag: (value) => fromDagPayload(value, schema, bound),
|
|
188
|
+
encodeBlock: (payload) => encodePayloadBlock(payload, schema, bound),
|
|
189
|
+
decodeBlock: (bytes, cid) => decodePayloadBlock(bytes, schema, cid ? { ...bound, cid } : bound),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Budget, type JsonValue, type PayloadLimits } from "./value.js";
|
|
2
|
+
type Literal = string | number | boolean | null;
|
|
3
|
+
export type CidPathStep = {
|
|
4
|
+
kind: "property";
|
|
5
|
+
key: string;
|
|
6
|
+
} | {
|
|
7
|
+
kind: "index";
|
|
8
|
+
index: number;
|
|
9
|
+
} | {
|
|
10
|
+
kind: "wildcard";
|
|
11
|
+
} | {
|
|
12
|
+
kind: "filter";
|
|
13
|
+
key: string;
|
|
14
|
+
value: Literal;
|
|
15
|
+
};
|
|
16
|
+
export declare function parseCidPath(expression: string, limits?: Partial<PayloadLimits>): readonly CidPathStep[];
|
|
17
|
+
export declare function formatCidPath(steps: readonly CidPathStep[]): string;
|
|
18
|
+
export declare function locate(data: JsonValue, steps: readonly CidPathStep[], budget: Budget): Map<string, JsonValue>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA8B,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAEpG,KAAK,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAChD,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAEpD,wBAAgB,YAAY,CAC1B,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,OAAO,CAAC,aAAa,CAAM,GAClC,SAAS,WAAW,EAAE,CA6FxB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAcnE;AAED,wBAAgB,MAAM,CACpB,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,MAAM,EAAE,MAAM,GACb,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAqCxB"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { Budget, propertyPath, validUnicode } from "./value.js";
|
|
2
|
+
export function parseCidPath(expression, limits = {}) {
|
|
3
|
+
const budget = new Budget(limits);
|
|
4
|
+
if (typeof expression !== "string" ||
|
|
5
|
+
expression.length > budget.limits.maxPathLength ||
|
|
6
|
+
expression[0] !== "$")
|
|
7
|
+
throw new Error("Invalid CID path.");
|
|
8
|
+
let offset = 1;
|
|
9
|
+
const steps = [];
|
|
10
|
+
const fail = () => {
|
|
11
|
+
throw new Error("Unsupported CID path syntax.");
|
|
12
|
+
};
|
|
13
|
+
const take = (text) => {
|
|
14
|
+
if (!expression.startsWith(text, offset))
|
|
15
|
+
fail();
|
|
16
|
+
offset += text.length;
|
|
17
|
+
};
|
|
18
|
+
const string = () => {
|
|
19
|
+
const quote = expression[offset++];
|
|
20
|
+
if (quote !== '"' && quote !== "'")
|
|
21
|
+
fail();
|
|
22
|
+
let result = "";
|
|
23
|
+
while (offset < expression.length) {
|
|
24
|
+
const char = expression[offset++];
|
|
25
|
+
if (char === quote) {
|
|
26
|
+
if (!validUnicode(result))
|
|
27
|
+
fail();
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
if (char.charCodeAt(0) < 32)
|
|
31
|
+
fail();
|
|
32
|
+
if (char !== "\\") {
|
|
33
|
+
result += char;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const escaped = expression[offset++];
|
|
37
|
+
if (escaped === "'" || escaped === '"' || escaped === "\\")
|
|
38
|
+
result += escaped;
|
|
39
|
+
else if (escaped === "u") {
|
|
40
|
+
const hex = expression.slice(offset, offset + 4);
|
|
41
|
+
if (!/^[\da-f]{4}$/i.test(hex))
|
|
42
|
+
fail();
|
|
43
|
+
result += String.fromCharCode(Number.parseInt(hex, 16));
|
|
44
|
+
offset += 4;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const escapes = {
|
|
48
|
+
"/": "/",
|
|
49
|
+
b: "\b",
|
|
50
|
+
f: "\f",
|
|
51
|
+
n: "\n",
|
|
52
|
+
r: "\r",
|
|
53
|
+
t: "\t",
|
|
54
|
+
};
|
|
55
|
+
if (!escaped || !Object.hasOwn(escapes, escaped))
|
|
56
|
+
fail();
|
|
57
|
+
result += escapes[escaped];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return fail();
|
|
61
|
+
};
|
|
62
|
+
while (offset < expression.length) {
|
|
63
|
+
budget.visit(steps.length + 1);
|
|
64
|
+
take("[");
|
|
65
|
+
if (expression.startsWith("?@", offset)) {
|
|
66
|
+
take("?@[");
|
|
67
|
+
const key = string();
|
|
68
|
+
take("]");
|
|
69
|
+
while (expression[offset] === " ")
|
|
70
|
+
offset++;
|
|
71
|
+
take("==");
|
|
72
|
+
while (expression[offset] === " ")
|
|
73
|
+
offset++;
|
|
74
|
+
let value;
|
|
75
|
+
if (expression[offset] === '"' || expression[offset] === "'")
|
|
76
|
+
value = string();
|
|
77
|
+
else {
|
|
78
|
+
const literal = /^(?:true|false|null|-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?)/.exec(expression.slice(offset))?.[0];
|
|
79
|
+
if (!literal)
|
|
80
|
+
fail();
|
|
81
|
+
value = JSON.parse(literal);
|
|
82
|
+
if (typeof value === "number" && (!Number.isFinite(value) || Object.is(value, -0)))
|
|
83
|
+
fail();
|
|
84
|
+
offset += literal.length;
|
|
85
|
+
}
|
|
86
|
+
take("]");
|
|
87
|
+
steps.push({ kind: "filter", key, value });
|
|
88
|
+
}
|
|
89
|
+
else if (expression[offset] === "*") {
|
|
90
|
+
take("*]");
|
|
91
|
+
steps.push({ kind: "wildcard" });
|
|
92
|
+
}
|
|
93
|
+
else if (expression[offset] === "'" || expression[offset] === '"') {
|
|
94
|
+
const key = string();
|
|
95
|
+
take("]");
|
|
96
|
+
steps.push({ kind: "property", key });
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
const value = /^(?:0|[1-9]\d*)/.exec(expression.slice(offset))?.[0];
|
|
100
|
+
if (!value || !Number.isSafeInteger(Number(value)))
|
|
101
|
+
fail();
|
|
102
|
+
offset += value.length;
|
|
103
|
+
take("]");
|
|
104
|
+
steps.push({ kind: "index", index: Number(value) });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return steps;
|
|
108
|
+
}
|
|
109
|
+
export function formatCidPath(steps) {
|
|
110
|
+
return steps.reduce((path, step) => {
|
|
111
|
+
switch (step.kind) {
|
|
112
|
+
case "property":
|
|
113
|
+
return propertyPath(path, step.key);
|
|
114
|
+
case "index":
|
|
115
|
+
return `${path}[${step.index}]`;
|
|
116
|
+
case "wildcard":
|
|
117
|
+
return `${path}[*]`;
|
|
118
|
+
case "filter":
|
|
119
|
+
return `${path}[?@[${JSON.stringify(step.key)}] == ${JSON.stringify(step.value)}]`;
|
|
120
|
+
}
|
|
121
|
+
throw new Error("Unsupported CID path step.");
|
|
122
|
+
}, "$");
|
|
123
|
+
}
|
|
124
|
+
export function locate(data, steps, budget) {
|
|
125
|
+
let matches = new Map([["$", data]]);
|
|
126
|
+
for (const step of steps) {
|
|
127
|
+
const next = new Map();
|
|
128
|
+
for (const [path, value] of matches) {
|
|
129
|
+
budget.visit();
|
|
130
|
+
if (step.kind === "property") {
|
|
131
|
+
if (value &&
|
|
132
|
+
typeof value === "object" &&
|
|
133
|
+
!Array.isArray(value) &&
|
|
134
|
+
Object.hasOwn(value, step.key))
|
|
135
|
+
next.set(propertyPath(path, step.key), value[step.key]);
|
|
136
|
+
}
|
|
137
|
+
else if (Array.isArray(value)) {
|
|
138
|
+
if (step.kind === "index") {
|
|
139
|
+
if (step.index < value.length)
|
|
140
|
+
next.set(`${path}[${step.index}]`, value[step.index]);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
for (let i = 0; i < value.length; i++) {
|
|
144
|
+
budget.visit();
|
|
145
|
+
const item = value[i];
|
|
146
|
+
if (step.kind === "wildcard" ||
|
|
147
|
+
(item !== null &&
|
|
148
|
+
typeof item === "object" &&
|
|
149
|
+
!Array.isArray(item) &&
|
|
150
|
+
Object.hasOwn(item, step.key) &&
|
|
151
|
+
item[step.key] === step.value))
|
|
152
|
+
next.set(`${path}[${i}]`, item);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
matches = next;
|
|
158
|
+
}
|
|
159
|
+
return matches;
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Kind, type TSchema } from "@sinclair/typebox";
|
|
2
|
+
import { ContentRef } from "./content-ref.js";
|
|
3
|
+
export { ContentRef } from "./content-ref.js";
|
|
4
|
+
export interface TContentRef extends TSchema {
|
|
5
|
+
[Kind]: "ContentRef";
|
|
6
|
+
static: ContentRef;
|
|
7
|
+
type: "string";
|
|
8
|
+
"x-ipfs-content-ref": true;
|
|
9
|
+
}
|
|
10
|
+
/** The JSON keyword survives contract serialization; Kind preserves author-side inference. */
|
|
11
|
+
export declare function ContentRefSchema(options?: {
|
|
12
|
+
title?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
}): TContentRef;
|
|
15
|
+
//# sourceMappingURL=reference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reference.d.ts","sourceRoot":"","sources":["../src/reference.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,WAAW,WAAY,SAAQ,OAAO;IAC1C,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,QAAQ,CAAC;IACf,oBAAoB,EAAE,IAAI,CAAC;CAC5B;AAED,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACrD,WAAW,CAOb"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Kind, TypeRegistry } from "@sinclair/typebox";
|
|
2
|
+
import { ContentRef } from "./content-ref.js";
|
|
3
|
+
export { ContentRef } from "./content-ref.js";
|
|
4
|
+
/** The JSON keyword survives contract serialization; Kind preserves author-side inference. */
|
|
5
|
+
export function ContentRefSchema(options = {}) {
|
|
6
|
+
return {
|
|
7
|
+
...options,
|
|
8
|
+
[Kind]: "ContentRef",
|
|
9
|
+
type: "string",
|
|
10
|
+
"x-ipfs-content-ref": true,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
TypeRegistry.Set("ContentRef", (_schema, value) => value instanceof ContentRef);
|
|
14
|
+
//# sourceMappingURL=reference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reference.js","sourceRoot":"","sources":["../src/reference.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,YAAY,EAAgB,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAS9C,8FAA8F;AAC9F,MAAM,UAAU,gBAAgB,CAC9B,UAAoD,EAAE;IAEtD,OAAO;QACL,GAAG,OAAO;QACV,CAAC,IAAI,CAAC,EAAE,YAAY;QACpB,IAAI,EAAE,QAAQ;QACd,oBAAoB,EAAE,IAAI;KACZ,CAAC;AACnB,CAAC;AAED,YAAY,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,YAAY,UAAU,CAAC,CAAC"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAA0B,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AA6C5E,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM;;;EAoM5E"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { Ajv } from "ajv";
|
|
2
|
+
import { CID } from "multiformats/cid";
|
|
3
|
+
import { Budget, propertyPath, snapshot } from "./value.js";
|
|
4
|
+
const keywords = new Set([
|
|
5
|
+
"$schema",
|
|
6
|
+
"$id",
|
|
7
|
+
"title",
|
|
8
|
+
"description",
|
|
9
|
+
"default",
|
|
10
|
+
"examples",
|
|
11
|
+
"type",
|
|
12
|
+
"anyOf",
|
|
13
|
+
"const",
|
|
14
|
+
"enum",
|
|
15
|
+
"properties",
|
|
16
|
+
"required",
|
|
17
|
+
"additionalProperties",
|
|
18
|
+
"items",
|
|
19
|
+
"additionalItems",
|
|
20
|
+
"minItems",
|
|
21
|
+
"maxItems",
|
|
22
|
+
"uniqueItems",
|
|
23
|
+
"minProperties",
|
|
24
|
+
"maxProperties",
|
|
25
|
+
"minimum",
|
|
26
|
+
"maximum",
|
|
27
|
+
"exclusiveMinimum",
|
|
28
|
+
"exclusiveMaximum",
|
|
29
|
+
"multipleOf",
|
|
30
|
+
"minLength",
|
|
31
|
+
"maxLength",
|
|
32
|
+
"pattern",
|
|
33
|
+
"x-ipfs-content-ref",
|
|
34
|
+
]);
|
|
35
|
+
export function inspectSchema(input, data, budget) {
|
|
36
|
+
const root = snapshot(input, budget, undefined, true);
|
|
37
|
+
budget.bytes(root);
|
|
38
|
+
const discriminators = new Map();
|
|
39
|
+
const references = new Map();
|
|
40
|
+
const ajv = new Ajv({ strict: true, strictTuples: false, allErrors: false, ownProperties: true });
|
|
41
|
+
ajv.addKeyword({
|
|
42
|
+
keyword: "x-ipfs-content-ref",
|
|
43
|
+
schemaType: "boolean",
|
|
44
|
+
validate: (enabled, value) => {
|
|
45
|
+
if (!enabled || typeof value !== "string")
|
|
46
|
+
return false;
|
|
47
|
+
try {
|
|
48
|
+
CID.parse(value);
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
errors: false,
|
|
56
|
+
});
|
|
57
|
+
if (!ajv.validateSchema(root))
|
|
58
|
+
throw new Error("Invalid payload schema.");
|
|
59
|
+
const inspect = (schema, depth) => {
|
|
60
|
+
budget.visit(depth);
|
|
61
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema))
|
|
62
|
+
throw new Error("Expected a supported object schema.");
|
|
63
|
+
for (const key of Object.keys(schema))
|
|
64
|
+
if (!keywords.has(key))
|
|
65
|
+
throw new Error(`Unsupported payload schema keyword: ${key}.`);
|
|
66
|
+
if (schema.type !== undefined && typeof schema.type !== "string")
|
|
67
|
+
throw new Error("Use explicit union schemas.");
|
|
68
|
+
if (Object.hasOwn(schema, "x-ipfs-content-ref")) {
|
|
69
|
+
if (schema["x-ipfs-content-ref"] !== true ||
|
|
70
|
+
schema.type !== "string" ||
|
|
71
|
+
Object.keys(schema).some((key) => !["type", "x-ipfs-content-ref", "title", "description"].includes(key)))
|
|
72
|
+
throw new Error("Invalid ContentRef schema.");
|
|
73
|
+
references.set(schema, true);
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
let hasRefs = false;
|
|
77
|
+
for (const child of Object.values(schema.properties ?? {}))
|
|
78
|
+
hasRefs = inspect(child, depth + 1) || hasRefs;
|
|
79
|
+
if (schema.items)
|
|
80
|
+
for (const child of Array.isArray(schema.items) ? schema.items : [schema.items])
|
|
81
|
+
hasRefs = inspect(child, depth + 1) || hasRefs;
|
|
82
|
+
if (schema.additionalItems && typeof schema.additionalItems === "object")
|
|
83
|
+
throw new Error("Schema-valued additionalItems are unsupported; use a homogeneous array.");
|
|
84
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === "object")
|
|
85
|
+
hasRefs = inspect(schema.additionalProperties, depth + 1) || hasRefs;
|
|
86
|
+
if (schema.anyOf) {
|
|
87
|
+
let unionRefs = false;
|
|
88
|
+
for (const branch of schema.anyOf)
|
|
89
|
+
unionRefs = inspect(branch, depth + 1) || unionRefs;
|
|
90
|
+
if (unionRefs) {
|
|
91
|
+
const first = schema.anyOf[0];
|
|
92
|
+
const key = Object.keys(first.properties ?? {}).find((key) => {
|
|
93
|
+
const literals = new Set();
|
|
94
|
+
for (const branch of schema.anyOf) {
|
|
95
|
+
const property = branch.properties?.[key];
|
|
96
|
+
if (branch.type !== "object" ||
|
|
97
|
+
!branch.required?.includes(key) ||
|
|
98
|
+
!property ||
|
|
99
|
+
!Object.hasOwn(property, "const") ||
|
|
100
|
+
(property.const !== null && typeof property.const === "object") ||
|
|
101
|
+
property["x-ipfs-content-ref"] ||
|
|
102
|
+
branch.anyOf)
|
|
103
|
+
return false;
|
|
104
|
+
const literal = JSON.stringify(property.const);
|
|
105
|
+
if (literals.has(literal))
|
|
106
|
+
return false;
|
|
107
|
+
literals.add(literal);
|
|
108
|
+
}
|
|
109
|
+
return true;
|
|
110
|
+
});
|
|
111
|
+
if (!key)
|
|
112
|
+
throw new Error("Reference unions require a unique required literal discriminator.");
|
|
113
|
+
discriminators.set(schema, key);
|
|
114
|
+
}
|
|
115
|
+
hasRefs = hasRefs || unionRefs;
|
|
116
|
+
}
|
|
117
|
+
// Sibling validation clauses can narrow a union but must not add a second reference meaning.
|
|
118
|
+
if (schema.anyOf && (schema.properties || schema.items || schema.additionalProperties))
|
|
119
|
+
throw new Error("Reference traversal does not support union structural siblings.");
|
|
120
|
+
references.set(schema, hasRefs);
|
|
121
|
+
return hasRefs;
|
|
122
|
+
};
|
|
123
|
+
inspect(root, 0);
|
|
124
|
+
const validate = ajv.compile(root);
|
|
125
|
+
if (!validate(data))
|
|
126
|
+
throw new Error(`Payload does not match schema: ${ajv.errorsText(validate.errors)}.`);
|
|
127
|
+
const expected = new Map();
|
|
128
|
+
const rules = new Set();
|
|
129
|
+
const selected = (schema, value) => {
|
|
130
|
+
const key = discriminators.get(schema);
|
|
131
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || !Object.hasOwn(value, key))
|
|
132
|
+
throw new Error("Missing payload discriminator.");
|
|
133
|
+
const branches = schema.anyOf.filter((branch) => branch.properties[key].const === value[key]);
|
|
134
|
+
if (branches.length !== 1)
|
|
135
|
+
throw new Error("Invalid or ambiguous payload discriminator.");
|
|
136
|
+
return branches[0];
|
|
137
|
+
};
|
|
138
|
+
const filter = (path, key, literal) => `${path}[?@[${JSON.stringify(key)}] == ${JSON.stringify(literal)}]`;
|
|
139
|
+
const walk = (schema, value, path, rule, depth) => {
|
|
140
|
+
budget.visit(depth);
|
|
141
|
+
if (!references.get(schema))
|
|
142
|
+
return;
|
|
143
|
+
if (schema["x-ipfs-content-ref"]) {
|
|
144
|
+
rules.add(rule);
|
|
145
|
+
if (value !== undefined)
|
|
146
|
+
expected.set(path, rule);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (schema.anyOf) {
|
|
150
|
+
const branch = value === undefined ? undefined : selected(schema, value);
|
|
151
|
+
for (const option of schema.anyOf)
|
|
152
|
+
walk(option, option === branch ? value : undefined, path, rule, depth + 1);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (schema.properties)
|
|
156
|
+
for (const [key, child] of Object.entries(schema.properties))
|
|
157
|
+
walk(child, value && typeof value === "object" && !Array.isArray(value) && Object.hasOwn(value, key)
|
|
158
|
+
? value[key]
|
|
159
|
+
: undefined, propertyPath(path, key), propertyPath(rule, key), depth + 1);
|
|
160
|
+
if (schema.additionalProperties &&
|
|
161
|
+
typeof schema.additionalProperties === "object" &&
|
|
162
|
+
value &&
|
|
163
|
+
typeof value === "object" &&
|
|
164
|
+
!Array.isArray(value))
|
|
165
|
+
for (const [key, item] of Object.entries(value))
|
|
166
|
+
if (!Object.hasOwn(schema.properties ?? {}, key))
|
|
167
|
+
walk(schema.additionalProperties, item, propertyPath(path, key), propertyPath(rule, key), depth + 1);
|
|
168
|
+
if (schema.items) {
|
|
169
|
+
if (Array.isArray(schema.items)) {
|
|
170
|
+
schema.items.forEach((item, i) => {
|
|
171
|
+
walk(item, Array.isArray(value) ? value[i] : undefined, `${path}[${i}]`, `${rule}[${i}]`, depth + 1);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
const item = schema.items;
|
|
176
|
+
const key = discriminators.get(item);
|
|
177
|
+
if (key) {
|
|
178
|
+
for (const branch of item.anyOf)
|
|
179
|
+
walk(branch, undefined, path, filter(rule, key, branch.properties[key].const), depth + 1);
|
|
180
|
+
}
|
|
181
|
+
else
|
|
182
|
+
walk(item, undefined, path, `${rule}[*]`, depth + 1);
|
|
183
|
+
if (Array.isArray(value))
|
|
184
|
+
value.forEach((child, i) => {
|
|
185
|
+
const branch = key ? selected(item, child) : item;
|
|
186
|
+
walk(branch, child, `${path}[${i}]`, key ? filter(rule, key, branch.properties[key].const) : `${rule}[*]`, depth + 1);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
walk(root, data, "$", "$", 0);
|
|
192
|
+
if (rules.size > budget.limits.maxPaths)
|
|
193
|
+
throw new Error("Schema reference path capacity exceeded.");
|
|
194
|
+
return { expected, rules };
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=schema.js.map
|