brass-runtime 1.15.0 → 1.16.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/CHANGELOG.md +17 -0
- package/README.md +673 -136
- package/dist/agent/cli/main.cjs +40 -35
- package/dist/agent/cli/main.js +9 -4
- package/dist/agent/cli/main.mjs +9 -4
- package/dist/agent/index.cjs +8 -4
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +7 -3
- package/dist/agent/index.mjs +7 -3
- package/dist/chunk-2HQTDLHF.mjs +683 -0
- package/dist/chunk-36I3M4UC.mjs +370 -0
- package/dist/chunk-3AYM6WPJ.js +1629 -0
- package/dist/chunk-3LOYJFRR.cjs +300 -0
- package/dist/chunk-3RG5ZIWI.js +10 -0
- package/dist/chunk-3Y2RIUMM.js +300 -0
- package/dist/{chunk-VEZNF5GZ.cjs → chunk-4ROBZFL6.cjs} +130 -126
- package/dist/{chunk-3QMOKAS5.js → chunk-52OB2ROS.js} +9 -5
- package/dist/chunk-52PPNNI4.cjs +416 -0
- package/dist/chunk-5EC274J5.cjs +2874 -0
- package/dist/chunk-5QC7LRZ3.js +229 -0
- package/dist/chunk-5VRJNBLZ.mjs +2874 -0
- package/dist/chunk-62AZW6UT.cjs +313 -0
- package/dist/chunk-6IXXWIUM.js +683 -0
- package/dist/chunk-74ZTY6CP.js +2871 -0
- package/dist/chunk-76YMRMH2.cjs +777 -0
- package/dist/chunk-7CMJS3QE.mjs +2871 -0
- package/dist/{chunk-4NHES7VK.mjs → chunk-7JIJOVCT.js} +27 -13
- package/dist/chunk-A2OM6NEH.mjs +194 -0
- package/dist/chunk-AGR5B2BC.cjs +683 -0
- package/dist/chunk-AVNQLJ5V.js +777 -0
- package/dist/chunk-B33ICAKP.js +313 -0
- package/dist/{chunk-ELOOF35R.mjs → chunk-B5JD23U7.mjs} +1 -1
- package/dist/chunk-BABBZK4Y.js +2024 -0
- package/dist/chunk-C3MDXTRZ.js +354 -0
- package/dist/chunk-CIZFIMK5.js +2193 -0
- package/dist/chunk-CZIVE6NT.cjs +354 -0
- package/dist/chunk-DNFJLJMW.mjs +354 -0
- package/dist/chunk-DNFO2EIZ.mjs +777 -0
- package/dist/chunk-EJ6BPYVR.mjs +416 -0
- package/dist/chunk-ENKODRU3.cjs +2193 -0
- package/dist/chunk-EOC4UHBS.mjs +229 -0
- package/dist/{chunk-BMH5AV44.js → chunk-FH2X7BVP.js} +756 -440
- package/dist/{chunk-PPUXIH5R.js → chunk-FHQGHPMO.mjs} +27 -13
- package/dist/{chunk-TGIFUAK4.cjs → chunk-GLE2WY7Z.cjs} +951 -635
- package/dist/{chunk-BDF4AMWX.mjs → chunk-GYM3LLGS.mjs} +756 -440
- package/dist/chunk-HLWLMW2F.mjs +2024 -0
- package/dist/chunk-JF5WGYJJ.cjs +194 -0
- package/dist/chunk-KH4SYAOS.mjs +1629 -0
- package/dist/chunk-KN32XNTH.mjs +313 -0
- package/dist/chunk-KQLYONSE.cjs +2871 -0
- package/dist/{chunk-STVLQ3XD.cjs → chunk-KZJQ723N.cjs} +92 -78
- package/dist/chunk-L2SYFEBS.js +194 -0
- package/dist/chunk-L6VB5N7Q.cjs +104 -0
- package/dist/{chunk-K6M7MDZ4.mjs → chunk-MBEJI5HF.mjs} +9 -5
- package/dist/chunk-MIIYDLGM.js +2874 -0
- package/dist/chunk-MOO4L7F4.mjs +104 -0
- package/dist/chunk-MT3OWDPC.mjs +2193 -0
- package/dist/chunk-MVGUEJ5Z.cjs +370 -0
- package/dist/chunk-OBGZSXTJ.cjs +10 -0
- package/dist/chunk-PD4EJTQC.cjs +229 -0
- package/dist/chunk-PWC3RBQE.mjs +300 -0
- package/dist/chunk-Q2I37RP3.cjs +1629 -0
- package/dist/chunk-RKGKFN2A.js +416 -0
- package/dist/{chunk-R3R2FVLG.cjs → chunk-SA6HUJVI.cjs} +5 -5
- package/dist/chunk-TRM4JUZQ.js +104 -0
- package/dist/chunk-UB4B6OFY.js +370 -0
- package/dist/{chunk-TO7IKXYT.js → chunk-UCUBNWM2.js} +1 -1
- package/dist/chunk-VN44DYYT.cjs +2024 -0
- package/dist/chunk-Y6FXYEAI.mjs +10 -0
- package/dist/client-CZHU674n.d.ts +820 -0
- package/dist/core/index.cjs +198 -4
- package/dist/core/index.d.ts +311 -212
- package/dist/core/index.js +237 -43
- package/dist/core/index.mjs +237 -43
- package/dist/{effect-CMOQKX8y.d.ts → effect-DIUHZ9IN.d.ts} +195 -1
- package/dist/effectRunner-CFLC32IK.cjs +8 -0
- package/dist/effectRunner-L4S7IPT3.js +8 -0
- package/dist/effectRunner-NNGG75QA.mjs +8 -0
- package/dist/http/index.cjs +1227 -2971
- package/dist/http/index.d.ts +826 -280
- package/dist/http/index.js +1089 -2833
- package/dist/http/index.mjs +1089 -2833
- package/dist/http/testing.cjs +161 -0
- package/dist/http/testing.d.ts +43 -0
- package/dist/http/testing.js +161 -0
- package/dist/http/testing.mjs +161 -0
- package/dist/index.cjs +486 -250
- package/dist/index.d.ts +87 -95
- package/dist/index.js +391 -155
- package/dist/index.mjs +391 -155
- package/dist/observability/index.cjs +162 -0
- package/dist/observability/index.d.ts +152 -0
- package/dist/observability/index.js +162 -0
- package/dist/observability/index.mjs +162 -0
- package/dist/perf/cli.cjs +401 -0
- package/dist/perf/cli.d.ts +1 -0
- package/dist/perf/cli.js +401 -0
- package/dist/perf/cli.mjs +401 -0
- package/dist/perf/index.cjs +141 -0
- package/dist/perf/index.d.ts +483 -0
- package/dist/perf/index.js +141 -0
- package/dist/perf/index.mjs +141 -0
- package/dist/schedule-CK3Ml_7p.d.ts +259 -0
- package/dist/schema/index.cjs +29 -0
- package/dist/schema/index.d.ts +179 -0
- package/dist/schema/index.js +29 -0
- package/dist/schema/index.mjs +29 -0
- package/dist/server-GJPg8ZSG.d.ts +675 -0
- package/dist/{stream-FQm9h4Mg.d.ts → stream-B4oK9JFP.d.ts} +1 -1
- package/dist/tracer-Hwt1cl7h.d.ts +189 -0
- package/dist/tracing-DqbTKGcf.d.ts +148 -0
- package/docs/ARCHITECTURE.md +292 -0
- package/docs/README.md +63 -0
- package/docs/adr/0001-ai-context-pack.md +32 -0
- package/docs/agent-apply-mode.md +104 -0
- package/docs/agent-approvals.md +110 -0
- package/docs/agent-batch.md +185 -0
- package/docs/agent-boundaries.md +112 -0
- package/docs/agent-chat-sessions.md +160 -0
- package/docs/agent-ci.md +17 -0
- package/docs/agent-cli.md +405 -0
- package/docs/agent-config.md +480 -0
- package/docs/agent-context-discovery.md +159 -0
- package/docs/agent-copilot-like-dx.md +126 -0
- package/docs/agent-declarative-optimized-planning.md +138 -0
- package/docs/agent-dx.md +224 -0
- package/docs/agent-env-files.md +126 -0
- package/docs/agent-follow-up-context.md +43 -0
- package/docs/agent-global-usage.md +180 -0
- package/docs/agent-init.md +109 -0
- package/docs/agent-install-and-configure.md +516 -0
- package/docs/agent-language-workspace-ux.md +99 -0
- package/docs/agent-llm-adapters.md +123 -0
- package/docs/agent-local-install.md +190 -0
- package/docs/agent-local-tests.md +51 -0
- package/docs/agent-observability.md +155 -0
- package/docs/agent-patch-quality-loop.md +162 -0
- package/docs/agent-presets.md +22 -0
- package/docs/agent-project-commands.md +237 -0
- package/docs/agent-project-intelligence.md +156 -0
- package/docs/agent-redaction.md +18 -0
- package/docs/agent-release-readiness.md +76 -0
- package/docs/agent-rollback-safety.md +162 -0
- package/docs/agent-rollback.md +23 -0
- package/docs/agent-run-artifacts.md +16 -0
- package/docs/agent-vscode-auto-discovery.md +137 -0
- package/docs/agent-vscode-batch-runner.md +100 -0
- package/docs/agent-vscode-chat-layout.md +90 -0
- package/docs/agent-vscode-clean-install.md +147 -0
- package/docs/agent-vscode-code-actions.md +70 -0
- package/docs/agent-vscode-diff-preview.md +45 -0
- package/docs/agent-vscode-inline-assist.md +56 -0
- package/docs/agent-vscode-install.md +186 -0
- package/docs/agent-vscode-model-setup.md +97 -0
- package/docs/agent-vscode-patch-preview.md +92 -0
- package/docs/agent-vscode-problems.md +79 -0
- package/docs/agent-vscode-project-dashboard.md +106 -0
- package/docs/agent-vscode-run-history.md +92 -0
- package/docs/agent-vscode-ux.md +73 -0
- package/docs/ai/INVARIANTS.md +84 -0
- package/docs/ai/PROJECT_MAP.md +338 -0
- package/docs/ai/PUBLIC_API.md +336 -0
- package/docs/ai/VALIDATION_MATRIX.md +67 -0
- package/docs/api-polish.md +37 -0
- package/docs/cancellation.md +162 -0
- package/docs/coverage.md +46 -0
- package/docs/getting-started.md +159 -0
- package/docs/guides/README.md +40 -0
- package/docs/guides/circuit-breaker.md +89 -0
- package/docs/guides/error-handling.md +91 -0
- package/docs/guides/getting-started.md +107 -0
- package/docs/guides/layers.md +189 -0
- package/docs/guides/metrics.md +101 -0
- package/docs/guides/resource-management.md +141 -0
- package/docs/guides/retry.md +215 -0
- package/docs/guides/semaphore.md +66 -0
- package/docs/guides/streams.md +117 -0
- package/docs/guides/supervisors.md +98 -0
- package/docs/guides/testing.md +162 -0
- package/docs/guides/tracing.md +71 -0
- package/docs/http-recipes.md +399 -0
- package/docs/http.md +749 -0
- package/docs/modules.md +285 -0
- package/docs/observability-collector-smoke.md +31 -0
- package/docs/observability-framework-examples.md +98 -0
- package/docs/observability.md +542 -0
- package/docs/otel-collector-smoke.yaml +27 -0
- package/docs/performance-profiler.md +199 -0
- package/docs/production-readiness.md +73 -0
- package/docs/recipes/README.md +12 -0
- package/docs/recipes/http-server.md +45 -0
- package/docs/recipes/layers.md +44 -0
- package/docs/recipes/performance.md +47 -0
- package/docs/recipes/runtime.md +41 -0
- package/docs/recipes/testing.md +41 -0
- package/docs/release.md +53 -0
- package/docs/wasm-bounded-queues.md +44 -0
- package/docs/wasm-engine-observability-benchmarks.md +85 -0
- package/docs/wasm-fiber-engine.md +117 -0
- package/docs/wasm-scheduler-state-machine.md +122 -0
- package/docs/wasm-stream-chunks.md +54 -0
- package/package.json +48 -2
- package/dist/chunk-AR22SXML.js +0 -1043
- package/dist/chunk-BDYEENHT.js +0 -224
- package/dist/chunk-JFPU5GQI.mjs +0 -1043
- package/dist/chunk-MS34J5LY.cjs +0 -224
- package/dist/chunk-UMAZLXAB.mjs +0 -224
- package/dist/chunk-XPZNXSVN.cjs +0 -1043
- package/dist/tracing-DNT9jEbr.d.ts +0 -106
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } var _class;// src/schema/index.ts
|
|
2
|
+
var SchemaValidationException = class extends Error {
|
|
3
|
+
|
|
4
|
+
constructor(issues) {
|
|
5
|
+
super(formatIssues(issues));
|
|
6
|
+
this.name = "SchemaValidationException";
|
|
7
|
+
this.issues = issues;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var ConfigValidationError = (_class = class extends Error {
|
|
11
|
+
__init() {this._tag = "ConfigValidationError"}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
constructor(configName, issues) {
|
|
15
|
+
super(`${configName} failed validation: ${formatIssues(issues)}`);_class.prototype.__init.call(this);;
|
|
16
|
+
this.name = "ConfigValidationError";
|
|
17
|
+
this.configName = configName;
|
|
18
|
+
this.issues = issues;
|
|
19
|
+
}
|
|
20
|
+
}, _class);
|
|
21
|
+
function isConfigValidationError(error) {
|
|
22
|
+
return error instanceof ConfigValidationError || typeof error === "object" && error !== null && error._tag === "ConfigValidationError" && typeof error.configName === "string" && Array.isArray(error.issues);
|
|
23
|
+
}
|
|
24
|
+
function formatConfigError(error) {
|
|
25
|
+
if (!isConfigValidationError(error)) {
|
|
26
|
+
return error instanceof Error ? error.message : String(error);
|
|
27
|
+
}
|
|
28
|
+
return `${error.configName} failed validation: ${formatIssues(error.issues)}`;
|
|
29
|
+
}
|
|
30
|
+
var ok = (data) => ({ success: true, data });
|
|
31
|
+
var fail = (issues) => ({ success: false, issues });
|
|
32
|
+
var receivedKind = (value) => {
|
|
33
|
+
if (value === null) return "null";
|
|
34
|
+
if (value === void 0) return "undefined";
|
|
35
|
+
if (Array.isArray(value)) return "array";
|
|
36
|
+
if (typeof value === "number" && Number.isNaN(value)) return "NaN";
|
|
37
|
+
return typeof value;
|
|
38
|
+
};
|
|
39
|
+
var pathLabel = (path) => path.length === 0 ? "$" : path.reduce((acc, part) => typeof part === "number" ? `${acc}[${part}]` : `${acc}.${part}`, "$");
|
|
40
|
+
var makeSchemaIssue = (path, expected, received, message) => ({
|
|
41
|
+
path,
|
|
42
|
+
expected,
|
|
43
|
+
received: receivedKind(received),
|
|
44
|
+
message: _nullishCoalesce(message, () => ( `Expected ${expected} at ${pathLabel(path)}, received ${receivedKind(received)}`))
|
|
45
|
+
});
|
|
46
|
+
function formatIssues(issues) {
|
|
47
|
+
if (issues.length === 0) return "Validation failed";
|
|
48
|
+
const preview = issues.slice(0, 3).map((issue) => `${pathLabel(issue.path)}: ${issue.message}`).join("; ");
|
|
49
|
+
return issues.length > 3 ? `${preview}; +${issues.length - 3} more` : preview;
|
|
50
|
+
}
|
|
51
|
+
function makeSchema(kind, isOptional, parser, name) {
|
|
52
|
+
const self = {
|
|
53
|
+
_tag: "Schema",
|
|
54
|
+
kind,
|
|
55
|
+
name,
|
|
56
|
+
isOptional,
|
|
57
|
+
_parse: parser,
|
|
58
|
+
safeParse: (input) => parser(input, []),
|
|
59
|
+
parse: (input) => {
|
|
60
|
+
const result = parser(input, []);
|
|
61
|
+
if (result.success) return result.data;
|
|
62
|
+
throw new SchemaValidationException(result.issues);
|
|
63
|
+
},
|
|
64
|
+
optional: () => makeSchema(
|
|
65
|
+
`${kind}.optional`,
|
|
66
|
+
true,
|
|
67
|
+
(input, path) => input === void 0 ? ok(void 0) : parser(input, path),
|
|
68
|
+
name
|
|
69
|
+
),
|
|
70
|
+
nullable: () => makeSchema(
|
|
71
|
+
`${kind}.nullable`,
|
|
72
|
+
isOptional,
|
|
73
|
+
(input, path) => input === null ? ok(null) : parser(input, path),
|
|
74
|
+
name
|
|
75
|
+
),
|
|
76
|
+
array: () => arraySchema(self),
|
|
77
|
+
refine: (predicate, message) => makeSchema(
|
|
78
|
+
`${kind}.refine`,
|
|
79
|
+
isOptional,
|
|
80
|
+
(input, path) => {
|
|
81
|
+
const result = parser(input, path);
|
|
82
|
+
if (!result.success) return result;
|
|
83
|
+
return predicate(result.data) ? result : fail([makeSchemaIssue(path, _nullishCoalesce(name, () => ( kind)), result.data, _nullishCoalesce(message, () => ( `Failed refinement for ${_nullishCoalesce(name, () => ( kind))}`)))]);
|
|
84
|
+
},
|
|
85
|
+
name
|
|
86
|
+
),
|
|
87
|
+
transform: (fn, expected) => makeSchema(
|
|
88
|
+
`${kind}.transform`,
|
|
89
|
+
false,
|
|
90
|
+
(input, path) => {
|
|
91
|
+
const result = parser(input, path);
|
|
92
|
+
if (!result.success) return result;
|
|
93
|
+
try {
|
|
94
|
+
return ok(fn(result.data));
|
|
95
|
+
} catch (error) {
|
|
96
|
+
return fail([
|
|
97
|
+
makeSchemaIssue(
|
|
98
|
+
path,
|
|
99
|
+
_nullishCoalesce(expected, () => ( `transform(${_nullishCoalesce(name, () => ( kind))})`)),
|
|
100
|
+
result.data,
|
|
101
|
+
error instanceof Error ? error.message : String(error)
|
|
102
|
+
)
|
|
103
|
+
]);
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
_nullishCoalesce(expected, () => ( name))
|
|
107
|
+
)
|
|
108
|
+
};
|
|
109
|
+
return self;
|
|
110
|
+
}
|
|
111
|
+
function stringSchema(options = {}) {
|
|
112
|
+
return makeSchema("string", false, (input, path) => {
|
|
113
|
+
if (typeof input !== "string") return fail([makeSchemaIssue(path, _nullishCoalesce(options.name, () => ( "string")), input)]);
|
|
114
|
+
if (options.minLength !== void 0 && input.length < options.minLength) {
|
|
115
|
+
return fail([makeSchemaIssue(path, `string length >= ${options.minLength}`, input, `Expected at least ${options.minLength} characters`)]);
|
|
116
|
+
}
|
|
117
|
+
if (options.maxLength !== void 0 && input.length > options.maxLength) {
|
|
118
|
+
return fail([makeSchemaIssue(path, `string length <= ${options.maxLength}`, input, `Expected at most ${options.maxLength} characters`)]);
|
|
119
|
+
}
|
|
120
|
+
if (options.pattern && !options.pattern.test(input)) {
|
|
121
|
+
return fail([makeSchemaIssue(path, `string matching ${String(options.pattern)}`, input)]);
|
|
122
|
+
}
|
|
123
|
+
return ok(input);
|
|
124
|
+
}, options.name);
|
|
125
|
+
}
|
|
126
|
+
function nonEmptyStringSchema(options = {}) {
|
|
127
|
+
return stringSchema({
|
|
128
|
+
...options,
|
|
129
|
+
minLength: 1,
|
|
130
|
+
name: _nullishCoalesce(options.name, () => ( "non-empty string"))
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
134
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
135
|
+
var ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}(?:[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:\d{2})?)?$/;
|
|
136
|
+
function emailSchema() {
|
|
137
|
+
return stringSchema({ pattern: EMAIL_PATTERN, name: "email" });
|
|
138
|
+
}
|
|
139
|
+
function uuidSchema() {
|
|
140
|
+
return stringSchema({ pattern: UUID_PATTERN, name: "uuid" });
|
|
141
|
+
}
|
|
142
|
+
function urlSchema() {
|
|
143
|
+
return stringSchema({ name: "url" }).refine((value) => {
|
|
144
|
+
try {
|
|
145
|
+
new URL(value);
|
|
146
|
+
return true;
|
|
147
|
+
} catch (e) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}, "Expected valid URL");
|
|
151
|
+
}
|
|
152
|
+
function dateIsoSchema() {
|
|
153
|
+
return stringSchema({ pattern: ISO_DATE_PATTERN, name: "ISO date" }).refine((value) => Number.isFinite(Date.parse(value)), "Expected valid ISO date string");
|
|
154
|
+
}
|
|
155
|
+
function numberSchema(options = {}) {
|
|
156
|
+
const finite = _nullishCoalesce(options.finite, () => ( true));
|
|
157
|
+
return makeSchema("number", false, (input, path) => {
|
|
158
|
+
if (typeof input !== "number" || Number.isNaN(input)) return fail([makeSchemaIssue(path, _nullishCoalesce(options.name, () => ( "number")), input)]);
|
|
159
|
+
if (finite && !Number.isFinite(input)) return fail([makeSchemaIssue(path, "finite number", input)]);
|
|
160
|
+
if (options.int && !Number.isInteger(input)) return fail([makeSchemaIssue(path, "integer", input)]);
|
|
161
|
+
if (options.min !== void 0 && input < options.min) return fail([makeSchemaIssue(path, `number >= ${options.min}`, input)]);
|
|
162
|
+
if (options.max !== void 0 && input > options.max) return fail([makeSchemaIssue(path, `number <= ${options.max}`, input)]);
|
|
163
|
+
return ok(input);
|
|
164
|
+
}, options.name);
|
|
165
|
+
}
|
|
166
|
+
function intSchema(options = {}) {
|
|
167
|
+
return numberSchema({
|
|
168
|
+
...options,
|
|
169
|
+
int: true,
|
|
170
|
+
name: _nullishCoalesce(options.name, () => ( "integer"))
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
function positiveSchema(options = {}) {
|
|
174
|
+
const min = Math.max(_nullishCoalesce(options.min, () => ( 0)), 0);
|
|
175
|
+
return numberSchema({
|
|
176
|
+
...options,
|
|
177
|
+
min,
|
|
178
|
+
name: _nullishCoalesce(options.name, () => ( "positive number"))
|
|
179
|
+
}).refine((value) => value > 0, "Expected positive number");
|
|
180
|
+
}
|
|
181
|
+
function booleanSchema(name) {
|
|
182
|
+
return makeSchema(
|
|
183
|
+
"boolean",
|
|
184
|
+
false,
|
|
185
|
+
(input, path) => typeof input === "boolean" ? ok(input) : fail([makeSchemaIssue(path, _nullishCoalesce(name, () => ( "boolean")), input)]),
|
|
186
|
+
name
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
function unknownSchema() {
|
|
190
|
+
return makeSchema("unknown", false, (input) => ok(input));
|
|
191
|
+
}
|
|
192
|
+
function anySchema() {
|
|
193
|
+
return makeSchema("any", false, (input) => ok(input));
|
|
194
|
+
}
|
|
195
|
+
function literalSchema(value) {
|
|
196
|
+
return makeSchema(
|
|
197
|
+
`literal(${JSON.stringify(value)})`,
|
|
198
|
+
false,
|
|
199
|
+
(input, path) => Object.is(input, value) ? ok(value) : fail([makeSchemaIssue(path, JSON.stringify(value), input)])
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
function enumSchema(values) {
|
|
203
|
+
const allowed = new Set(values);
|
|
204
|
+
const expected = values.map((value) => JSON.stringify(value)).join(" | ");
|
|
205
|
+
return makeSchema(
|
|
206
|
+
`enum(${expected})`,
|
|
207
|
+
false,
|
|
208
|
+
(input, path) => (typeof input === "string" || typeof input === "number") && allowed.has(input) ? ok(input) : fail([makeSchemaIssue(path, expected, input)])
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
function arraySchema(item) {
|
|
212
|
+
return makeSchema("array", false, (input, path) => {
|
|
213
|
+
if (!Array.isArray(input)) return fail([makeSchemaIssue(path, "array", input)]);
|
|
214
|
+
const out = [];
|
|
215
|
+
const issues = [];
|
|
216
|
+
input.forEach((value, index) => {
|
|
217
|
+
const result = item._parse(value, [...path, index]);
|
|
218
|
+
if (result.success) {
|
|
219
|
+
out.push(result.data);
|
|
220
|
+
} else {
|
|
221
|
+
issues.push(...result.issues);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
return issues.length > 0 ? fail(issues) : ok(out);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
function objectSchema(shape, options = {}) {
|
|
228
|
+
const unknownKeys = _nullishCoalesce(options.unknownKeys, () => ( "strip"));
|
|
229
|
+
return makeSchema("object", false, (input, path) => {
|
|
230
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
231
|
+
return fail([makeSchemaIssue(path, _nullishCoalesce(options.name, () => ( "object")), input)]);
|
|
232
|
+
}
|
|
233
|
+
const source = input;
|
|
234
|
+
const out = unknownKeys === "passthrough" ? { ...source } : {};
|
|
235
|
+
const issues = [];
|
|
236
|
+
const knownKeys = new Set(Object.keys(shape));
|
|
237
|
+
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
238
|
+
if (!(key in source)) {
|
|
239
|
+
if (!fieldSchema.isOptional) {
|
|
240
|
+
issues.push(makeSchemaIssue([...path, key], _nullishCoalesce(fieldSchema.name, () => ( fieldSchema.kind)), void 0, "Required field is missing"));
|
|
241
|
+
}
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
const result = fieldSchema._parse(source[key], [...path, key]);
|
|
245
|
+
if (result.success) {
|
|
246
|
+
out[key] = result.data;
|
|
247
|
+
} else {
|
|
248
|
+
issues.push(...result.issues);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (unknownKeys === "strict") {
|
|
252
|
+
for (const key of Object.keys(source)) {
|
|
253
|
+
if (!knownKeys.has(key)) {
|
|
254
|
+
issues.push(makeSchemaIssue([...path, key], "known key", source[key], "Unknown key is not allowed"));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return issues.length > 0 ? fail(issues) : ok(out);
|
|
259
|
+
}, options.name);
|
|
260
|
+
}
|
|
261
|
+
function recordSchema(valueSchema) {
|
|
262
|
+
return makeSchema("record", false, (input, path) => {
|
|
263
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
264
|
+
return fail([makeSchemaIssue(path, "record", input)]);
|
|
265
|
+
}
|
|
266
|
+
const out = {};
|
|
267
|
+
const issues = [];
|
|
268
|
+
for (const [key, value] of Object.entries(input)) {
|
|
269
|
+
const result = valueSchema._parse(value, [...path, key]);
|
|
270
|
+
if (result.success) {
|
|
271
|
+
out[key] = result.data;
|
|
272
|
+
} else {
|
|
273
|
+
issues.push(...result.issues);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return issues.length > 0 ? fail(issues) : ok(out);
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
function unionSchema(members) {
|
|
280
|
+
const expected = members.map((member) => _nullishCoalesce(member.name, () => ( member.kind))).join(" | ");
|
|
281
|
+
return makeSchema("union", false, (input, path) => {
|
|
282
|
+
const branchIssues = [];
|
|
283
|
+
for (const member of members) {
|
|
284
|
+
const result = member._parse(input, path);
|
|
285
|
+
if (result.success) return ok(result.data);
|
|
286
|
+
branchIssues.push(result.issues);
|
|
287
|
+
}
|
|
288
|
+
const mostSpecific = branchIssues.flatMap((issues) => issues).filter((issue) => issue.path.length > path.length).sort((a, b) => b.path.length - a.path.length);
|
|
289
|
+
if (mostSpecific.length > 0) return fail(mostSpecific);
|
|
290
|
+
return fail([makeSchemaIssue(path, expected, input)]);
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
function customSchema(guard, expected, message) {
|
|
294
|
+
return makeSchema(
|
|
295
|
+
expected,
|
|
296
|
+
false,
|
|
297
|
+
(input, path) => guard(input) ? ok(input) : fail([makeSchemaIssue(path, expected, input, message)]),
|
|
298
|
+
expected
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
var schema = Object.freeze({
|
|
302
|
+
string: stringSchema,
|
|
303
|
+
nonEmptyString: nonEmptyStringSchema,
|
|
304
|
+
email: emailSchema,
|
|
305
|
+
url: urlSchema,
|
|
306
|
+
uuid: uuidSchema,
|
|
307
|
+
dateIso: dateIsoSchema,
|
|
308
|
+
number: numberSchema,
|
|
309
|
+
int: intSchema,
|
|
310
|
+
positive: positiveSchema,
|
|
311
|
+
boolean: booleanSchema,
|
|
312
|
+
literal: literalSchema,
|
|
313
|
+
enum: enumSchema,
|
|
314
|
+
array: arraySchema,
|
|
315
|
+
object: objectSchema,
|
|
316
|
+
record: recordSchema,
|
|
317
|
+
union: unionSchema,
|
|
318
|
+
optional: (inner) => inner.optional(),
|
|
319
|
+
nullable: (inner) => inner.nullable(),
|
|
320
|
+
unknown: unknownSchema,
|
|
321
|
+
any: anySchema,
|
|
322
|
+
custom: customSchema
|
|
323
|
+
});
|
|
324
|
+
var s = schema;
|
|
325
|
+
var Schema = schema;
|
|
326
|
+
function isSchema(value) {
|
|
327
|
+
return typeof value === "object" && value !== null && value._tag === "Schema" && typeof value.safeParse === "function" && typeof value._parse === "function";
|
|
328
|
+
}
|
|
329
|
+
function validateValue(data, validator) {
|
|
330
|
+
if (isSchema(validator)) return validator.safeParse(data);
|
|
331
|
+
const result = validator(data);
|
|
332
|
+
if (result.success) return ok(result.data);
|
|
333
|
+
return fail(_nullishCoalesce(result.issues, () => ( [makeSchemaIssue([], "valid JSON shape", data, result.error)])));
|
|
334
|
+
}
|
|
335
|
+
function parseConfig(configName, validator, value) {
|
|
336
|
+
const result = validateValue(value, validator);
|
|
337
|
+
if (result.success) return result.data;
|
|
338
|
+
throw new ConfigValidationError(configName, result.issues);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
exports.SchemaValidationException = SchemaValidationException; exports.ConfigValidationError = ConfigValidationError; exports.isConfigValidationError = isConfigValidationError; exports.formatConfigError = formatConfigError; exports.makeSchemaIssue = makeSchemaIssue; exports.formatIssues = formatIssues; exports.schema = schema; exports.s = s; exports.Schema = Schema; exports.isSchema = isSchema; exports.validateValue = validateValue; exports.parseConfig = parseConfig;
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
// src/schema/index.ts
|
|
2
|
+
var SchemaValidationException = class extends Error {
|
|
3
|
+
issues;
|
|
4
|
+
constructor(issues) {
|
|
5
|
+
super(formatIssues(issues));
|
|
6
|
+
this.name = "SchemaValidationException";
|
|
7
|
+
this.issues = issues;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var ConfigValidationError = class extends Error {
|
|
11
|
+
_tag = "ConfigValidationError";
|
|
12
|
+
configName;
|
|
13
|
+
issues;
|
|
14
|
+
constructor(configName, issues) {
|
|
15
|
+
super(`${configName} failed validation: ${formatIssues(issues)}`);
|
|
16
|
+
this.name = "ConfigValidationError";
|
|
17
|
+
this.configName = configName;
|
|
18
|
+
this.issues = issues;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
function isConfigValidationError(error) {
|
|
22
|
+
return error instanceof ConfigValidationError || typeof error === "object" && error !== null && error._tag === "ConfigValidationError" && typeof error.configName === "string" && Array.isArray(error.issues);
|
|
23
|
+
}
|
|
24
|
+
function formatConfigError(error) {
|
|
25
|
+
if (!isConfigValidationError(error)) {
|
|
26
|
+
return error instanceof Error ? error.message : String(error);
|
|
27
|
+
}
|
|
28
|
+
return `${error.configName} failed validation: ${formatIssues(error.issues)}`;
|
|
29
|
+
}
|
|
30
|
+
var ok = (data) => ({ success: true, data });
|
|
31
|
+
var fail = (issues) => ({ success: false, issues });
|
|
32
|
+
var receivedKind = (value) => {
|
|
33
|
+
if (value === null) return "null";
|
|
34
|
+
if (value === void 0) return "undefined";
|
|
35
|
+
if (Array.isArray(value)) return "array";
|
|
36
|
+
if (typeof value === "number" && Number.isNaN(value)) return "NaN";
|
|
37
|
+
return typeof value;
|
|
38
|
+
};
|
|
39
|
+
var pathLabel = (path) => path.length === 0 ? "$" : path.reduce((acc, part) => typeof part === "number" ? `${acc}[${part}]` : `${acc}.${part}`, "$");
|
|
40
|
+
var makeSchemaIssue = (path, expected, received, message) => ({
|
|
41
|
+
path,
|
|
42
|
+
expected,
|
|
43
|
+
received: receivedKind(received),
|
|
44
|
+
message: message ?? `Expected ${expected} at ${pathLabel(path)}, received ${receivedKind(received)}`
|
|
45
|
+
});
|
|
46
|
+
function formatIssues(issues) {
|
|
47
|
+
if (issues.length === 0) return "Validation failed";
|
|
48
|
+
const preview = issues.slice(0, 3).map((issue) => `${pathLabel(issue.path)}: ${issue.message}`).join("; ");
|
|
49
|
+
return issues.length > 3 ? `${preview}; +${issues.length - 3} more` : preview;
|
|
50
|
+
}
|
|
51
|
+
function makeSchema(kind, isOptional, parser, name) {
|
|
52
|
+
const self = {
|
|
53
|
+
_tag: "Schema",
|
|
54
|
+
kind,
|
|
55
|
+
name,
|
|
56
|
+
isOptional,
|
|
57
|
+
_parse: parser,
|
|
58
|
+
safeParse: (input) => parser(input, []),
|
|
59
|
+
parse: (input) => {
|
|
60
|
+
const result = parser(input, []);
|
|
61
|
+
if (result.success) return result.data;
|
|
62
|
+
throw new SchemaValidationException(result.issues);
|
|
63
|
+
},
|
|
64
|
+
optional: () => makeSchema(
|
|
65
|
+
`${kind}.optional`,
|
|
66
|
+
true,
|
|
67
|
+
(input, path) => input === void 0 ? ok(void 0) : parser(input, path),
|
|
68
|
+
name
|
|
69
|
+
),
|
|
70
|
+
nullable: () => makeSchema(
|
|
71
|
+
`${kind}.nullable`,
|
|
72
|
+
isOptional,
|
|
73
|
+
(input, path) => input === null ? ok(null) : parser(input, path),
|
|
74
|
+
name
|
|
75
|
+
),
|
|
76
|
+
array: () => arraySchema(self),
|
|
77
|
+
refine: (predicate, message) => makeSchema(
|
|
78
|
+
`${kind}.refine`,
|
|
79
|
+
isOptional,
|
|
80
|
+
(input, path) => {
|
|
81
|
+
const result = parser(input, path);
|
|
82
|
+
if (!result.success) return result;
|
|
83
|
+
return predicate(result.data) ? result : fail([makeSchemaIssue(path, name ?? kind, result.data, message ?? `Failed refinement for ${name ?? kind}`)]);
|
|
84
|
+
},
|
|
85
|
+
name
|
|
86
|
+
),
|
|
87
|
+
transform: (fn, expected) => makeSchema(
|
|
88
|
+
`${kind}.transform`,
|
|
89
|
+
false,
|
|
90
|
+
(input, path) => {
|
|
91
|
+
const result = parser(input, path);
|
|
92
|
+
if (!result.success) return result;
|
|
93
|
+
try {
|
|
94
|
+
return ok(fn(result.data));
|
|
95
|
+
} catch (error) {
|
|
96
|
+
return fail([
|
|
97
|
+
makeSchemaIssue(
|
|
98
|
+
path,
|
|
99
|
+
expected ?? `transform(${name ?? kind})`,
|
|
100
|
+
result.data,
|
|
101
|
+
error instanceof Error ? error.message : String(error)
|
|
102
|
+
)
|
|
103
|
+
]);
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
expected ?? name
|
|
107
|
+
)
|
|
108
|
+
};
|
|
109
|
+
return self;
|
|
110
|
+
}
|
|
111
|
+
function stringSchema(options = {}) {
|
|
112
|
+
return makeSchema("string", false, (input, path) => {
|
|
113
|
+
if (typeof input !== "string") return fail([makeSchemaIssue(path, options.name ?? "string", input)]);
|
|
114
|
+
if (options.minLength !== void 0 && input.length < options.minLength) {
|
|
115
|
+
return fail([makeSchemaIssue(path, `string length >= ${options.minLength}`, input, `Expected at least ${options.minLength} characters`)]);
|
|
116
|
+
}
|
|
117
|
+
if (options.maxLength !== void 0 && input.length > options.maxLength) {
|
|
118
|
+
return fail([makeSchemaIssue(path, `string length <= ${options.maxLength}`, input, `Expected at most ${options.maxLength} characters`)]);
|
|
119
|
+
}
|
|
120
|
+
if (options.pattern && !options.pattern.test(input)) {
|
|
121
|
+
return fail([makeSchemaIssue(path, `string matching ${String(options.pattern)}`, input)]);
|
|
122
|
+
}
|
|
123
|
+
return ok(input);
|
|
124
|
+
}, options.name);
|
|
125
|
+
}
|
|
126
|
+
function nonEmptyStringSchema(options = {}) {
|
|
127
|
+
return stringSchema({
|
|
128
|
+
...options,
|
|
129
|
+
minLength: 1,
|
|
130
|
+
name: options.name ?? "non-empty string"
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
134
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
135
|
+
var ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}(?:[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:\d{2})?)?$/;
|
|
136
|
+
function emailSchema() {
|
|
137
|
+
return stringSchema({ pattern: EMAIL_PATTERN, name: "email" });
|
|
138
|
+
}
|
|
139
|
+
function uuidSchema() {
|
|
140
|
+
return stringSchema({ pattern: UUID_PATTERN, name: "uuid" });
|
|
141
|
+
}
|
|
142
|
+
function urlSchema() {
|
|
143
|
+
return stringSchema({ name: "url" }).refine((value) => {
|
|
144
|
+
try {
|
|
145
|
+
new URL(value);
|
|
146
|
+
return true;
|
|
147
|
+
} catch {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}, "Expected valid URL");
|
|
151
|
+
}
|
|
152
|
+
function dateIsoSchema() {
|
|
153
|
+
return stringSchema({ pattern: ISO_DATE_PATTERN, name: "ISO date" }).refine((value) => Number.isFinite(Date.parse(value)), "Expected valid ISO date string");
|
|
154
|
+
}
|
|
155
|
+
function numberSchema(options = {}) {
|
|
156
|
+
const finite = options.finite ?? true;
|
|
157
|
+
return makeSchema("number", false, (input, path) => {
|
|
158
|
+
if (typeof input !== "number" || Number.isNaN(input)) return fail([makeSchemaIssue(path, options.name ?? "number", input)]);
|
|
159
|
+
if (finite && !Number.isFinite(input)) return fail([makeSchemaIssue(path, "finite number", input)]);
|
|
160
|
+
if (options.int && !Number.isInteger(input)) return fail([makeSchemaIssue(path, "integer", input)]);
|
|
161
|
+
if (options.min !== void 0 && input < options.min) return fail([makeSchemaIssue(path, `number >= ${options.min}`, input)]);
|
|
162
|
+
if (options.max !== void 0 && input > options.max) return fail([makeSchemaIssue(path, `number <= ${options.max}`, input)]);
|
|
163
|
+
return ok(input);
|
|
164
|
+
}, options.name);
|
|
165
|
+
}
|
|
166
|
+
function intSchema(options = {}) {
|
|
167
|
+
return numberSchema({
|
|
168
|
+
...options,
|
|
169
|
+
int: true,
|
|
170
|
+
name: options.name ?? "integer"
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
function positiveSchema(options = {}) {
|
|
174
|
+
const min = Math.max(options.min ?? 0, 0);
|
|
175
|
+
return numberSchema({
|
|
176
|
+
...options,
|
|
177
|
+
min,
|
|
178
|
+
name: options.name ?? "positive number"
|
|
179
|
+
}).refine((value) => value > 0, "Expected positive number");
|
|
180
|
+
}
|
|
181
|
+
function booleanSchema(name) {
|
|
182
|
+
return makeSchema(
|
|
183
|
+
"boolean",
|
|
184
|
+
false,
|
|
185
|
+
(input, path) => typeof input === "boolean" ? ok(input) : fail([makeSchemaIssue(path, name ?? "boolean", input)]),
|
|
186
|
+
name
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
function unknownSchema() {
|
|
190
|
+
return makeSchema("unknown", false, (input) => ok(input));
|
|
191
|
+
}
|
|
192
|
+
function anySchema() {
|
|
193
|
+
return makeSchema("any", false, (input) => ok(input));
|
|
194
|
+
}
|
|
195
|
+
function literalSchema(value) {
|
|
196
|
+
return makeSchema(
|
|
197
|
+
`literal(${JSON.stringify(value)})`,
|
|
198
|
+
false,
|
|
199
|
+
(input, path) => Object.is(input, value) ? ok(value) : fail([makeSchemaIssue(path, JSON.stringify(value), input)])
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
function enumSchema(values) {
|
|
203
|
+
const allowed = new Set(values);
|
|
204
|
+
const expected = values.map((value) => JSON.stringify(value)).join(" | ");
|
|
205
|
+
return makeSchema(
|
|
206
|
+
`enum(${expected})`,
|
|
207
|
+
false,
|
|
208
|
+
(input, path) => (typeof input === "string" || typeof input === "number") && allowed.has(input) ? ok(input) : fail([makeSchemaIssue(path, expected, input)])
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
function arraySchema(item) {
|
|
212
|
+
return makeSchema("array", false, (input, path) => {
|
|
213
|
+
if (!Array.isArray(input)) return fail([makeSchemaIssue(path, "array", input)]);
|
|
214
|
+
const out = [];
|
|
215
|
+
const issues = [];
|
|
216
|
+
input.forEach((value, index) => {
|
|
217
|
+
const result = item._parse(value, [...path, index]);
|
|
218
|
+
if (result.success) {
|
|
219
|
+
out.push(result.data);
|
|
220
|
+
} else {
|
|
221
|
+
issues.push(...result.issues);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
return issues.length > 0 ? fail(issues) : ok(out);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
function objectSchema(shape, options = {}) {
|
|
228
|
+
const unknownKeys = options.unknownKeys ?? "strip";
|
|
229
|
+
return makeSchema("object", false, (input, path) => {
|
|
230
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
231
|
+
return fail([makeSchemaIssue(path, options.name ?? "object", input)]);
|
|
232
|
+
}
|
|
233
|
+
const source = input;
|
|
234
|
+
const out = unknownKeys === "passthrough" ? { ...source } : {};
|
|
235
|
+
const issues = [];
|
|
236
|
+
const knownKeys = new Set(Object.keys(shape));
|
|
237
|
+
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
238
|
+
if (!(key in source)) {
|
|
239
|
+
if (!fieldSchema.isOptional) {
|
|
240
|
+
issues.push(makeSchemaIssue([...path, key], fieldSchema.name ?? fieldSchema.kind, void 0, "Required field is missing"));
|
|
241
|
+
}
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
const result = fieldSchema._parse(source[key], [...path, key]);
|
|
245
|
+
if (result.success) {
|
|
246
|
+
out[key] = result.data;
|
|
247
|
+
} else {
|
|
248
|
+
issues.push(...result.issues);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (unknownKeys === "strict") {
|
|
252
|
+
for (const key of Object.keys(source)) {
|
|
253
|
+
if (!knownKeys.has(key)) {
|
|
254
|
+
issues.push(makeSchemaIssue([...path, key], "known key", source[key], "Unknown key is not allowed"));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return issues.length > 0 ? fail(issues) : ok(out);
|
|
259
|
+
}, options.name);
|
|
260
|
+
}
|
|
261
|
+
function recordSchema(valueSchema) {
|
|
262
|
+
return makeSchema("record", false, (input, path) => {
|
|
263
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
264
|
+
return fail([makeSchemaIssue(path, "record", input)]);
|
|
265
|
+
}
|
|
266
|
+
const out = {};
|
|
267
|
+
const issues = [];
|
|
268
|
+
for (const [key, value] of Object.entries(input)) {
|
|
269
|
+
const result = valueSchema._parse(value, [...path, key]);
|
|
270
|
+
if (result.success) {
|
|
271
|
+
out[key] = result.data;
|
|
272
|
+
} else {
|
|
273
|
+
issues.push(...result.issues);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return issues.length > 0 ? fail(issues) : ok(out);
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
function unionSchema(members) {
|
|
280
|
+
const expected = members.map((member) => member.name ?? member.kind).join(" | ");
|
|
281
|
+
return makeSchema("union", false, (input, path) => {
|
|
282
|
+
const branchIssues = [];
|
|
283
|
+
for (const member of members) {
|
|
284
|
+
const result = member._parse(input, path);
|
|
285
|
+
if (result.success) return ok(result.data);
|
|
286
|
+
branchIssues.push(result.issues);
|
|
287
|
+
}
|
|
288
|
+
const mostSpecific = branchIssues.flatMap((issues) => issues).filter((issue) => issue.path.length > path.length).sort((a, b) => b.path.length - a.path.length);
|
|
289
|
+
if (mostSpecific.length > 0) return fail(mostSpecific);
|
|
290
|
+
return fail([makeSchemaIssue(path, expected, input)]);
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
function customSchema(guard, expected, message) {
|
|
294
|
+
return makeSchema(
|
|
295
|
+
expected,
|
|
296
|
+
false,
|
|
297
|
+
(input, path) => guard(input) ? ok(input) : fail([makeSchemaIssue(path, expected, input, message)]),
|
|
298
|
+
expected
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
var schema = Object.freeze({
|
|
302
|
+
string: stringSchema,
|
|
303
|
+
nonEmptyString: nonEmptyStringSchema,
|
|
304
|
+
email: emailSchema,
|
|
305
|
+
url: urlSchema,
|
|
306
|
+
uuid: uuidSchema,
|
|
307
|
+
dateIso: dateIsoSchema,
|
|
308
|
+
number: numberSchema,
|
|
309
|
+
int: intSchema,
|
|
310
|
+
positive: positiveSchema,
|
|
311
|
+
boolean: booleanSchema,
|
|
312
|
+
literal: literalSchema,
|
|
313
|
+
enum: enumSchema,
|
|
314
|
+
array: arraySchema,
|
|
315
|
+
object: objectSchema,
|
|
316
|
+
record: recordSchema,
|
|
317
|
+
union: unionSchema,
|
|
318
|
+
optional: (inner) => inner.optional(),
|
|
319
|
+
nullable: (inner) => inner.nullable(),
|
|
320
|
+
unknown: unknownSchema,
|
|
321
|
+
any: anySchema,
|
|
322
|
+
custom: customSchema
|
|
323
|
+
});
|
|
324
|
+
var s = schema;
|
|
325
|
+
var Schema = schema;
|
|
326
|
+
function isSchema(value) {
|
|
327
|
+
return typeof value === "object" && value !== null && value._tag === "Schema" && typeof value.safeParse === "function" && typeof value._parse === "function";
|
|
328
|
+
}
|
|
329
|
+
function validateValue(data, validator) {
|
|
330
|
+
if (isSchema(validator)) return validator.safeParse(data);
|
|
331
|
+
const result = validator(data);
|
|
332
|
+
if (result.success) return ok(result.data);
|
|
333
|
+
return fail(result.issues ?? [makeSchemaIssue([], "valid JSON shape", data, result.error)]);
|
|
334
|
+
}
|
|
335
|
+
function parseConfig(configName, validator, value) {
|
|
336
|
+
const result = validateValue(value, validator);
|
|
337
|
+
if (result.success) return result.data;
|
|
338
|
+
throw new ConfigValidationError(configName, result.issues);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export {
|
|
342
|
+
SchemaValidationException,
|
|
343
|
+
ConfigValidationError,
|
|
344
|
+
isConfigValidationError,
|
|
345
|
+
formatConfigError,
|
|
346
|
+
makeSchemaIssue,
|
|
347
|
+
formatIssues,
|
|
348
|
+
schema,
|
|
349
|
+
s,
|
|
350
|
+
Schema,
|
|
351
|
+
isSchema,
|
|
352
|
+
validateValue,
|
|
353
|
+
parseConfig
|
|
354
|
+
};
|