schemair 0.1.0 → 0.3.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.
Files changed (83) hide show
  1. package/README.md +542 -32
  2. package/dist/authoring/index.cjs +13 -350
  3. package/dist/authoring/index.d.cts +2 -90
  4. package/dist/authoring/index.d.ts +2 -90
  5. package/dist/authoring/index.js +2 -304
  6. package/dist/authoring-Dnrg5TXm.cjs +389 -0
  7. package/dist/authoring-DyJNYs5o.js +362 -0
  8. package/dist/chunk-bFfwrPtJ.js +18 -0
  9. package/dist/compatibility/index.cjs +43 -0
  10. package/dist/compatibility/index.d.cts +2 -0
  11. package/dist/compatibility/index.d.ts +2 -0
  12. package/dist/compatibility/index.js +42 -0
  13. package/dist/definition/index.cjs +10 -2
  14. package/dist/definition/index.d.cts +3 -21
  15. package/dist/definition/index.d.ts +3 -21
  16. package/dist/definition/index.js +2 -2
  17. package/dist/definition-BH_LzXGc.js +1115 -0
  18. package/dist/definition-BLLBpLKv.cjs +1187 -0
  19. package/dist/index-1sDuqu05.d.ts +373 -0
  20. package/dist/index-BFSMT_2d.d.ts +53 -0
  21. package/dist/index-BGz7L_Fq.d.cts +73 -0
  22. package/dist/index-BTtdqi_M.d.ts +418 -0
  23. package/dist/index-BfbClf6R.d.cts +20 -0
  24. package/dist/index-CK7Is7vy.d.cts +420 -0
  25. package/dist/index-CUGhtuwA.d.cts +53 -0
  26. package/dist/index-CV8EZQy8.d.ts +92 -0
  27. package/dist/index-CzNxjqVg.d.cts +47 -0
  28. package/dist/index-DGHMUZ5m.d.cts +92 -0
  29. package/dist/{index-eK2Xgrwp.d.ts → index-DxvfPmw6.d.ts} +13 -9
  30. package/dist/index-T6nFhvGQ.d.ts +20 -0
  31. package/dist/{index-TACcK_mi.d.cts → index-ba_52Yu9.d.cts} +13 -9
  32. package/dist/index-hrcM9oJe.d.ts +47 -0
  33. package/dist/index-i7Au-FQ6.d.cts +373 -0
  34. package/dist/index-mu1znI1F.d.ts +73 -0
  35. package/dist/index.cjs +70 -58
  36. package/dist/index.d.cts +9 -7
  37. package/dist/index.d.ts +9 -7
  38. package/dist/index.js +10 -6
  39. package/dist/integrations/json-schema/index.cjs +328 -0
  40. package/dist/integrations/json-schema/index.d.cts +53 -0
  41. package/dist/integrations/json-schema/index.d.ts +53 -0
  42. package/dist/integrations/json-schema/index.js +324 -0
  43. package/dist/integrations/standard-schema/index.cjs +32 -0
  44. package/dist/integrations/standard-schema/index.d.cts +22 -0
  45. package/dist/integrations/standard-schema/index.d.ts +22 -0
  46. package/dist/integrations/standard-schema/index.js +32 -0
  47. package/dist/payload/index.cjs +45 -82
  48. package/dist/payload/index.d.cts +2 -56
  49. package/dist/payload/index.d.ts +2 -56
  50. package/dist/payload/index.js +45 -81
  51. package/dist/relations/index.cjs +3 -4
  52. package/dist/relations/index.d.cts +2 -2
  53. package/dist/relations/index.d.ts +2 -2
  54. package/dist/relations/index.js +2 -2
  55. package/dist/{relations-CMz_0nf4.cjs → relations-NUVJkAG8.cjs} +143 -211
  56. package/dist/{relations-By0bK3UK.js → relations-QtnCRW9x.js} +140 -202
  57. package/dist/resolve/index.cjs +308 -0
  58. package/dist/resolve/index.d.cts +2 -0
  59. package/dist/resolve/index.d.ts +2 -0
  60. package/dist/resolve/index.js +305 -0
  61. package/dist/schema-ref-key-BHVFVfj1.cjs +26 -0
  62. package/dist/schema-ref-key-DR__tPr-.js +14 -0
  63. package/dist/spec/index.cjs +9 -0
  64. package/dist/spec/index.d.cts +2 -2
  65. package/dist/spec/index.d.ts +2 -2
  66. package/dist/spec/index.js +3 -1
  67. package/dist/standard/index.cjs +810 -0
  68. package/dist/standard/index.d.cts +3 -0
  69. package/dist/standard/index.d.ts +3 -0
  70. package/dist/standard/index.js +777 -0
  71. package/dist/standard-BGMgbbEQ.js +471 -0
  72. package/dist/standard-etPFZDJI.cjs +513 -0
  73. package/dist/type-interpreter/index.cjs +3 -7
  74. package/dist/type-interpreter/index.d.cts +2 -99
  75. package/dist/type-interpreter/index.d.ts +2 -99
  76. package/dist/type-interpreter/index.js +2 -2
  77. package/dist/{type-interpreter-Ck0VDhzn.js → type-interpreter-BA8gcLUU.js} +58 -560
  78. package/dist/{type-interpreter-DAIBUqKf.cjs → type-interpreter-D8xETgq1.cjs} +63 -589
  79. package/package.json +60 -5
  80. package/dist/definition-BXj3T94L.js +0 -467
  81. package/dist/definition-DSZZTz4e.cjs +0 -473
  82. package/dist/index-CEzHfht2.d.ts +0 -269
  83. package/dist/index-rzkFjgrt.d.cts +0 -269
