@kindgi/schema 0.0.0-bootstrap.0 → 0.1.1
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 +201 -0
- package/README.md +52 -2
- package/SPEC.md +120 -0
- package/dist/canonical.d.ts +27 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +55 -0
- package/dist/canonical.js.map +1 -0
- package/dist/errors.d.ts +68 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +4 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/registry.d.ts +86 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +261 -0
- package/dist/registry.js.map +1 -0
- package/dist/version.d.ts +30 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +70 -0
- package/dist/version.js.map +1 -0
- package/dist/zod.d.ts +154 -0
- package/dist/zod.d.ts.map +1 -0
- package/dist/zod.js +216 -0
- package/dist/zod.js.map +1 -0
- package/package.json +61 -4
- package/src/canonical.ts +52 -0
- package/src/errors.ts +82 -0
- package/src/index.ts +36 -0
- package/src/registry.test.ts +221 -0
- package/src/registry.ts +347 -0
- package/src/version.test.ts +114 -0
- package/src/version.ts +93 -0
- package/src/zod.ts +313 -0
- package/type-manifest.json +101 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { Result } from '@kindgi/types';
|
|
2
|
+
import type { SchemaError } from './errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* A registry of loaded and compiled JSON Schemas, keyed by `$id`.
|
|
5
|
+
*
|
|
6
|
+
* The registry pre-compiles a validator for every schema at construction time,
|
|
7
|
+
* so `validate()` is a hot-path operation with no per-call compilation cost.
|
|
8
|
+
* Cross-schema `$ref`s (e.g. pack manifest → tool schema) are resolved
|
|
9
|
+
* automatically because all schemas are registered before compilation.
|
|
10
|
+
*/
|
|
11
|
+
export interface SpecRegistry {
|
|
12
|
+
/**
|
|
13
|
+
* Validate `data` against the schema with the given `$id`.
|
|
14
|
+
*
|
|
15
|
+
* The generic `T` is a caller-asserted type — the runtime does not verify
|
|
16
|
+
* it beyond schema conformance. Consumers pair the `$id` with a manually
|
|
17
|
+
* maintained TypeScript type (or, later, a codegen'd one).
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const r = registry.validate<Flow>('https://kindgi.com/schemas/v1/flow.schema.json', input);
|
|
21
|
+
* if (r.kind === 'ok') { runOnGraph(r.value); }
|
|
22
|
+
*/
|
|
23
|
+
validate<T = unknown>(id: string, data: unknown): Result<T, SchemaError>;
|
|
24
|
+
/** Retrieve the raw parsed schema JSON registered at `$id`. */
|
|
25
|
+
getSchema(id: string): Result<unknown, SchemaError>;
|
|
26
|
+
/** Return every registered schema `$id` in insertion order. */
|
|
27
|
+
ids(): readonly string[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build a SpecRegistry from an array of already-parsed schema documents.
|
|
31
|
+
*
|
|
32
|
+
* All schemas are registered with the Ajv instance FIRST (so cross-schema
|
|
33
|
+
* `$ref`s can resolve), then validators are compiled and cached.
|
|
34
|
+
*
|
|
35
|
+
* Returns `err` on the first failure — this is fail-fast on purpose. If a
|
|
36
|
+
* spec is broken, downstream validators are meaningless.
|
|
37
|
+
*/
|
|
38
|
+
export declare function createSpecRegistry(schemas: readonly unknown[]): Result<SpecRegistry, SchemaError>;
|
|
39
|
+
/**
|
|
40
|
+
* A compiled inline JSON Schema. Unlike `SpecRegistry`, which stores schemas
|
|
41
|
+
* addressed by `$id`, this represents a single anonymous schema (e.g. a loop
|
|
42
|
+
* node's `outputSchema`) whose validator has already been compiled.
|
|
43
|
+
*
|
|
44
|
+
* Callers compile once (at flow load time) and validate many times (each
|
|
45
|
+
* loop iteration).
|
|
46
|
+
*/
|
|
47
|
+
export interface CompiledInlineSchema {
|
|
48
|
+
/**
|
|
49
|
+
* Validate `data`. Returns the original value on success (typed as `T`
|
|
50
|
+
* for caller convenience — the runtime does not verify the T assertion
|
|
51
|
+
* beyond schema conformance).
|
|
52
|
+
*/
|
|
53
|
+
validate<T = unknown>(data: unknown): Result<T, ValidationErrorLike>;
|
|
54
|
+
/** The raw schema JSON, for round-tripping or debugging. */
|
|
55
|
+
readonly source: unknown;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Structural shape of a validation failure, decoupled from the `SchemaError`
|
|
59
|
+
* discriminated union (which requires an `id`). Consumers that want to
|
|
60
|
+
* surface an inline-schema validation failure typically wrap this in their
|
|
61
|
+
* own domain error.
|
|
62
|
+
*/
|
|
63
|
+
export interface ValidationErrorLike {
|
|
64
|
+
readonly code: 'validation-error';
|
|
65
|
+
readonly message: string;
|
|
66
|
+
readonly errors: readonly unknown[];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Compile a single anonymous JSON Schema (draft 2020-12) into a reusable
|
|
70
|
+
* validator. Returns `err` if the schema itself is malformed (Ajv rejects
|
|
71
|
+
* it), which is how the flow loader surfaces `LoopOutputSchemaError` and
|
|
72
|
+
* similar load-time diagnostics.
|
|
73
|
+
*
|
|
74
|
+
* Design note: this is intentionally decoupled from `SpecRegistry` — inline
|
|
75
|
+
* schemas don't have a `$id` and don't need cross-schema `$ref` resolution.
|
|
76
|
+
*/
|
|
77
|
+
export declare function compileInlineSchema(schema: unknown): Result<CompiledInlineSchema, SchemaError>;
|
|
78
|
+
/**
|
|
79
|
+
* Load a SpecRegistry from a directory of `*.schema.json` files.
|
|
80
|
+
*
|
|
81
|
+
* Reads every `*.schema.json` in the directory (non-recursive), parses each,
|
|
82
|
+
* and delegates to `createSpecRegistry`. Files are loaded in sorted order for
|
|
83
|
+
* deterministic behavior across environments.
|
|
84
|
+
*/
|
|
85
|
+
export declare function loadSpecRegistry(dir: string): Promise<Result<SpecRegistry, SchemaError>>;
|
|
86
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAY/C;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IAEzE,+DAA+D;IAC/D,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAEpD,+DAA+D;IAC/D,GAAG,IAAI,SAAS,MAAM,EAAE,CAAC;CAC1B;AA2ED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CAAC,YAAY,EAAE,WAAW,CAAC,CAiEjG;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC;IACrE,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC;CACrC;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,oBAAoB,EAAE,WAAW,CAAC,CA0C9F;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC,CAmD9F"}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (C) 2026 Kindgi Inc.
|
|
3
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import * as addFormatsModule from 'ajv-formats';
|
|
6
|
+
// Ajv 8's `/dist/2020` entry exports the Ajv2020 class as a named export.
|
|
7
|
+
// The named-import form is stable across ESM/CJS/bundler interop; the default form is not.
|
|
8
|
+
import { Ajv2020 } from 'ajv/dist/2020.js';
|
|
9
|
+
const addFormatsRaw = addFormatsModule;
|
|
10
|
+
const addFormats = typeof addFormatsRaw === 'function'
|
|
11
|
+
? addFormatsRaw
|
|
12
|
+
: addFormatsRaw.default;
|
|
13
|
+
function notFound(id) {
|
|
14
|
+
return {
|
|
15
|
+
code: 'schema-not-found',
|
|
16
|
+
message: `No schema registered with $id: ${id}`,
|
|
17
|
+
id,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function makeRegistry(state) {
|
|
21
|
+
return {
|
|
22
|
+
validate(id, data) {
|
|
23
|
+
const validator = state.validators.get(id);
|
|
24
|
+
if (validator === undefined) {
|
|
25
|
+
return { kind: 'err', error: notFound(id) };
|
|
26
|
+
}
|
|
27
|
+
if (validator(data)) {
|
|
28
|
+
return { kind: 'ok', value: data };
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
kind: 'err',
|
|
32
|
+
error: {
|
|
33
|
+
code: 'validation-error',
|
|
34
|
+
message: `Data does not validate against ${id}`,
|
|
35
|
+
id,
|
|
36
|
+
errors: validator.errors ?? [],
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
getSchema(id) {
|
|
41
|
+
const schema = state.schemas.get(id);
|
|
42
|
+
if (schema === undefined) {
|
|
43
|
+
return { kind: 'err', error: notFound(id) };
|
|
44
|
+
}
|
|
45
|
+
return { kind: 'ok', value: schema };
|
|
46
|
+
},
|
|
47
|
+
ids() {
|
|
48
|
+
return Array.from(state.schemas.keys());
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function extractId(schema) {
|
|
53
|
+
if (typeof schema !== 'object' || schema === null || !('$id' in schema)) {
|
|
54
|
+
return {
|
|
55
|
+
kind: 'err',
|
|
56
|
+
error: {
|
|
57
|
+
code: 'schema-compile-error',
|
|
58
|
+
message: 'Schema is missing top-level $id',
|
|
59
|
+
id: '<unknown>',
|
|
60
|
+
cause: schema,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const id = schema.$id;
|
|
65
|
+
if (typeof id !== 'string' || id.length === 0) {
|
|
66
|
+
return {
|
|
67
|
+
kind: 'err',
|
|
68
|
+
error: {
|
|
69
|
+
code: 'schema-compile-error',
|
|
70
|
+
message: 'Schema $id is not a non-empty string',
|
|
71
|
+
id: String(id),
|
|
72
|
+
cause: schema,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return { kind: 'ok', value: id };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Build a SpecRegistry from an array of already-parsed schema documents.
|
|
80
|
+
*
|
|
81
|
+
* All schemas are registered with the Ajv instance FIRST (so cross-schema
|
|
82
|
+
* `$ref`s can resolve), then validators are compiled and cached.
|
|
83
|
+
*
|
|
84
|
+
* Returns `err` on the first failure — this is fail-fast on purpose. If a
|
|
85
|
+
* spec is broken, downstream validators are meaningless.
|
|
86
|
+
*/
|
|
87
|
+
export function createSpecRegistry(schemas) {
|
|
88
|
+
const ajv = new Ajv2020({
|
|
89
|
+
strict: true,
|
|
90
|
+
allErrors: true,
|
|
91
|
+
allowUnionTypes: false,
|
|
92
|
+
});
|
|
93
|
+
addFormats(ajv);
|
|
94
|
+
const schemaMap = new Map();
|
|
95
|
+
// Pass 1: register every schema so $refs can resolve during compilation.
|
|
96
|
+
for (const schema of schemas) {
|
|
97
|
+
const idResult = extractId(schema);
|
|
98
|
+
if (idResult.kind === 'err') {
|
|
99
|
+
return idResult;
|
|
100
|
+
}
|
|
101
|
+
const id = idResult.value;
|
|
102
|
+
try {
|
|
103
|
+
ajv.addSchema(schema, id);
|
|
104
|
+
schemaMap.set(id, schema);
|
|
105
|
+
}
|
|
106
|
+
catch (cause) {
|
|
107
|
+
return {
|
|
108
|
+
kind: 'err',
|
|
109
|
+
error: {
|
|
110
|
+
code: 'schema-compile-error',
|
|
111
|
+
message: `Failed to register schema with $id ${id}`,
|
|
112
|
+
id,
|
|
113
|
+
cause,
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Pass 2: compile validators, now that cross-refs resolve.
|
|
119
|
+
const validators = new Map();
|
|
120
|
+
for (const id of schemaMap.keys()) {
|
|
121
|
+
let validator;
|
|
122
|
+
try {
|
|
123
|
+
validator = ajv.getSchema(id);
|
|
124
|
+
}
|
|
125
|
+
catch (cause) {
|
|
126
|
+
return {
|
|
127
|
+
kind: 'err',
|
|
128
|
+
error: {
|
|
129
|
+
code: 'schema-compile-error',
|
|
130
|
+
message: `Failed to compile validator for $id ${id}`,
|
|
131
|
+
id,
|
|
132
|
+
cause,
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (validator === undefined) {
|
|
137
|
+
return {
|
|
138
|
+
kind: 'err',
|
|
139
|
+
error: {
|
|
140
|
+
code: 'schema-compile-error',
|
|
141
|
+
message: `Ajv did not return a validator for $id ${id}`,
|
|
142
|
+
id,
|
|
143
|
+
cause: null,
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
validators.set(id, validator);
|
|
148
|
+
}
|
|
149
|
+
return { kind: 'ok', value: makeRegistry({ schemas: schemaMap, validators }) };
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Compile a single anonymous JSON Schema (draft 2020-12) into a reusable
|
|
153
|
+
* validator. Returns `err` if the schema itself is malformed (Ajv rejects
|
|
154
|
+
* it), which is how the flow loader surfaces `LoopOutputSchemaError` and
|
|
155
|
+
* similar load-time diagnostics.
|
|
156
|
+
*
|
|
157
|
+
* Design note: this is intentionally decoupled from `SpecRegistry` — inline
|
|
158
|
+
* schemas don't have a `$id` and don't need cross-schema `$ref` resolution.
|
|
159
|
+
*/
|
|
160
|
+
export function compileInlineSchema(schema) {
|
|
161
|
+
const ajv = new Ajv2020({
|
|
162
|
+
strict: true,
|
|
163
|
+
allErrors: true,
|
|
164
|
+
allowUnionTypes: false,
|
|
165
|
+
});
|
|
166
|
+
addFormats(ajv);
|
|
167
|
+
let validator;
|
|
168
|
+
try {
|
|
169
|
+
validator = ajv.compile(schema);
|
|
170
|
+
}
|
|
171
|
+
catch (cause) {
|
|
172
|
+
return {
|
|
173
|
+
kind: 'err',
|
|
174
|
+
error: {
|
|
175
|
+
code: 'schema-compile-error',
|
|
176
|
+
message: `Inline schema failed to compile: ${cause?.message ?? String(cause)}`,
|
|
177
|
+
id: '<inline>',
|
|
178
|
+
cause,
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
kind: 'ok',
|
|
184
|
+
value: {
|
|
185
|
+
source: schema,
|
|
186
|
+
validate(data) {
|
|
187
|
+
if (validator(data)) {
|
|
188
|
+
return { kind: 'ok', value: data };
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
kind: 'err',
|
|
192
|
+
error: {
|
|
193
|
+
code: 'validation-error',
|
|
194
|
+
message: 'Data does not validate against inline schema',
|
|
195
|
+
errors: validator.errors ?? [],
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Load a SpecRegistry from a directory of `*.schema.json` files.
|
|
204
|
+
*
|
|
205
|
+
* Reads every `*.schema.json` in the directory (non-recursive), parses each,
|
|
206
|
+
* and delegates to `createSpecRegistry`. Files are loaded in sorted order for
|
|
207
|
+
* deterministic behavior across environments.
|
|
208
|
+
*/
|
|
209
|
+
export async function loadSpecRegistry(dir) {
|
|
210
|
+
let entries;
|
|
211
|
+
try {
|
|
212
|
+
entries = await readdir(dir);
|
|
213
|
+
}
|
|
214
|
+
catch (cause) {
|
|
215
|
+
return {
|
|
216
|
+
kind: 'err',
|
|
217
|
+
error: {
|
|
218
|
+
code: 'schema-load-error',
|
|
219
|
+
message: `Cannot read specs directory: ${dir}`,
|
|
220
|
+
path: dir,
|
|
221
|
+
cause,
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
const files = entries.filter((n) => n.endsWith('.schema.json')).sort();
|
|
226
|
+
const schemas = [];
|
|
227
|
+
for (const file of files) {
|
|
228
|
+
const fullPath = join(dir, file);
|
|
229
|
+
let raw;
|
|
230
|
+
try {
|
|
231
|
+
raw = await readFile(fullPath, 'utf-8');
|
|
232
|
+
}
|
|
233
|
+
catch (cause) {
|
|
234
|
+
return {
|
|
235
|
+
kind: 'err',
|
|
236
|
+
error: {
|
|
237
|
+
code: 'schema-load-error',
|
|
238
|
+
message: `Cannot read schema file: ${fullPath}`,
|
|
239
|
+
path: fullPath,
|
|
240
|
+
cause,
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
schemas.push(JSON.parse(raw));
|
|
246
|
+
}
|
|
247
|
+
catch (cause) {
|
|
248
|
+
return {
|
|
249
|
+
kind: 'err',
|
|
250
|
+
error: {
|
|
251
|
+
code: 'schema-parse-error',
|
|
252
|
+
message: `Invalid JSON in schema file: ${fullPath}`,
|
|
253
|
+
path: fullPath,
|
|
254
|
+
cause,
|
|
255
|
+
},
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return createSpecRegistry(schemas);
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Result, SchemaMajor, Semver } from '@kindgi/types';
|
|
2
|
+
import type { SchemaError } from './errors.js';
|
|
3
|
+
/** Parsed version information from a schema's `$id` and `$comment`. */
|
|
4
|
+
export interface SchemaVersion {
|
|
5
|
+
/** Major version, parsed from the `$id` URL path segment (e.g. `v1` → 1). */
|
|
6
|
+
readonly major: SchemaMajor;
|
|
7
|
+
/** Full semver, parsed from `$comment: "schema-version: X.Y.Z"`. */
|
|
8
|
+
readonly semver: Semver;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Extract the schema version from a schema document.
|
|
12
|
+
*
|
|
13
|
+
* Requires BOTH:
|
|
14
|
+
* - A `$id` matching `https://kindgi.com/schemas/v<N>/<name>.schema.json`.
|
|
15
|
+
* - A `$comment: "schema-version: X.Y.Z"` line (semver, with optional prerelease).
|
|
16
|
+
*
|
|
17
|
+
* The major version comes from `$id`; the full semver comes from `$comment`.
|
|
18
|
+
* A mismatch between them (e.g. `$id` says `v2` but comment says `1.0.0`) is
|
|
19
|
+
* NOT detected here — that's a separate lint responsibility.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // SPECS_SCHEMAS_DIR from '@kindgi/specs'
|
|
23
|
+
* const schema = JSON.parse(await readFile(join(SPECS_SCHEMAS_DIR, 'flow.schema.json'), 'utf-8'));
|
|
24
|
+
* const result = versionOf(schema);
|
|
25
|
+
* if (result.kind === 'ok') {
|
|
26
|
+
* console.log(result.value.major, result.value.semver);
|
|
27
|
+
* }
|
|
28
|
+
*/
|
|
29
|
+
export declare function versionOf(schema: unknown): Result<SchemaVersion, SchemaError>;
|
|
30
|
+
//# sourceMappingURL=version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,oEAAoE;IACpE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AASD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,aAAa,EAAE,WAAW,CAAC,CAmD7E"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (C) 2026 Kindgi Inc.
|
|
3
|
+
const ID_PATTERN = /^https:\/\/kindgi\.com\/schemas\/v(\d+)\/([a-z][a-z0-9-]*)\.schema\.json$/;
|
|
4
|
+
const COMMENT_PATTERN = /^schema-version: (\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)$/;
|
|
5
|
+
function compileError(id, message, cause = null) {
|
|
6
|
+
return { code: 'schema-compile-error', message, id, cause };
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Extract the schema version from a schema document.
|
|
10
|
+
*
|
|
11
|
+
* Requires BOTH:
|
|
12
|
+
* - A `$id` matching `https://kindgi.com/schemas/v<N>/<name>.schema.json`.
|
|
13
|
+
* - A `$comment: "schema-version: X.Y.Z"` line (semver, with optional prerelease).
|
|
14
|
+
*
|
|
15
|
+
* The major version comes from `$id`; the full semver comes from `$comment`.
|
|
16
|
+
* A mismatch between them (e.g. `$id` says `v2` but comment says `1.0.0`) is
|
|
17
|
+
* NOT detected here — that's a separate lint responsibility.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // SPECS_SCHEMAS_DIR from '@kindgi/specs'
|
|
21
|
+
* const schema = JSON.parse(await readFile(join(SPECS_SCHEMAS_DIR, 'flow.schema.json'), 'utf-8'));
|
|
22
|
+
* const result = versionOf(schema);
|
|
23
|
+
* if (result.kind === 'ok') {
|
|
24
|
+
* console.log(result.value.major, result.value.semver);
|
|
25
|
+
* }
|
|
26
|
+
*/
|
|
27
|
+
export function versionOf(schema) {
|
|
28
|
+
if (typeof schema !== 'object' || schema === null) {
|
|
29
|
+
return { kind: 'err', error: compileError('<unknown>', 'Schema is not an object', schema) };
|
|
30
|
+
}
|
|
31
|
+
const s = schema;
|
|
32
|
+
if (typeof s.$id !== 'string' || s.$id.length === 0) {
|
|
33
|
+
return { kind: 'err', error: compileError('<unknown>', 'Schema $id is missing or empty') };
|
|
34
|
+
}
|
|
35
|
+
const idMatch = ID_PATTERN.exec(s.$id);
|
|
36
|
+
if (idMatch === null) {
|
|
37
|
+
return {
|
|
38
|
+
kind: 'err',
|
|
39
|
+
error: compileError(s.$id, `Schema $id does not match https://kindgi.com/schemas/v<N>/<name>.schema.json: ${s.$id}`),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const majorStr = idMatch[1];
|
|
43
|
+
if (majorStr === undefined) {
|
|
44
|
+
// Regex guarantees the capture, but TS narrowing requires the check.
|
|
45
|
+
return { kind: 'err', error: compileError(s.$id, 'Unreachable: $id regex captured no major') };
|
|
46
|
+
}
|
|
47
|
+
const major = Number(majorStr);
|
|
48
|
+
if (typeof s.$comment !== 'string') {
|
|
49
|
+
return {
|
|
50
|
+
kind: 'err',
|
|
51
|
+
error: compileError(s.$id, 'Schema $comment is missing (expected `schema-version: X.Y.Z`)'),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const commentMatch = COMMENT_PATTERN.exec(s.$comment);
|
|
55
|
+
if (commentMatch === null) {
|
|
56
|
+
return {
|
|
57
|
+
kind: 'err',
|
|
58
|
+
error: compileError(s.$id, `Schema $comment does not match \`schema-version: X.Y.Z\`: ${s.$comment}`),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const semverStr = commentMatch[1];
|
|
62
|
+
if (semverStr === undefined) {
|
|
63
|
+
return {
|
|
64
|
+
kind: 'err',
|
|
65
|
+
error: compileError(s.$id, 'Unreachable: $comment regex captured no semver'),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return { kind: 'ok', value: { major, semver: semverStr } };
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC;AAcjC,MAAM,UAAU,GAAG,2EAA2E,CAAC;AAC/F,MAAM,eAAe,GAAG,0EAA0E,CAAC;AAEnG,SAAS,YAAY,CAAC,EAAU,EAAE,OAAe,EAAE,QAAiB,IAAI;IACtE,OAAO,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;AAC9D,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,SAAS,CAAC,MAAe;IACvC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QAClD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,WAAW,EAAE,yBAAyB,EAAE,MAAM,CAAC,EAAE,CAAC;IAC9F,CAAC;IACD,MAAM,CAAC,GAAG,MAA+C,CAAC;IAE1D,IAAI,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,WAAW,EAAE,gCAAgC,CAAC,EAAE,CAAC;IAC7F,CAAC;IACD,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACvC,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,OAAO;YACL,IAAI,EAAE,KAAK;YACX,KAAK,EAAE,YAAY,CACjB,CAAC,CAAC,GAAG,EACL,iFAAiF,CAAC,CAAC,GAAG,EAAE,CACzF;SACF,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,qEAAqE;QACrE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,EAAE,0CAA0C,CAAC,EAAE,CAAC;IACjG,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAgB,CAAC;IAE9C,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACnC,OAAO;YACL,IAAI,EAAE,KAAK;YACX,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,EAAE,+DAA+D,CAAC;SAC5F,CAAC;IACJ,CAAC;IACD,MAAM,YAAY,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACtD,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;QAC1B,OAAO;YACL,IAAI,EAAE,KAAK;YACX,KAAK,EAAE,YAAY,CACjB,CAAC,CAAC,GAAG,EACL,6DAA6D,CAAC,CAAC,QAAQ,EAAE,CAC1E;SACF,CAAC;IACJ,CAAC;IACD,MAAM,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IAClC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO;YACL,IAAI,EAAE,KAAK;YACX,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,EAAE,gDAAgD,CAAC;SAC7E,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAmB,EAAE,EAAE,CAAC;AACvE,CAAC"}
|
package/dist/zod.d.ts
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import type { Result } from '@kindgi/types';
|
|
2
|
+
import type { InvalidZodConversionError } from './errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* Wire-authoritative JSON Schema shape. Matches the JsonSchema alias used by
|
|
5
|
+
* `@kindgi/tools` and `@kindgi/guardrails` — a Draft 2020-12 object
|
|
6
|
+
* with `type`, `properties`, etc. Kept as `Readonly<Record<string, unknown>>`
|
|
7
|
+
* here to avoid importing any consumer type.
|
|
8
|
+
*/
|
|
9
|
+
export type JSONSchemaObject = Readonly<Record<string, unknown>>;
|
|
10
|
+
/**
|
|
11
|
+
* Structural shape of a Zod v4 schema. We deliberately avoid importing
|
|
12
|
+
* `zod` at type-position here so `@kindgi/schema` keeps zero runtime OR
|
|
13
|
+
* peer dependency on Zod — the utils compile even in a workspace that
|
|
14
|
+
* never installs `zod`. Downstream packages that DO peer-depend on `zod`
|
|
15
|
+
* import `z.ZodType` themselves and pass instances through this alias.
|
|
16
|
+
*
|
|
17
|
+
* Zod v4 schemas carry `_zod` (internals) + `~standard` (Standard Schema
|
|
18
|
+
* spec adapter) at the type-level; both properties are stable across
|
|
19
|
+
* Zod v4's minor releases.
|
|
20
|
+
*/
|
|
21
|
+
export interface ZodLikeSchema {
|
|
22
|
+
readonly _zod: unknown;
|
|
23
|
+
readonly '~standard': unknown;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The alternate authoring input accepted at framework boundaries. Callers
|
|
27
|
+
* pass either a JSON Schema object (Draft 2020-12) or a Zod v4 schema.
|
|
28
|
+
*
|
|
29
|
+
* Non-TS consumers see no change — the framework converts Zod to JSON
|
|
30
|
+
* Schema at author time via `toJSONSchema`, and the wire form is always
|
|
31
|
+
* JSON Schema.
|
|
32
|
+
*/
|
|
33
|
+
export type AnySchema = JSONSchemaObject | ZodLikeSchema;
|
|
34
|
+
/**
|
|
35
|
+
* Structural detection. Returns true iff `value` looks like a Zod v4
|
|
36
|
+
* schema — `_zod` property present AND `~standard` present. Purely
|
|
37
|
+
* structural: never imports from `zod` at runtime, so the check is safe
|
|
38
|
+
* even when zod is not installed at all.
|
|
39
|
+
*
|
|
40
|
+
* The check is deliberately narrow — a JSON Schema object never has a
|
|
41
|
+
* `_zod` property, so the two authoring surfaces cannot collide.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isZodSchema(value: unknown): value is ZodLikeSchema;
|
|
44
|
+
/**
|
|
45
|
+
* Structural detection for a JSON Schema object. Cheap heuristic — accepts
|
|
46
|
+
* any object that isn't a Zod schema. JSON Schema validity (Draft 2020-12
|
|
47
|
+
* compilability) is checked separately by each consumer via Ajv.
|
|
48
|
+
*/
|
|
49
|
+
export declare function isJsonSchemaObject(value: unknown): value is JSONSchemaObject;
|
|
50
|
+
/**
|
|
51
|
+
* Author-time detection: how to interpret an `AnySchema` value. Used by
|
|
52
|
+
* downstream packages when they need to route on the authoring surface —
|
|
53
|
+
* for example, to preserve the original Zod schema for TS `z.infer<...>`
|
|
54
|
+
* while caching the converted JSON Schema for wire use.
|
|
55
|
+
*/
|
|
56
|
+
export type SchemaKind = 'zod' | 'json-schema';
|
|
57
|
+
/** Return `'zod'` for Zod schemas, `'json-schema'` for JSON Schema objects. */
|
|
58
|
+
export declare function schemaKindOf(value: AnySchema): SchemaKind;
|
|
59
|
+
/**
|
|
60
|
+
* Which side of a schema a JSON Schema describes:
|
|
61
|
+
*
|
|
62
|
+
* - `input` — what a caller may send. A field with a `.default()` is
|
|
63
|
+
* optional (the default fills it). Tool inputs, guardrail config.
|
|
64
|
+
* - `output` — what parsing produces. A defaulted field is always
|
|
65
|
+
* present. Tool outputs, an agent's typed answer.
|
|
66
|
+
*
|
|
67
|
+
* Every conversion names one: they differ exactly where Zod defaults,
|
|
68
|
+
* so the wrong one silently requires fields callers may leave out.
|
|
69
|
+
*/
|
|
70
|
+
export type SchemaIo = 'input' | 'output';
|
|
71
|
+
/**
|
|
72
|
+
* Convert an `AnySchema` to its authoritative JSON Schema wire form.
|
|
73
|
+
*
|
|
74
|
+
* - Zod schema → calls `z.toJSONSchema(schema, { io })` (Zod v4 native —
|
|
75
|
+
* no third-party `zod-to-json-schema` dependency).
|
|
76
|
+
* - JSON Schema object → returned as-is.
|
|
77
|
+
* - Anything else → `err`.
|
|
78
|
+
*
|
|
79
|
+
* Conversion failures (unrepresentable Zod types like `.transform()`,
|
|
80
|
+
* cycles without a registry, function schemas) surface as
|
|
81
|
+
* `InvalidZodConversionError` with the underlying cause preserved. No
|
|
82
|
+
* throws escape.
|
|
83
|
+
*
|
|
84
|
+
* Zod is imported dynamically the first time a Zod schema flows through:
|
|
85
|
+
* a workspace that never uses Zod never pays the import cost, and one
|
|
86
|
+
* that hasn't installed the peer dep gets a clean typed error instead of
|
|
87
|
+
* a module-resolution crash.
|
|
88
|
+
*/
|
|
89
|
+
export declare function toJSONSchema(schema: AnySchema, io: SchemaIo): Promise<Result<JSONSchemaObject, InvalidZodConversionError>>;
|
|
90
|
+
/**
|
|
91
|
+
* Synchronous variant — for defineTool / defineGuardrail sites that must
|
|
92
|
+
* stay sync. Requires the caller to have already resolved the converter
|
|
93
|
+
* (via `loadZodConverter()`) at package init. When Zod is not installed
|
|
94
|
+
* but a Zod schema is passed, returns `err` with `peer-dep-missing`
|
|
95
|
+
* distinguishable by its `cause`.
|
|
96
|
+
*/
|
|
97
|
+
export declare function toJSONSchemaSync(schema: AnySchema, converter: ZodConverter | undefined, io: SchemaIo): Result<JSONSchemaObject, InvalidZodConversionError>;
|
|
98
|
+
/**
|
|
99
|
+
* A resolved handle on `z.toJSONSchema`. Passed to `toJSONSchemaSync`
|
|
100
|
+
* from consumers that eagerly loaded the peer dep once at package init.
|
|
101
|
+
*/
|
|
102
|
+
export type ZodConverter = (schema: ZodLikeSchema, params?: {
|
|
103
|
+
readonly io?: SchemaIo;
|
|
104
|
+
}) => JSONSchemaObject;
|
|
105
|
+
/** A problem `parseWithSchema` found, as the schema reported it. */
|
|
106
|
+
export interface SchemaIssue {
|
|
107
|
+
readonly message: string;
|
|
108
|
+
readonly path?: readonly unknown[];
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Parse a value with a Zod schema through its Standard Schema interface
|
|
112
|
+
* (`'~standard'.validate`): the parsed value — defaults filled,
|
|
113
|
+
* transforms and refinements applied — or the issues. What a handler
|
|
114
|
+
* typed with `z.infer` of the schema expects to receive.
|
|
115
|
+
*/
|
|
116
|
+
export declare function parseWithSchema(schema: ZodLikeSchema, value: unknown): Promise<{
|
|
117
|
+
readonly kind: 'ok';
|
|
118
|
+
readonly value: unknown;
|
|
119
|
+
} | {
|
|
120
|
+
readonly kind: 'err';
|
|
121
|
+
readonly issues: readonly SchemaIssue[];
|
|
122
|
+
}>;
|
|
123
|
+
/**
|
|
124
|
+
* Load `z.toJSONSchema` from the `zod` peer dependency. Returns
|
|
125
|
+
* `undefined` when zod is not installed — callers decide whether that's
|
|
126
|
+
* an error or a silent no-op (JSON-Schema-only workspaces are legitimate).
|
|
127
|
+
*
|
|
128
|
+
* The result is cached — repeat calls resolve synchronously after the
|
|
129
|
+
* first.
|
|
130
|
+
*/
|
|
131
|
+
export declare function loadZodConverter(): Promise<ZodConverter | undefined>;
|
|
132
|
+
/**
|
|
133
|
+
* Synchronous variant of `loadZodConverter`. Uses Node's `createRequire`
|
|
134
|
+
* so sync authoring surfaces (`defineTool`, `defineGuardrail`) can stay
|
|
135
|
+
* sync even on their first Zod-authored call. Falls back cleanly when
|
|
136
|
+
* `zod` isn't installed: returns `undefined` and callers surface the
|
|
137
|
+
* missing peer dep as a typed error at the boundary.
|
|
138
|
+
*
|
|
139
|
+
* Runtime: Node ≥18 (both CJS and ESM entry points to zod resolve
|
|
140
|
+
* through the same `createRequire` handle). No behavior change for
|
|
141
|
+
* workspaces that never author with Zod — the first sync call to
|
|
142
|
+
* `loadZodConverterSync` returns `undefined` cheaply.
|
|
143
|
+
*/
|
|
144
|
+
export declare function loadZodConverterSync(): ZodConverter | undefined;
|
|
145
|
+
/**
|
|
146
|
+
* Test-only: reset the cached converter so tests can exercise both the
|
|
147
|
+
* peer-dep-present and peer-dep-missing branches. Not part of the public
|
|
148
|
+
* API — callers outside this package must not depend on this being
|
|
149
|
+
* present.
|
|
150
|
+
*
|
|
151
|
+
* @internal
|
|
152
|
+
*/
|
|
153
|
+
export declare function __resetZodConverterCacheForTests(): void;
|
|
154
|
+
//# sourceMappingURL=zod.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod.d.ts","sourceRoot":"","sources":["../src/zod.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAO7D;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEjE;;;;;;;;;;GAUG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG,gBAAgB,GAAG,aAAa,CAAC;AAEzD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAIlE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAI5E;AAED;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,aAAa,CAAC;AAE/C,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,CAEzD;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE1C;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,EAAE,EAAE,QAAQ,GACX,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,yBAAyB,CAAC,CAAC,CAmB9D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,YAAY,GAAG,SAAS,EACnC,EAAE,EAAE,QAAQ,GACX,MAAM,CAAC,gBAAgB,EAAE,yBAAyB,CAAC,CA6BrD;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,MAAM,EAAE,aAAa,EACrB,MAAM,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAA;CAAE,KAChC,gBAAgB,CAAC;AAEtB,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CACpC;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,OAAO,GACb,OAAO,CACN;IAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAA;CAAE,CACpE,CAkBA;AAID;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAc1E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,IAAI,YAAY,GAAG,SAAS,CAc/D;AAmBD;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,IAAI,IAAI,CAEvD"}
|