@ultimat3/schema 1.0.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 (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +100 -0
  3. package/package.json +33 -0
  4. package/src/builder.d.ts +62 -0
  5. package/src/builder.d.ts.map +1 -0
  6. package/src/builder.js +93 -0
  7. package/src/builder.js.map +1 -0
  8. package/src/builder.ts +173 -0
  9. package/src/coerce.d.ts +15 -0
  10. package/src/coerce.d.ts.map +1 -0
  11. package/src/coerce.js +123 -0
  12. package/src/coerce.js.map +1 -0
  13. package/src/coerce.ts +125 -0
  14. package/src/errors.d.ts +62 -0
  15. package/src/errors.d.ts.map +1 -0
  16. package/src/errors.js +85 -0
  17. package/src/errors.js.map +1 -0
  18. package/src/errors.ts +140 -0
  19. package/src/index.d.ts +19 -0
  20. package/src/index.d.ts.map +1 -0
  21. package/src/index.js +11 -0
  22. package/src/index.js.map +1 -0
  23. package/src/index.ts +102 -0
  24. package/src/json-schema.d.ts +37 -0
  25. package/src/json-schema.d.ts.map +1 -0
  26. package/src/json-schema.js +108 -0
  27. package/src/json-schema.js.map +1 -0
  28. package/src/json-schema.ts +149 -0
  29. package/src/node.d.ts +32 -0
  30. package/src/node.d.ts.map +1 -0
  31. package/src/node.js +24 -0
  32. package/src/node.js.map +1 -0
  33. package/src/node.ts +75 -0
  34. package/src/provider.d.ts +32 -0
  35. package/src/provider.d.ts.map +1 -0
  36. package/src/provider.js +49 -0
  37. package/src/provider.js.map +1 -0
  38. package/src/provider.ts +67 -0
  39. package/src/standard.d.ts +44 -0
  40. package/src/standard.d.ts.map +1 -0
  41. package/src/standard.js +71 -0
  42. package/src/standard.js.map +1 -0
  43. package/src/standard.ts +160 -0
  44. package/src/t.d.ts +6 -0
  45. package/src/t.d.ts.map +1 -0
  46. package/src/t.js +79 -0
  47. package/src/t.js.map +1 -0
  48. package/src/t.ts +101 -0
  49. package/src/validators.d.ts +63 -0
  50. package/src/validators.d.ts.map +1 -0
  51. package/src/validators.js +271 -0
  52. package/src/validators.js.map +1 -0
  53. package/src/validators.ts +389 -0
package/src/coerce.ts ADDED
@@ -0,0 +1,125 @@
1
+ // Single responsibility: HTTP-boundary coercion. Kept out of validation on purpose — only the
2
+ // HTTP layer has strings that "mean" numbers. Actions, jobs and MCP calls receive real JSON and
3
+ // must never get this leniency.
4
+
5
+ import type { SchemaNode } from './node';
6
+ import { tryIntrospect } from './provider';
7
+
8
+ const TRUE_VALUES = new Set(['1', 'true', 'yes', 'on']);
9
+ const FALSE_VALUES = new Set(['0', 'false', 'no', 'off', '']);
10
+
11
+ export type QuerySource =
12
+ | URLSearchParams
13
+ | Readonly<Record<string, string | readonly string[] | undefined>>;
14
+
15
+ /**
16
+ * Coerce one raw value toward `node`. Never throws and never invents data: anything it cannot
17
+ * confidently convert is returned untouched so validation produces the real error message.
18
+ */
19
+ export function coerceNode(node: SchemaNode, raw: unknown): unknown {
20
+ if (raw === undefined || raw === null) return raw;
21
+
22
+ switch (node.kind) {
23
+ case 'number': {
24
+ if (typeof raw !== 'string') return raw;
25
+ const value = Number(raw);
26
+ return raw.trim() !== '' && Number.isFinite(value) ? value : raw;
27
+ }
28
+ case 'boolean': {
29
+ if (typeof raw !== 'string') return raw;
30
+ const lowered = raw.toLowerCase();
31
+ if (TRUE_VALUES.has(lowered)) return true;
32
+ if (FALSE_VALUES.has(lowered)) return false;
33
+ return raw;
34
+ }
35
+ case 'date': {
36
+ if (typeof raw !== 'string') return raw;
37
+ const parsed = new Date(raw);
38
+ return Number.isNaN(parsed.getTime()) ? raw : parsed;
39
+ }
40
+ case 'array': {
41
+ const items: unknown[] = Array.isArray(raw) ? raw : [raw];
42
+ const itemNode = node.items;
43
+ return itemNode === undefined ? items : items.map((item) => coerceNode(itemNode, item));
44
+ }
45
+ case 'record': {
46
+ if (typeof raw !== 'object' || node.valueNode === undefined) return raw;
47
+ const out: Record<string, unknown> = {};
48
+ for (const [key, value] of Object.entries(raw as Record<string, unknown>)) {
49
+ out[key] = coerceNode(node.valueNode, value);
50
+ }
51
+ return out;
52
+ }
53
+ case 'object': {
54
+ if (typeof raw !== 'object' || node.properties === undefined) return raw;
55
+ const source = raw as Record<string, unknown>;
56
+ const out: Record<string, unknown> = { ...source };
57
+ for (const [key, child] of Object.entries(node.properties)) {
58
+ if (key in source) out[key] = coerceNode(child, source[key]);
59
+ }
60
+ return out;
61
+ }
62
+ case 'money': {
63
+ if (typeof raw !== 'object') return raw;
64
+ const source = raw as Record<string, unknown>;
65
+ const minor = typeof source['minor'] === 'string' ? Number(source['minor']) : source['minor'];
66
+ return Number.isFinite(minor) ? { ...source, minor } : raw;
67
+ }
68
+ case 'union': {
69
+ // Only unambiguous single-kind unions (e.g. `number | undefined`) are safe to coerce.
70
+ const kinds = new Set((node.anyOf ?? []).map((member) => member.kind));
71
+ if (kinds.size !== 1) return raw;
72
+ const [member] = node.anyOf ?? [];
73
+ return member === undefined ? raw : coerceNode(member, raw);
74
+ }
75
+ default:
76
+ return raw;
77
+ }
78
+ }
79
+
80
+ function toRecord(source: QuerySource): Record<string, string | readonly string[] | undefined> {
81
+ if (!(source instanceof URLSearchParams)) {
82
+ return { ...source };
83
+ }
84
+ const out: Record<string, string | readonly string[]> = {};
85
+ for (const key of new Set(source.keys())) {
86
+ const all = source.getAll(key);
87
+ out[key] = all.length > 1 ? all : (all[0] as string);
88
+ }
89
+ return out;
90
+ }
91
+
92
+ /**
93
+ * Coerce a query string / route params object against a schema, ready to `parse()`.
94
+ * Unknown keys are passed through — the schema decides what to keep.
95
+ */
96
+ export function coerceQuery(schema: unknown, source: QuerySource): Record<string, unknown> {
97
+ const record = toRecord(source);
98
+ const node = tryIntrospect(schema);
99
+ if (node?.properties === undefined) return record;
100
+
101
+ const out: Record<string, unknown> = { ...record };
102
+ for (const [key, child] of Object.entries(node.properties)) {
103
+ if (!(key in record)) continue;
104
+ const raw = record[key];
105
+ out[key] = coerceNode(child, child.kind === 'array' ? (raw ?? []) : normaliseSingle(raw));
106
+ }
107
+ return out;
108
+ }
109
+
110
+ function normaliseSingle(raw: string | readonly string[] | undefined): unknown {
111
+ return Array.isArray(raw) ? raw[raw.length - 1] : raw;
112
+ }
113
+
114
+ /** Coerce an arbitrary record (route params, form data) against a schema. */
115
+ export function coerceInput(
116
+ schema: unknown,
117
+ raw: Readonly<Record<string, unknown>>,
118
+ ): Record<string, unknown> {
119
+ const node = tryIntrospect(schema);
120
+ if (node === undefined) return { ...raw };
121
+ const coerced = coerceNode(node, raw);
122
+ return typeof coerced === 'object' && coerced !== null
123
+ ? (coerced as Record<string, unknown>)
124
+ : { ...raw };
125
+ }
@@ -0,0 +1,62 @@
1
+ /** Same well-known symbol `@ultimat3/core` brands with. Keep in sync, never rename. */
2
+ export declare const ULTIMATE_ERROR_BRAND: unique symbol;
3
+ export interface SchemaErrorCodeDeclaration {
4
+ readonly title: string;
5
+ readonly docs?: string | undefined;
6
+ }
7
+ /**
8
+ * Pass to `registerErrorCodes()` from a package that may import both tiers (the CLI does this
9
+ * at boot) so the terminal and the dev overlay render these codes identically.
10
+ */
11
+ export declare const SCHEMA_ERROR_CODES: Readonly<Record<string, SchemaErrorCodeDeclaration>>;
12
+ export interface SchemaErrorInit {
13
+ readonly code: string;
14
+ readonly cause: string;
15
+ readonly fix: string;
16
+ readonly docs?: string | undefined;
17
+ readonly meta?: Readonly<Record<string, unknown>> | undefined;
18
+ }
19
+ export interface SchemaErrorJSON {
20
+ readonly code: string;
21
+ readonly title: string;
22
+ readonly cause: string;
23
+ readonly fix: string;
24
+ readonly docs: string;
25
+ readonly meta?: Readonly<Record<string, unknown>> | undefined;
26
+ }
27
+ export declare class SchemaError extends Error {
28
+ readonly [ULTIMATE_ERROR_BRAND] = true;
29
+ readonly name: string;
30
+ readonly code: string;
31
+ readonly title: string;
32
+ readonly cause: string;
33
+ readonly fix: string;
34
+ readonly docs: string;
35
+ readonly meta: Readonly<Record<string, unknown>> | undefined;
36
+ constructor(init: SchemaErrorInit);
37
+ /** The same 3-line rendering as `UltimateError.format()`. */
38
+ format(): string;
39
+ toJSON(): SchemaErrorJSON;
40
+ }
41
+ export interface ValidationIssue {
42
+ /** Dotted path from the validated root, e.g. `input.items[0].price`. */
43
+ readonly path: string;
44
+ readonly expected: string;
45
+ readonly received: string;
46
+ readonly message: string;
47
+ }
48
+ export declare class ValidationFailedError extends SchemaError {
49
+ static readonly code = "X_VALIDATION_FAILED";
50
+ readonly name = "ValidationFailedError";
51
+ readonly issues: readonly ValidationIssue[];
52
+ constructor(issues: readonly ValidationIssue[], root?: string);
53
+ /** One line per issue — what the dev overlay and `x test --json` render. */
54
+ formatIssues(): string;
55
+ }
56
+ export declare class SchemaUnsupportedError extends SchemaError {
57
+ static readonly code = "X_SCHEMA_UNSUPPORTED";
58
+ readonly name = "SchemaUnsupportedError";
59
+ constructor(init: Omit<SchemaErrorInit, 'code'>);
60
+ }
61
+ export declare function isSchemaError(value: unknown): value is SchemaError;
62
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["errors.ts"],"names":[],"mappings":"AAIA,uFAAuF;AACvF,eAAO,MAAM,oBAAoB,EAAE,OAAO,MAAqC,CAAC;AAEhF,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAIhF,CAAC;AAYL,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;CAC/D;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;CAC/D;AAED,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,CAAC,oBAAoB,CAAC,QAAQ;IACvC,SAAkB,IAAI,EAAE,MAAM,CAAiB;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,SAAiB,KAAK,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAE7D,YAAY,IAAI,EAAE,eAAe,EAQhC;IAED,6DAA6D;IAC7D,MAAM,IAAI,MAAM,CAIf;IAED,MAAM,IAAI,eAAe,CASxB;CACF;AAED,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,qBAAa,qBAAsB,SAAQ,WAAW;IACpD,MAAM,CAAC,QAAQ,CAAC,IAAI,yBAAyB;IAC7C,SAAkB,IAAI,2BAA2B;IACjD,QAAQ,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAC;IAE5C,YAAY,MAAM,EAAE,SAAS,eAAe,EAAE,EAAE,IAAI,SAAU,EAW7D;IAED,4EAA4E;IAC5E,YAAY,IAAI,MAAM,CAErB;CACF;AAED,qBAAa,sBAAuB,SAAQ,WAAW;IACrD,MAAM,CAAC,QAAQ,CAAC,IAAI,0BAA0B;IAC9C,SAAkB,IAAI,4BAA4B;IAClD,YAAY,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,EAE9C;CACF;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAElE"}
package/src/errors.js ADDED
@@ -0,0 +1,85 @@
1
+ // Single responsibility: this package's error codes. `@ultimat3/schema` is tier 0 and may not
2
+ // import `@ultimat3/core`, so `SchemaError` reproduces the `UltimateError` shape structurally
3
+ // and carries the same `Symbol.for('ultimate.error')` brand — `isUltimateError()` still matches.
4
+ /** Same well-known symbol `@ultimat3/core` brands with. Keep in sync, never rename. */
5
+ export const ULTIMATE_ERROR_BRAND = Symbol.for('ultimate.error');
6
+ /**
7
+ * Pass to `registerErrorCodes()` from a package that may import both tiers (the CLI does this
8
+ * at boot) so the terminal and the dev overlay render these codes identically.
9
+ */
10
+ export const SCHEMA_ERROR_CODES = Object.freeze({
11
+ X_VALIDATION_FAILED: { title: 'value did not match its schema' },
12
+ X_SCHEMA_UNSUPPORTED: { title: 'the active schema provider cannot do this' },
13
+ });
14
+ const TITLES = Object.freeze({
15
+ X_VALIDATION_FAILED: 'value did not match its schema',
16
+ X_SCHEMA_UNSUPPORTED: 'the active schema provider cannot do this',
17
+ });
18
+ /** `X_SCHEMA_UNSUPPORTED` -> `schema unsupported`, same fallback as the core registry. */
19
+ function humanize(code) {
20
+ return code.replace(/^X_/, '').toLowerCase().replaceAll('_', ' ');
21
+ }
22
+ export class SchemaError extends Error {
23
+ [ULTIMATE_ERROR_BRAND] = true;
24
+ name = 'SchemaError';
25
+ code;
26
+ title;
27
+ fix;
28
+ docs;
29
+ meta;
30
+ constructor(init) {
31
+ const title = TITLES[init.code] ?? humanize(init.code);
32
+ super(`${init.code}: ${title}`, { cause: init.cause });
33
+ this.code = init.code;
34
+ this.title = title;
35
+ this.fix = init.fix;
36
+ this.docs = init.docs ?? `https://ultimate.dev/errors/${init.code}`;
37
+ this.meta = init.meta;
38
+ }
39
+ /** The same 3-line rendering as `UltimateError.format()`. */
40
+ format() {
41
+ return [`${this.code}: ${this.title}`, ` cause: ${this.cause}`, ` fix: ${this.fix}`].join('\n');
42
+ }
43
+ toJSON() {
44
+ return {
45
+ code: this.code,
46
+ title: this.title,
47
+ cause: this.cause,
48
+ fix: this.fix,
49
+ docs: this.docs,
50
+ meta: this.meta,
51
+ };
52
+ }
53
+ }
54
+ export class ValidationFailedError extends SchemaError {
55
+ static code = 'X_VALIDATION_FAILED';
56
+ name = 'ValidationFailedError';
57
+ issues;
58
+ constructor(issues, root = 'value') {
59
+ const cause = issues
60
+ .map((issue) => `${issue.path === '' ? root : issue.path}: ${issue.message}`)
61
+ .join('; ');
62
+ super({
63
+ code: ValidationFailedError.code,
64
+ cause,
65
+ fix: `send ${root} with the field(s) named in cause corrected to the expected type`,
66
+ meta: { issues },
67
+ });
68
+ this.issues = issues;
69
+ }
70
+ /** One line per issue — what the dev overlay and `x test --json` render. */
71
+ formatIssues() {
72
+ return this.issues.map((issue) => ` ${issue.path}: ${issue.message}`).join('\n');
73
+ }
74
+ }
75
+ export class SchemaUnsupportedError extends SchemaError {
76
+ static code = 'X_SCHEMA_UNSUPPORTED';
77
+ name = 'SchemaUnsupportedError';
78
+ constructor(init) {
79
+ super({ ...init, code: SchemaUnsupportedError.code });
80
+ }
81
+ }
82
+ export function isSchemaError(value) {
83
+ return typeof value === 'object' && value !== null && ULTIMATE_ERROR_BRAND in value;
84
+ }
85
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["errors.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,8FAA8F;AAC9F,iGAAiG;AAEjG,uFAAuF;AACvF,MAAM,CAAC,MAAM,oBAAoB,GAAkB,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;AAOhF;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAC7B,MAAM,CAAC,MAAM,CAAC;IACZ,mBAAmB,EAAE,EAAE,KAAK,EAAE,gCAAgC,EAAE;IAChE,oBAAoB,EAAE,EAAE,KAAK,EAAE,2CAA2C,EAAE;CAC7E,CAAC,CAAC;AAEL,MAAM,MAAM,GAAqC,MAAM,CAAC,MAAM,CAAC;IAC7D,mBAAmB,EAAE,gCAAgC;IACrD,oBAAoB,EAAE,2CAA2C;CAClE,CAAC,CAAC;AAEH,0FAA0F;AAC1F,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACpE,CAAC;AAmBD,MAAM,OAAO,WAAY,SAAQ,KAAK;IAC3B,CAAC,oBAAoB,CAAC,GAAG,IAAI,CAAC;IACrB,IAAI,GAAW,aAAa,CAAC;IACtC,IAAI,CAAS;IACb,KAAK,CAAS;IAEd,GAAG,CAAS;IACZ,IAAI,CAAS;IACb,IAAI,CAAgD;IAE7D,YAAY,IAAqB;QAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvD,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACpB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,+BAA+B,IAAI,CAAC,IAAI,EAAE,CAAC;QACpE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACxB,CAAC;IAED,6DAA6D;IAC7D,MAAM;QACJ,OAAO,CAAC,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,EAAE,EAAE,YAAY,IAAI,CAAC,KAAK,EAAE,EAAE,YAAY,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAC3F,IAAI,CACL,CAAC;IACJ,CAAC;IAED,MAAM;QACJ,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB,CAAC;IACJ,CAAC;CACF;AAUD,MAAM,OAAO,qBAAsB,SAAQ,WAAW;IACpD,MAAM,CAAU,IAAI,GAAG,qBAAqB,CAAC;IAC3B,IAAI,GAAG,uBAAuB,CAAC;IACxC,MAAM,CAA6B;IAE5C,YAAY,MAAkC,EAAE,IAAI,GAAG,OAAO;QAC5D,MAAM,KAAK,GAAG,MAAM;aACjB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;aAC5E,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,KAAK,CAAC;YACJ,IAAI,EAAE,qBAAqB,CAAC,IAAI;YAChC,KAAK;YACL,GAAG,EAAE,QAAQ,IAAI,kEAAkE;YACnF,IAAI,EAAE,EAAE,MAAM,EAAE;SACjB,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,4EAA4E;IAC5E,YAAY;QACV,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpF,CAAC;CACF;AAED,MAAM,OAAO,sBAAuB,SAAQ,WAAW;IACrD,MAAM,CAAU,IAAI,GAAG,sBAAsB,CAAC;IAC5B,IAAI,GAAG,wBAAwB,CAAC;IAClD,YAAY,IAAmC;QAC7C,KAAK,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,sBAAsB,CAAC,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;CACF;AAED,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,oBAAoB,IAAI,KAAK,CAAC;AACtF,CAAC"}
package/src/errors.ts ADDED
@@ -0,0 +1,140 @@
1
+ // Single responsibility: this package's error codes. `@ultimat3/schema` is tier 0 and may not
2
+ // import `@ultimat3/core`, so `SchemaError` reproduces the `UltimateError` shape structurally
3
+ // and carries the same `Symbol.for('ultimate.error')` brand — `isUltimateError()` still matches.
4
+
5
+ import { formatIssues } from './standard';
6
+
7
+ /** Same well-known symbol `@ultimat3/core` brands with. Keep in sync, never rename. */
8
+ export const ULTIMATE_ERROR_BRAND: unique symbol = Symbol.for('ultimate.error');
9
+
10
+ export interface SchemaErrorCodeDeclaration {
11
+ readonly title: string;
12
+ readonly docs?: string | undefined;
13
+ }
14
+
15
+ /**
16
+ * Pass to `registerErrorCodes()` from a package that may import both tiers (the CLI does this
17
+ * at boot) so the terminal and the dev overlay render these codes identically.
18
+ */
19
+ export const SCHEMA_ERROR_CODES: Readonly<Record<string, SchemaErrorCodeDeclaration>> =
20
+ Object.freeze({
21
+ X_VALIDATION_FAILED: { title: 'value did not match its schema' },
22
+ X_SCHEMA_UNSUPPORTED: { title: 'the active schema provider cannot do this' },
23
+ });
24
+
25
+ /**
26
+ * Derived, never re-typed: the declarations above are the single source, so a title edited there
27
+ * cannot fall out of step with what `SchemaError` renders locally.
28
+ */
29
+ const TITLES: Readonly<Record<string, string>> = Object.freeze(
30
+ Object.fromEntries(
31
+ Object.entries(SCHEMA_ERROR_CODES).map(([code, declaration]) => [code, declaration.title]),
32
+ ),
33
+ );
34
+
35
+ /** `X_SCHEMA_UNSUPPORTED` -> `schema unsupported`, same fallback as the core registry. */
36
+ function humanize(code: string): string {
37
+ return code.replace(/^X_/, '').toLowerCase().replaceAll('_', ' ');
38
+ }
39
+
40
+ export interface SchemaErrorInit {
41
+ readonly code: string;
42
+ readonly cause: string;
43
+ readonly fix: string;
44
+ readonly docs?: string | undefined;
45
+ readonly meta?: Readonly<Record<string, unknown>> | undefined;
46
+ }
47
+
48
+ export interface SchemaErrorJSON {
49
+ readonly code: string;
50
+ readonly title: string;
51
+ readonly cause: string;
52
+ readonly fix: string;
53
+ readonly docs: string;
54
+ readonly meta?: Readonly<Record<string, unknown>> | undefined;
55
+ }
56
+
57
+ export class SchemaError extends Error {
58
+ readonly [ULTIMATE_ERROR_BRAND] = true;
59
+ override readonly name: string = 'SchemaError';
60
+ readonly code: string;
61
+ readonly title: string;
62
+ declare readonly cause: string;
63
+ readonly fix: string;
64
+ readonly docs: string;
65
+ readonly meta: Readonly<Record<string, unknown>> | undefined;
66
+
67
+ constructor(init: SchemaErrorInit) {
68
+ const title = TITLES[init.code] ?? humanize(init.code);
69
+ super(`${init.code}: ${title}`, { cause: init.cause });
70
+ this.code = init.code;
71
+ this.title = title;
72
+ this.fix = init.fix;
73
+ this.docs = init.docs ?? `https://ultimate.dev/errors/${init.code}`;
74
+ this.meta = init.meta;
75
+ }
76
+
77
+ /** The same 3-line rendering as `UltimateError.format()`. */
78
+ format(): string {
79
+ return [`${this.code}: ${this.title}`, ` cause: ${this.cause}`, ` fix: ${this.fix}`].join(
80
+ '\n',
81
+ );
82
+ }
83
+
84
+ toJSON(): SchemaErrorJSON {
85
+ return {
86
+ code: this.code,
87
+ title: this.title,
88
+ cause: this.cause,
89
+ fix: this.fix,
90
+ docs: this.docs,
91
+ meta: this.meta,
92
+ };
93
+ }
94
+ }
95
+
96
+ export interface ValidationIssue {
97
+ /** Dotted path from the validated root, e.g. `input.items[0].price`. */
98
+ readonly path: string;
99
+ readonly expected: string;
100
+ readonly received: string;
101
+ readonly message: string;
102
+ }
103
+
104
+ export class ValidationFailedError extends SchemaError {
105
+ static readonly code = 'X_VALIDATION_FAILED';
106
+ override readonly name = 'ValidationFailedError';
107
+ readonly issues: readonly ValidationIssue[];
108
+
109
+ constructor(issues: readonly ValidationIssue[], root = 'value') {
110
+ const cause = issues
111
+ .map((issue) => `${issue.path === '' ? root : issue.path}: ${issue.message}`)
112
+ .join('; ');
113
+ super({
114
+ code: ValidationFailedError.code,
115
+ cause,
116
+ fix: `send ${root} with the field(s) named in cause corrected to the expected type`,
117
+ meta: { issues },
118
+ });
119
+ this.issues = issues;
120
+ }
121
+
122
+ /** One line per issue — what the dev overlay and `x test --json` render. */
123
+ formatIssues(): string {
124
+ return formatIssues(this.issues)
125
+ .map((line) => ` ${line}`)
126
+ .join('\n');
127
+ }
128
+ }
129
+
130
+ export class SchemaUnsupportedError extends SchemaError {
131
+ static readonly code = 'X_SCHEMA_UNSUPPORTED';
132
+ override readonly name = 'SchemaUnsupportedError';
133
+ constructor(init: Omit<SchemaErrorInit, 'code'>) {
134
+ super({ ...init, code: SchemaUnsupportedError.code });
135
+ }
136
+ }
137
+
138
+ export function isSchemaError(value: unknown): value is SchemaError {
139
+ return typeof value === 'object' && value !== null && ULTIMATE_ERROR_BRAND in value;
140
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ export type { AnySchema, Check, CheckErr, CheckOk, CheckResult, Path, Schema, Shape, ShapeInput, ShapeOutput, Simplify, } from './builder';
2
+ export { checkOf, describeValue, expected, fail, failWith, makeSchema, pass, VENDOR, } from './builder';
3
+ export type { QuerySource } from './coerce';
4
+ export { coerceInput, coerceNode, coerceQuery } from './coerce';
5
+ export type { SchemaErrorCodeDeclaration, SchemaErrorInit, SchemaErrorJSON, ValidationIssue, } from './errors';
6
+ export { isSchemaError, SCHEMA_ERROR_CODES, SchemaError, SchemaUnsupportedError, ULTIMATE_ERROR_BRAND, ValidationFailedError, } from './errors';
7
+ export type { JsonSchema, JsonSchemaDialect, JsonSchemaType, ToJsonSchemaOptions, } from './json-schema';
8
+ export { nodeToJsonSchema, toJsonSchema, toMcpInputSchema } from './json-schema';
9
+ export type { SchemaFormat, SchemaKind, SchemaNode } from './node';
10
+ export { isSchemaNode, nodeOf, requiredKeys } from './node';
11
+ export type { SchemaProvider } from './provider';
12
+ export { builtinProvider, configureSchemaProvider, introspect, resetSchemaProvider, schemaProvider, tryIntrospect, } from './provider';
13
+ export type { InferInput, InferOutput, StandardFailureResult, StandardIssue, StandardPathSegment, StandardResult, StandardSchemaProps, StandardSchemaV1, StandardSuccessResult, StandardTypes, } from './standard';
14
+ export { formatPath, isStandardSchema, parse, parseAsync, toValidationIssues, validate, validateAsync, } from './standard';
15
+ export type { Infer } from './t';
16
+ export { t } from './t';
17
+ export type { MoneyValue, NumberSchema, ObjectSchema, StringSchema, TNamespace, } from './validators';
18
+ export { arraySchema, builtinT, enumSchema, literalSchema, objectSchema, optionalSchema, recordSchema, unionSchema, } from './validators';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,SAAS,EACT,KAAK,EACL,QAAQ,EACR,OAAO,EACP,WAAW,EACX,IAAI,EACJ,MAAM,EACN,KAAK,EACL,UAAU,EACV,WAAW,EACX,QAAQ,GACT,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,OAAO,EACP,aAAa,EACb,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,IAAI,EACJ,MAAM,GACP,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAChE,YAAY,EACV,0BAA0B,EAC1B,eAAe,EACf,eAAe,EACf,eAAe,GAChB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,WAAW,EACX,sBAAsB,EACtB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,mBAAmB,GACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjF,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAC5D,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,UAAU,EACV,mBAAmB,EACnB,cAAc,EACd,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,UAAU,EACV,WAAW,EACX,qBAAqB,EACrB,aAAa,EACb,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,EACrB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,KAAK,EACL,UAAU,EACV,kBAAkB,EAClB,QAAQ,EACR,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,YAAY,EACV,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,UAAU,GACX,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,WAAW,EACX,QAAQ,EACR,UAAU,EACV,aAAa,EACb,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,WAAW,GACZ,MAAM,cAAc,CAAC"}
package/src/index.js ADDED
@@ -0,0 +1,11 @@
1
+ // Single responsibility: the public API of @ultimat3/schema. Explicit named exports only.
2
+ export { checkOf, describeValue, expected, fail, failWith, makeSchema, pass, VENDOR, } from './builder';
3
+ export { coerceInput, coerceNode, coerceQuery } from './coerce';
4
+ export { isSchemaError, SCHEMA_ERROR_CODES, SchemaError, SchemaUnsupportedError, ULTIMATE_ERROR_BRAND, ValidationFailedError, } from './errors';
5
+ export { nodeToJsonSchema, toJsonSchema, toMcpInputSchema } from './json-schema';
6
+ export { isSchemaNode, nodeOf, requiredKeys } from './node';
7
+ export { builtinProvider, configureSchemaProvider, introspect, resetSchemaProvider, schemaProvider, tryIntrospect, } from './provider';
8
+ export { formatPath, isStandardSchema, parse, parseAsync, toValidationIssues, validate, validateAsync, } from './standard';
9
+ export { t } from './t';
10
+ export { arraySchema, builtinT, enumSchema, literalSchema, objectSchema, optionalSchema, recordSchema, unionSchema, } from './validators';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAe1F,OAAO,EACL,OAAO,EACP,aAAa,EACb,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,IAAI,EACJ,MAAM,GACP,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAOhE,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,WAAW,EACX,sBAAsB,EACtB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAOlB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjF,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAE5D,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,UAAU,EACV,mBAAmB,EACnB,cAAc,EACd,aAAa,GACd,MAAM,YAAY,CAAC;AAapB,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,KAAK,EACL,UAAU,EACV,kBAAkB,EAClB,QAAQ,EACR,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,OAAO,EACL,WAAW,EACX,QAAQ,EACR,UAAU,EACV,aAAa,EACb,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,WAAW,GACZ,MAAM,cAAc,CAAC"}
package/src/index.ts ADDED
@@ -0,0 +1,102 @@
1
+ // Single responsibility: the public API of @ultimat3/schema. Explicit named exports only.
2
+
3
+ export type {
4
+ AnySchema,
5
+ Check,
6
+ CheckErr,
7
+ CheckOk,
8
+ CheckResult,
9
+ Path,
10
+ Schema,
11
+ Shape,
12
+ ShapeInput,
13
+ ShapeOutput,
14
+ Simplify,
15
+ } from './builder';
16
+ export {
17
+ checkOf,
18
+ describeValue,
19
+ expected,
20
+ fail,
21
+ failWith,
22
+ makeSchema,
23
+ pass,
24
+ VENDOR,
25
+ } from './builder';
26
+ export type { QuerySource } from './coerce';
27
+ export { coerceInput, coerceNode, coerceQuery } from './coerce';
28
+ export type {
29
+ SchemaErrorCodeDeclaration,
30
+ SchemaErrorInit,
31
+ SchemaErrorJSON,
32
+ ValidationIssue,
33
+ } from './errors';
34
+ export {
35
+ isSchemaError,
36
+ SCHEMA_ERROR_CODES,
37
+ SchemaError,
38
+ SchemaUnsupportedError,
39
+ ULTIMATE_ERROR_BRAND,
40
+ ValidationFailedError,
41
+ } from './errors';
42
+ export type {
43
+ JsonSchema,
44
+ JsonSchemaDialect,
45
+ JsonSchemaType,
46
+ ToJsonSchemaOptions,
47
+ } from './json-schema';
48
+ export { nodeToJsonSchema, toJsonSchema, toMcpInputSchema } from './json-schema';
49
+ export type { SchemaFormat, SchemaKind, SchemaNode } from './node';
50
+ export { isSchemaNode, nodeOf, requiredKeys } from './node';
51
+ export type { SchemaProvider } from './provider';
52
+ export {
53
+ builtinProvider,
54
+ configureSchemaProvider,
55
+ introspect,
56
+ resetSchemaProvider,
57
+ schemaProvider,
58
+ tryIntrospect,
59
+ } from './provider';
60
+ export type {
61
+ FormattableIssue,
62
+ InferInput,
63
+ InferOutput,
64
+ StandardFailureResult,
65
+ StandardIssue,
66
+ StandardPathSegment,
67
+ StandardResult,
68
+ StandardSchemaProps,
69
+ StandardSchemaV1,
70
+ StandardSuccessResult,
71
+ StandardTypes,
72
+ } from './standard';
73
+ export {
74
+ formatIssues,
75
+ formatPath,
76
+ isStandardSchema,
77
+ parse,
78
+ parseAsync,
79
+ toValidationIssues,
80
+ validate,
81
+ validateAsync,
82
+ } from './standard';
83
+ export type { Infer } from './t';
84
+ export { t } from './t';
85
+ export type {
86
+ MoneyValue,
87
+ NumberSchema,
88
+ ObjectSchema,
89
+ StringSchema,
90
+ TNamespace,
91
+ } from './validators';
92
+ export {
93
+ arraySchema,
94
+ builtinT,
95
+ enumSchema,
96
+ literalSchema,
97
+ nullableSchema,
98
+ objectSchema,
99
+ optionalSchema,
100
+ recordSchema,
101
+ unionSchema,
102
+ } from './validators';
@@ -0,0 +1,37 @@
1
+ import { type SchemaNode } from './node';
2
+ export type JsonSchemaType = 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array';
3
+ export interface JsonSchema {
4
+ readonly $schema?: string;
5
+ readonly type?: JsonSchemaType;
6
+ readonly format?: string;
7
+ readonly description?: string;
8
+ readonly default?: unknown;
9
+ readonly minLength?: number;
10
+ readonly maxLength?: number;
11
+ readonly pattern?: string;
12
+ readonly minimum?: number;
13
+ readonly maximum?: number;
14
+ readonly enum?: readonly (string | number)[];
15
+ readonly const?: string | number | boolean | null;
16
+ readonly properties?: Readonly<Record<string, JsonSchema>>;
17
+ readonly required?: readonly string[];
18
+ readonly additionalProperties?: boolean | JsonSchema;
19
+ readonly items?: JsonSchema;
20
+ readonly anyOf?: readonly JsonSchema[];
21
+ readonly title?: string;
22
+ }
23
+ export type JsonSchemaDialect = '2020-12' | 'draft-07';
24
+ export interface ToJsonSchemaOptions {
25
+ /** MCP clients are happiest with `draft-07`; OpenAPI 3.1 wants `2020-12` (the default). */
26
+ readonly dialect?: JsonSchemaDialect | undefined;
27
+ /** Emit `$schema` at the root. Off for OpenAPI component schemas. */
28
+ readonly includeDialect?: boolean | undefined;
29
+ readonly title?: string | undefined;
30
+ }
31
+ /** Convert any schema the active provider can introspect. */
32
+ export declare function toJsonSchema(schema: unknown, options?: ToJsonSchemaOptions): JsonSchema;
33
+ /** The exact shape an MCP `tools/list` entry needs: draft-07, no `$schema`. */
34
+ export declare function toMcpInputSchema(schema: unknown): JsonSchema;
35
+ /** Convert an already-introspected node — used by generators that walk the IR themselves. */
36
+ export declare function nodeToJsonSchema(node: SchemaNode): JsonSchema;
37
+ //# sourceMappingURL=json-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-schema.d.ts","sourceRoot":"","sources":["json-schema.ts"],"names":[],"mappings":"AAIA,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGvD,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE9F,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC7C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IAClD,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IAC3D,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IACrD,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,UAAU,CAAC;AAOvD,MAAM,WAAW,mBAAmB;IAClC,2FAA2F;IAC3F,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACjD,qEAAqE;IACrE,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAsFD,6DAA6D;AAC7D,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,UAAU,CAQvF;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,GAAG,UAAU,CAE5D;AAED,6FAA6F;AAC7F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAE7D"}