@@ -0,0 +1,324 @@
1
+ import { i as STANDARD_CONSTRAINT_PATHS, o as STANDARD_SEMANTIC_PATHS } from "../../standard-BGMgbbEQ.js";
2
+ import { pathKey } from "../../standard/index.js";
3
+
4
+ //#region src/integrations/json-schema/index.ts
5
+ function diagnostic(context, code, message, path, severity = "warning") {
6
+ context.diagnostics.push({
7
+ code,
8
+ message,
9
+ path,
10
+ severity
11
+ });
12
+ }
13
+ function mergeKeyword(target, source) {
14
+ if (source) Object.assign(target, source);
15
+ }
16
+ function extension(target, value) {
17
+ const existing = target["x-schemair"];
18
+ target["x-schemair"] = {
19
+ ...existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {},
20
+ ...value,
21
+ version: 1
22
+ };
23
+ }
24
+ function standardSemantic(path, node) {
25
+ const key = pathKey(path);
26
+ const stringFormats = {
27
+ [pathKey(STANDARD_SEMANTIC_PATHS.string.date)]: "date",
28
+ [pathKey(STANDARD_SEMANTIC_PATHS.string.datetime)]: "date-time",
29
+ [pathKey(STANDARD_SEMANTIC_PATHS.string.datetimeIso)]: "date-time",
30
+ [pathKey(STANDARD_SEMANTIC_PATHS.string.email)]: "email",
31
+ [pathKey(STANDARD_SEMANTIC_PATHS.string.url)]: "uri",
32
+ [pathKey(STANDARD_SEMANTIC_PATHS.string.ipV4)]: "ipv4",
33
+ [pathKey(STANDARD_SEMANTIC_PATHS.string.ipV6)]: "ipv6",
34
+ [pathKey(STANDARD_SEMANTIC_PATHS.string.uuid)]: "uuid",
35
+ [pathKey(STANDARD_SEMANTIC_PATHS.string.uuidV4)]: "uuid"
36
+ };
37
+ if (node.name === "string" && stringFormats[key]) return { format: stringFormats[key] };
38
+ if (node.name === "number" && key === pathKey(STANDARD_SEMANTIC_PATHS.number.integer)) return { type: "integer" };
39
+ if (node.name === "number" && key === pathKey(STANDARD_SEMANTIC_PATHS.number.safeInteger)) return {
40
+ type: "integer",
41
+ minimum: -9007199254740991,
42
+ maximum: 9007199254740991
43
+ };
44
+ }
45
+ function standardConstraint(constraint, target) {
46
+ const key = pathKey(constraint.constraintPath);
47
+ const value = constraint.args;
48
+ switch (key) {
49
+ case pathKey(STANDARD_CONSTRAINT_PATHS.string.minLength): return typeof value === "number" ? { minLength: value } : void 0;
50
+ case pathKey(STANDARD_CONSTRAINT_PATHS.string.maxLength): return typeof value === "number" ? { maxLength: value } : void 0;
51
+ case pathKey(STANDARD_CONSTRAINT_PATHS.string.pattern): return typeof value === "string" ? { pattern: value } : void 0;
52
+ case pathKey(STANDARD_CONSTRAINT_PATHS.number.minimum): return typeof value === "number" ? { minimum: value } : void 0;
53
+ case pathKey(STANDARD_CONSTRAINT_PATHS.number.maximum): return typeof value === "number" ? { maximum: value } : void 0;
54
+ case pathKey(STANDARD_CONSTRAINT_PATHS.number.exclusiveMinimum): return typeof value === "number" ? target === "draft-2020-12" ? { exclusiveMinimum: value } : {
55
+ minimum: value,
56
+ exclusiveMinimum: true
57
+ } : void 0;
58
+ case pathKey(STANDARD_CONSTRAINT_PATHS.number.exclusiveMaximum): return typeof value === "number" ? target === "draft-2020-12" ? { exclusiveMaximum: value } : {
59
+ maximum: value,
60
+ exclusiveMaximum: true
61
+ } : void 0;
62
+ case pathKey(STANDARD_CONSTRAINT_PATHS.number.multipleOf): return typeof value === "number" ? { multipleOf: value } : void 0;
63
+ case pathKey(STANDARD_CONSTRAINT_PATHS.array.minItems): return typeof value === "number" ? { minItems: value } : void 0;
64
+ case pathKey(STANDARD_CONSTRAINT_PATHS.array.maxItems): return typeof value === "number" ? { maxItems: value } : void 0;
65
+ case pathKey(STANDARD_CONSTRAINT_PATHS.array.uniqueItems): return typeof value === "boolean" ? { uniqueItems: value } : void 0;
66
+ case pathKey(STANDARD_CONSTRAINT_PATHS.record.minProperties): return typeof value === "number" ? { minProperties: value } : void 0;
67
+ case pathKey(STANDARD_CONSTRAINT_PATHS.record.maxProperties): return typeof value === "number" ? { maxProperties: value } : void 0;
68
+ default: return;
69
+ }
70
+ }
71
+ function applyMetadata(target, node, context, path) {
72
+ if ("semanticPath" in node && node.semanticPath) {
73
+ const custom = context.options.semanticMapper?.(node.semanticPath, node);
74
+ const mapped = custom ?? standardSemantic(node.semanticPath, node);
75
+ if (mapped) {
76
+ mergeKeyword(target, mapped);
77
+ extension(target, { semanticPath: node.semanticPath });
78
+ if (custom === void 0) diagnostic(context, "semantic.lossy", `Semantic path ${node.semanticPath.join("/")} is approximated by JSON Schema keywords`, path);
79
+ } else {
80
+ extension(target, { semanticPath: node.semanticPath });
81
+ diagnostic(context, "semantic.unmapped", `Semantic path ${node.semanticPath.join("/")} has no lossless JSON Schema mapping`, path);
82
+ }
83
+ }
84
+ if ("constraints" in node && node.constraints) for (const constraint of node.constraints) {
85
+ const mapped = context.options.constraintMapper?.(constraint, node) ?? standardConstraint(constraint, context.target);
86
+ if (mapped) mergeKeyword(target, mapped);
87
+ else {
88
+ const prior = target["x-schemair"];
89
+ const meta = prior && typeof prior === "object" && !Array.isArray(prior) ? prior : {};
90
+ extension(target, { constraints: [...Array.isArray(meta.constraints) ? meta.constraints : [], {
91
+ constraintPath: [...constraint.constraintPath],
92
+ ...constraint.args === void 0 ? {} : { args: constraint.args }
93
+ }] });
94
+ diagnostic(context, "constraint.unmapped", `Constraint ${constraint.constraintPath.join("/")} has no lossless JSON Schema mapping`, path);
95
+ }
96
+ }
97
+ }
98
+ function project(node, context, path) {
99
+ if (context.stack.includes(node)) {
100
+ diagnostic(context, "schema.cycle", "Cyclic schema graph requires an explicit ref strategy", path, "error");
101
+ const cycle = {};
102
+ extension(cycle, { selfRef: true });
103
+ return cycle;
104
+ }
105
+ context.stack.push(node);
106
+ let result;
107
+ switch (node.kind) {
108
+ case "primitive":
109
+ if (context.target === "openapi-3.0" && node.name === "null") {
110
+ result = {};
111
+ extension(result, { original: {
112
+ kind: "primitive",
113
+ name: "null"
114
+ } });
115
+ diagnostic(context, "openapi.null.unsupported", "OpenAPI 3.0 Schema Objects cannot represent a standalone null type", path, "error");
116
+ } else result = { type: node.name === "null" ? "null" : node.name };
117
+ applyMetadata(result, node, context, path);
118
+ break;
119
+ case "literal":
120
+ if (context.target === "openapi-3.0") {
121
+ result = { enum: [node.literal] };
122
+ extension(result, { literal: node.literal });
123
+ diagnostic(context, "openapi.literal.lossy", "OpenAPI 3.0 has no const keyword; the literal is projected as a single-value enum", path);
124
+ } else result = { const: node.literal };
125
+ break;
126
+ case "literalUnion":
127
+ result = { enum: [...node.values] };
128
+ extension(result, { union: {
129
+ kind: "literalUnion",
130
+ values: [...node.values]
131
+ } });
132
+ break;
133
+ case "nullable": {
134
+ const inner = project(node.value, context, [...path, "value"]);
135
+ if (context.target === "openapi-3.0") {
136
+ result = {
137
+ ...inner,
138
+ nullable: true
139
+ };
140
+ extension(result, { union: {
141
+ kind: "nullable",
142
+ value: true
143
+ } });
144
+ diagnostic(context, "openapi.nullable.lossy", "OpenAPI 3.0 nullable is preserved as an extension because it is not equivalent to JSON Schema null union semantics", path);
145
+ } else result = { anyOf: [inner, { type: "null" }] };
146
+ break;
147
+ }
148
+ case "array":
149
+ result = {
150
+ type: "array",
151
+ items: project(node.elementSchema, context, [...path, "elementSchema"])
152
+ };
153
+ applyMetadata(result, node, context, path);
154
+ break;
155
+ case "tuple":
156
+ if (context.target === "draft-07") result = {
157
+ type: "array",
158
+ items: node.elementSchemas.map((item, index) => project(item, context, [
159
+ ...path,
160
+ "elementSchemas",
161
+ index
162
+ ])),
163
+ additionalItems: false,
164
+ minItems: node.elementSchemas.length,
165
+ maxItems: node.elementSchemas.length
166
+ };
167
+ else if (context.target === "openapi-3.0") {
168
+ const elements = node.elementSchemas.map((item, index) => project(item, context, [
169
+ ...path,
170
+ "elementSchemas",
171
+ index
172
+ ]));
173
+ result = {
174
+ type: "array",
175
+ items: {}
176
+ };
177
+ extension(result, { union: {
178
+ kind: "tuple",
179
+ length: node.elementSchemas.length,
180
+ elementSchemas: elements
181
+ } });
182
+ diagnostic(context, "openapi.tuple.lossy", "OpenAPI 3.0 has no tuple form; tuple position schemas are retained only in x-schemair", path);
183
+ } else result = {
184
+ type: "array",
185
+ prefixItems: node.elementSchemas.map((item, index) => project(item, context, [
186
+ ...path,
187
+ "elementSchemas",
188
+ index
189
+ ])),
190
+ items: false,
191
+ minItems: node.elementSchemas.length,
192
+ maxItems: node.elementSchemas.length
193
+ };
194
+ break;
195
+ case "record": {
196
+ const properties = {};
197
+ const required = [];
198
+ for (const field of node.fields) {
199
+ properties[field.key] = project(field.schema, context, [
200
+ ...path,
201
+ "fields",
202
+ field.key
203
+ ]);
204
+ if (field.required) required.push(field.key);
205
+ }
206
+ result = {
207
+ type: "object",
208
+ properties
209
+ };
210
+ if (required.length) result.required = required;
211
+ if (node.additionalFields === void 0) result.additionalProperties = false;
212
+ else if (node.additionalFields === true) result.additionalProperties = true;
213
+ else result.additionalProperties = project(node.additionalFields, context, [...path, "additionalFields"]);
214
+ applyMetadata(result, node, context, path);
215
+ break;
216
+ }
217
+ case "taggedUnion":
218
+ result = { oneOf: node.variants.map((variant, index) => project(variant.schema, context, [
219
+ ...path,
220
+ "variants",
221
+ index
222
+ ])) };
223
+ extension(result, { union: {
224
+ kind: "taggedUnion",
225
+ discriminator: node.discriminator,
226
+ variants: node.variants.map((variant) => ({
227
+ key: variant.key,
228
+ description: variant.description ?? null
229
+ }))
230
+ } });
231
+ diagnostic(context, "union.tagged.lossy", "SchemaIR tagged-union keys are not JSON Schema validation semantics", path);
232
+ break;
233
+ case "ref": {
234
+ const reference = context.options.refStrategy?.(node.refPath);
235
+ result = reference ? { $ref: reference } : {};
236
+ if (!reference) {
237
+ extension(result, { refPath: node.refPath });
238
+ diagnostic(context, "ref.unresolved", `No JSON Schema ref strategy resolved ${node.refPath.join("/")}`, path, "error");
239
+ }
240
+ break;
241
+ }
242
+ case "selfRef":
243
+ result = {};
244
+ extension(result, { selfRef: true });
245
+ diagnostic(context, "ref.self", "selfRef needs a caller-owned JSON Schema anchor strategy", path, "error");
246
+ break;
247
+ }
248
+ context.stack.pop();
249
+ return result;
250
+ }
251
+ function fidelity(diagnostics) {
252
+ if (diagnostics.some((item) => item.severity === "error")) return "unsupported";
253
+ if (diagnostics.length) return "lossy";
254
+ return "exact";
255
+ }
256
+ /** Project a SchemaNode into JSON Schema Draft 2020-12 without hiding loss. */
257
+ function schemaNodeToJsonSchema(node, options = {}) {
258
+ const target = options.target ?? "draft-2020-12";
259
+ if (target === "openapi-3.0") return schemaNodeToOpenApiSchema(node, options);
260
+ const context = {
261
+ options,
262
+ target,
263
+ diagnostics: [],
264
+ stack: []
265
+ };
266
+ return {
267
+ schema: project(node, context, []),
268
+ fidelity: fidelity(context.diagnostics),
269
+ diagnostics: context.diagnostics
270
+ };
271
+ }
272
+ /** Project a SchemaNode to an OpenAPI 3.0 Schema Object. */
273
+ function schemaNodeToOpenApiSchema(node, options = {}) {
274
+ const context = {
275
+ options,
276
+ target: "openapi-3.0",
277
+ diagnostics: [],
278
+ stack: []
279
+ };
280
+ return {
281
+ schema: project(node, context, []),
282
+ fidelity: fidelity(context.diagnostics),
283
+ diagnostics: context.diagnostics
284
+ };
285
+ }
286
+ /** Alias emphasizing that this is a diagnostic-bearing projection operation. */
287
+ const schemaNodeToJsonSchemaWithDiagnostics = schemaNodeToJsonSchema;
288
+ /**
289
+ * Expose a runtime SchemaIR declaration through Standard JSON Schema V1.
290
+ *
291
+ * SchemaIR declarations do not perform input/output transformations, so both
292
+ * converter methods project the same contract. Lossy projections are allowed
293
+ * because their preserved metadata remains in `x-schemair`; unsupported
294
+ * projections throw as required by the Standard JSON Schema protocol.
295
+ */
296
+ function schemaIRToStandardJsonSchema(node, options = {}) {
297
+ const convert = (target) => {
298
+ const { target: _ignoredTarget, ...projectionOptions } = options;
299
+ const projectionTarget = target === "openapi-3.0" || target === "draft-2020-12" || target === "draft-07" ? target : void 0;
300
+ const result = projectionTarget === "openapi-3.0" ? schemaNodeToOpenApiSchema(node, projectionOptions) : projectionTarget ? schemaNodeToJsonSchema(node, {
301
+ ...projectionOptions,
302
+ target: projectionTarget
303
+ }) : void 0;
304
+ if (!result) throw new Error(`SchemaIR Standard JSON Schema adapter does not support target ${target}`);
305
+ if (result.fidelity === "unsupported") {
306
+ const details = result.diagnostics.map((item) => item.message).join("; ");
307
+ throw new Error(`SchemaIR cannot be represented as JSON Schema: ${details}`);
308
+ }
309
+ return result.schema;
310
+ };
311
+ return { "~standard": {
312
+ version: 1,
313
+ vendor: "schemair",
314
+ jsonSchema: {
315
+ input: ({ target }) => convert(target),
316
+ output: ({ target }) => convert(target)
317
+ }
318
+ } };
319
+ }
320
+ /** Uppercase acronym alias matching the protocol name. */
321
+ const schemaIRToStandardJSONSchema = schemaIRToStandardJsonSchema;
322
+
323
+ //#endregion
324
+ export { schemaIRToStandardJSONSchema, schemaIRToStandardJsonSchema, schemaNodeToJsonSchema, schemaNodeToJsonSchemaWithDiagnostics, schemaNodeToOpenApiSchema };
@@ -0,0 +1,32 @@
1
+ const require_payload_index = require('../../payload/index.cjs');
2
+
3
+ //#region src/integrations/standard-schema/index.ts
4
+ function toStandardIssue(issue) {
5
+ const path = issue.path.length > 0 ? [...issue.path] : void 0;
6
+ return path === void 0 ? { message: issue.message } : {
7
+ message: issue.message,
8
+ path
9
+ };
10
+ }
11
+ /**
12
+ * Expose a serializable SchemaIR declaration through the Standard Schema
13
+ * runtime protocol. Validation is synchronous; load external refs and policy
14
+ * data before constructing the adapter.
15
+ *
16
+ * The adapter never transforms a payload and intentionally does not expose
17
+ * `~standard.types` because the declaration is runtime data.
18
+ */
19
+ function schemaIRToStandardSchema(schema, options = {}) {
20
+ return { "~standard": {
21
+ version: 1,
22
+ vendor: "schemair",
23
+ validate: (value) => {
24
+ const result = require_payload_index.validatePayload(value, schema, options);
25
+ if (result.status === "accepted") return { value };
26
+ return { issues: result.issues.map(toStandardIssue) };
27
+ }
28
+ } };
29
+ }
30
+
31
+ //#endregion
32
+ exports.schemaIRToStandardSchema = schemaIRToStandardSchema;
@@ -0,0 +1,22 @@
1
+ import { ct as SchemaNode } from "../../index-i7Au-FQ6.cjs";
2
+ import { s as PayloadValidationContext } from "../../index-CzNxjqVg.cjs";
3
+ import { StandardSchemaV1, StandardSchemaV1 as StandardSchemaV1$1 } from "@standard-schema/spec";
4
+
5
+ //#region src/integrations/standard-schema/index.d.ts
6
+ /** Options captured by a Standard Schema adapter at construction time. */
7
+ type StandardSchemaAdapterOptions = PayloadValidationContext;
8
+ /** Runtime-only Standard Schema surface for a dynamic SchemaIR declaration. */
9
+ type SchemaIRStandardSchema = {
10
+ readonly '~standard': Omit<StandardSchemaV1$1.Props, 'types'>;
11
+ };
12
+ /**
13
+ * Expose a serializable SchemaIR declaration through the Standard Schema
14
+ * runtime protocol. Validation is synchronous; load external refs and policy
15
+ * data before constructing the adapter.
16
+ *
17
+ * The adapter never transforms a payload and intentionally does not expose
18
+ * `~standard.types` because the declaration is runtime data.
19
+ */
20
+ declare function schemaIRToStandardSchema(schema: SchemaNode, options?: StandardSchemaAdapterOptions): SchemaIRStandardSchema;
21
+ //#endregion
22
+ export { SchemaIRStandardSchema, StandardSchemaAdapterOptions, type StandardSchemaV1, schemaIRToStandardSchema };
@@ -0,0 +1,22 @@
1
+ import { ct as SchemaNode } from "../../index-1sDuqu05.js";
2
+ import { s as PayloadValidationContext } from "../../index-hrcM9oJe.js";
3
+ import { StandardSchemaV1, StandardSchemaV1 as StandardSchemaV1$1 } from "@standard-schema/spec";
4
+
5
+ //#region src/integrations/standard-schema/index.d.ts
6
+ /** Options captured by a Standard Schema adapter at construction time. */
7
+ type StandardSchemaAdapterOptions = PayloadValidationContext;
8
+ /** Runtime-only Standard Schema surface for a dynamic SchemaIR declaration. */
9
+ type SchemaIRStandardSchema = {
10
+ readonly '~standard': Omit<StandardSchemaV1$1.Props, 'types'>;
11
+ };
12
+ /**
13
+ * Expose a serializable SchemaIR declaration through the Standard Schema
14
+ * runtime protocol. Validation is synchronous; load external refs and policy
15
+ * data before constructing the adapter.
16
+ *
17
+ * The adapter never transforms a payload and intentionally does not expose
18
+ * `~standard.types` because the declaration is runtime data.
19
+ */
20
+ declare function schemaIRToStandardSchema(schema: SchemaNode, options?: StandardSchemaAdapterOptions): SchemaIRStandardSchema;
21
+ //#endregion
22
+ export { SchemaIRStandardSchema, StandardSchemaAdapterOptions, type StandardSchemaV1, schemaIRToStandardSchema };
@@ -0,0 +1,32 @@
1
+ import { validatePayload } from "../../payload/index.js";
2
+
3
+ //#region src/integrations/standard-schema/index.ts
4
+ function toStandardIssue(issue) {
5
+ const path = issue.path.length > 0 ? [...issue.path] : void 0;
6
+ return path === void 0 ? { message: issue.message } : {
7
+ message: issue.message,
8
+ path
9
+ };
10
+ }
11
+ /**
12
+ * Expose a serializable SchemaIR declaration through the Standard Schema
13
+ * runtime protocol. Validation is synchronous; load external refs and policy
14
+ * data before constructing the adapter.
15
+ *
16
+ * The adapter never transforms a payload and intentionally does not expose
17
+ * `~standard.types` because the declaration is runtime data.
18
+ */
19
+ function schemaIRToStandardSchema(schema, options = {}) {
20
+ return { "~standard": {
21
+ version: 1,
22
+ vendor: "schemair",
23
+ validate: (value) => {
24
+ const result = validatePayload(value, schema, options);
25
+ if (result.status === "accepted") return { value };
26
+ return { issues: result.issues.map(toStandardIssue) };
27
+ }
28
+ } };
29
+ }
30
+
31
+ //#endregion
32
+ export { schemaIRToStandardSchema };
@@ -1,4 +1,5 @@
1
- const require_definition = require('../definition-DSZZTz4e.cjs');
1
+ const require_definition = require('../definition-BLLBpLKv.cjs');
2
+ const require_schema_ref_key = require('../schema-ref-key-BHVFVfj1.cjs');
2
3
 
3
4
  //#region src/payload/validator.ts
4
5
  function hasOwn(value, key) {
@@ -38,22 +39,19 @@ function hasAccessorOrSymbol(value) {
38
39
  function isPromiseLike(value) {
39
40
  return (typeof value === "object" && value !== null || typeof value === "function") && typeof value.then === "function";
40
41
  }
41
- function chain(previous, next) {
42
- return isPromiseLike(previous) ? Promise.resolve(previous).then(() => next()) : next();
43
- }
44
42
  var PayloadValidator = class {
45
43
  issues = [];
46
44
  activePayload = /* @__PURE__ */ new WeakSet();
47
45
  activeRefs = /* @__PURE__ */ new Set();
46
+ refIndex;
48
47
  rootSchema;
49
- constructor(context, rootSchema, allowAsync) {
48
+ constructor(context, rootSchema) {
50
49
  this.context = context;
51
- this.allowAsync = allowAsync;
52
50
  this.rootSchema = rootSchema;
51
+ this.refIndex = require_schema_ref_key.indexSchemaRefs(context.refs);
53
52
  }
54
53
  run(value) {
55
- const validation = this.validateNode(value, this.rootSchema, [], this.rootSchema);
56
- if (isPromiseLike(validation)) return Promise.resolve(validation).then(() => this.result());
54
+ this.validateNode(value, this.rootSchema, [], this.rootSchema);
57
55
  return this.result();
58
56
  }
59
57
  result() {
@@ -93,35 +91,29 @@ var PayloadValidator = class {
93
91
  }
94
92
  validateNode(value, schema, path, root) {
95
93
  switch (schema.kind) {
96
- case "primitive": {
94
+ case "primitive":
97
95
  if (!this.matchesPrimitive(value, schema.name)) {
98
96
  this.reject(path, "type", `expected ${schema.name}`);
99
97
  return;
100
98
  }
101
- let pending = void 0;
102
- if ((schema.name === "string" || schema.name === "number") && schema.semanticPath) pending = chain(pending, () => this.runSemantic(schema.semanticPath, value, schema, path, root));
103
- if ((schema.name === "string" || schema.name === "number") && schema.constraints) pending = chain(pending, () => this.runConstraints(schema.constraints, value, schema, path, root));
104
- return pending;
105
- }
99
+ if ((schema.name === "string" || schema.name === "number") && schema.semanticPath) this.runSemantic(schema.semanticPath, value, schema, path, root);
100
+ if ((schema.name === "string" || schema.name === "number") && schema.constraints) this.runConstraints(schema.constraints, value, schema, path, root);
101
+ return;
106
102
  case "literal":
107
103
  if (!isLiteral(value) || !equalLiteral(value, schema.literal)) this.reject(path, "literal", "value does not match literal");
108
104
  return;
109
105
  case "record": return this.validateRecord(value, schema, path, root);
110
- case "array": {
106
+ case "array":
111
107
  if (!isDenseArray(value)) {
112
108
  this.reject(path, "array", "expected a dense array");
113
109
  return;
114
110
  }
115
111
  if (!this.enterPayload(value, path)) return;
116
- let pending = void 0;
117
- for (let index = 0; index < value.length; index += 1) pending = chain(pending, () => this.validateNode(value[index], schema.elementSchema, [...path, index], root));
118
- pending = chain(pending, () => {
119
- this.leavePayload(value);
120
- return schema.constraints ? this.runConstraints(schema.constraints, value, schema, path, root) : void 0;
121
- });
122
- return pending;
123
- }
124
- case "tuple": {
112
+ for (let index = 0; index < value.length; index += 1) this.validateNode(value[index], schema.elementSchema, [...path, index], root);
113
+ this.leavePayload(value);
114
+ if (schema.constraints) this.runConstraints(schema.constraints, value, schema, path, root);
115
+ return;
116
+ case "tuple":
125
117
  if (!isDenseArray(value)) {
126
118
  this.reject(path, "tuple", "expected a dense array");
127
119
  return;
@@ -131,15 +123,12 @@ var PayloadValidator = class {
131
123
  return;
132
124
  }
133
125
  if (!this.enterPayload(value, path)) return;
134
- let pending = void 0;
135
126
  for (let index = 0; index < schema.elementSchemas.length; index += 1) {
136
127
  const elementSchema = schema.elementSchemas[index];
137
- if (elementSchema) pending = chain(pending, () => this.validateNode(value[index], elementSchema, [...path, index], root));
128
+ if (elementSchema) this.validateNode(value[index], elementSchema, [...path, index], root);
138
129
  }
139
- return chain(pending, () => {
140
- this.leavePayload(value);
141
- });
142
- }
130
+ this.leavePayload(value);
131
+ return;
143
132
  case "literalUnion":
144
133
  if (!isLiteral(value) || !schema.values.some((candidate) => equalLiteral(candidate, value))) this.reject(path, "literal-union", "value is not one of the allowed literals");
145
134
  return;
@@ -165,26 +154,23 @@ var PayloadValidator = class {
165
154
  }
166
155
  if (!this.enterPayload(value, path)) return;
167
156
  const fields = new Map(schema.fields.map((field) => [field.key, field]));
168
- let pending = void 0;
169
157
  for (const field of schema.fields) {
170
158
  if (!hasOwn(value, field.key)) {
171
159
  if (field.required === true) this.reject([...path, field.key], "required", "required field is missing");
172
160
  continue;
173
161
  }
174
- pending = chain(pending, () => this.validateNode(value[field.key], field.schema, [...path, field.key], root));
162
+ this.validateNode(value[field.key], field.schema, [...path, field.key], root);
175
163
  }
176
164
  for (const key of Object.keys(value)) {
177
165
  if (fields.has(key)) continue;
178
166
  if (!hasOwn(schema, "additionalFields")) this.reject([...path, key], "additional-field", "unknown field is not allowed");
179
167
  else if (schema.additionalFields !== true) {
180
168
  const additionalSchema = schema.additionalFields;
181
- if (additionalSchema) pending = chain(pending, () => this.validateNode(value[key], additionalSchema, [...path, key], root));
169
+ if (additionalSchema) this.validateNode(value[key], additionalSchema, [...path, key], root);
182
170
  } else if (!this.isJsonValue(value[key], /* @__PURE__ */ new WeakSet())) this.reject([...path, key], "additional-value", "additional field must be JSON-compatible");
183
171
  }
184
- return chain(pending, () => {
185
- this.leavePayload(value);
186
- return schema.constraints ? this.runConstraints(schema.constraints, value, schema, path, root) : void 0;
187
- });
172
+ this.leavePayload(value);
173
+ if (schema.constraints) this.runConstraints(schema.constraints, value, schema, path, root);
188
174
  }
189
175
  validateTaggedUnion(value, schema, path, root) {
190
176
  if (!isPlainRecord(value) || hasAccessorOrSymbol(value)) {
@@ -207,15 +193,18 @@ var PayloadValidator = class {
207
193
  return this.validateNode(value, variant.schema, path, root);
208
194
  }
209
195
  validateRef(value, schema, path, root) {
210
- if (!this.context.resolveRef) {
211
- this.unsupported(path, "ref.resolver", "refPath requires an explicit resolver");
212
- return;
213
- }
214
- const refKey = schema.refPath.join("\0");
196
+ const refKey = require_schema_ref_key.schemaRefKey(schema.refPath);
215
197
  if (this.activeRefs.has(refKey)) {
216
198
  this.unknown(path, "ref.cycle", "refPath resolution cycle could not be determined");
217
199
  return;
218
200
  }
201
+ const materialized = this.refIndex.get(refKey);
202
+ if (materialized !== void 0) return this.handleResolution(materialized, value, path, root);
203
+ if (!this.context.resolveRef) {
204
+ if (this.context.refs !== void 0) this.unknown(path, "ref.unresolved", "refPath is not present in the resolved environment");
205
+ else this.unsupported(path, "ref.resolver", "refPath requires an explicit resolver");
206
+ return;
207
+ }
219
208
  this.activeRefs.add(refKey);
220
209
  let resolved;
221
210
  try {
@@ -231,19 +220,15 @@ var PayloadValidator = class {
231
220
  return;
232
221
  }
233
222
  if (isPromiseLike(resolved)) {
234
- if (!this.allowAsync) {
235
- this.unsupported(path, "ref.async", "synchronous validation requires a synchronous ref resolver");
236
- this.activeRefs.delete(refKey);
237
- return;
238
- }
239
- return Promise.resolve(resolved).then((result) => this.handleResolution(result, value, path, root)).catch((error) => {
240
- this.unknown(path, "ref.error", `refPath resolver failed: ${error instanceof Error ? error.message : String(error)}`);
241
- }).finally(() => this.activeRefs.delete(refKey));
223
+ this.unsupported(path, "ref.async", "synchronous validation requires a synchronous ref resolver");
224
+ this.activeRefs.delete(refKey);
225
+ return;
226
+ }
227
+ try {
228
+ this.handleResolution(resolved, value, path, root);
229
+ } finally {
230
+ this.activeRefs.delete(refKey);
242
231
  }
243
- const handled = this.handleResolution(resolved, value, path, root);
244
- if (isPromiseLike(handled)) return Promise.resolve(handled).finally(() => this.activeRefs.delete(refKey));
245
- this.activeRefs.delete(refKey);
246
- return handled;
247
232
  }
248
233
  handleResolution(resolved, value, path, root) {
249
234
  if (resolved === void 0) {
@@ -279,19 +264,17 @@ var PayloadValidator = class {
279
264
  }), path, "semantic");
280
265
  }
281
266
  runConstraints(constraints, value, schema, path, root) {
282
- let pending = void 0;
283
267
  for (const constraint of constraints) {
284
268
  if (!this.context.constraintProvider) {
285
269
  this.unsupported(path, "constraint.provider", `constraint path ${constraint.constraintPath.join("/")} has no provider`);
286
270
  continue;
287
271
  }
288
- pending = chain(pending, () => this.applyProvider(() => this.context.constraintProvider(constraint.constraintPath, constraint.args, value, {
272
+ this.applyProvider(() => this.context.constraintProvider(constraint.constraintPath, constraint.args, value, {
289
273
  path,
290
274
  schema,
291
275
  rootSchema: root
292
- }), path, "constraint"));
276
+ }), path, "constraint");
293
277
  }
294
- return pending;
295
278
  }
296
279
  applyProvider(call, path, kind) {
297
280
  let result;
@@ -302,13 +285,8 @@ var PayloadValidator = class {
302
285
  return;
303
286
  }
304
287
  if (isPromiseLike(result)) {
305
- if (!this.allowAsync) {
306
- this.unsupported(path, `${kind}.async`, `synchronous validation requires a synchronous ${kind} provider`);
307
- return;
308
- }
309
- return Promise.resolve(result).then((decision) => this.applyDecision(decision, path, kind)).catch((error) => {
310
- this.unknown(path, `${kind}.error`, `${kind} provider failed: ${error instanceof Error ? error.message : String(error)}`);
311
- });
288
+ this.unsupported(path, `${kind}.async`, `synchronous validation requires a synchronous ${kind} provider`);
289
+ return;
312
290
  }
313
291
  return this.applyDecision(result, path, kind);
314
292
  }
@@ -368,23 +346,8 @@ function validateDefinition(schema) {
368
346
  function validatePayload(value, schema, context = {}) {
369
347
  const validated = validateDefinition(schema);
370
348
  if ("status" in validated) return validated;
371
- const result = new PayloadValidator(context, validated, false).run(value);
372
- if (isPromiseLike(result)) return {
373
- status: "unknown",
374
- issues: [{
375
- code: "payload.unknown.async",
376
- path: [],
377
- message: "synchronous payload validation produced an asynchronous result"
378
- }]
379
- };
380
- return result;
381
- }
382
- async function validatePayloadAsync(value, schema, context = {}) {
383
- const validated = validateDefinition(schema);
384
- if ("status" in validated) return validated;
385
- return Promise.resolve(new PayloadValidator(context, validated, true).run(value));
349
+ return new PayloadValidator(context, validated).run(value);
386
350
  }
387
351
 
388
352
  //#endregion
389
- exports.validatePayload = validatePayload;
390
- exports.validatePayloadAsync = validatePayloadAsync;
353
+ exports.validatePayload = validatePayload;