autotel
Version:
Write Once, Observe Anywhere
133 lines (131 loc) • 4.55 kB
JavaScript
import { VALIDATION_ATTR, VALIDATION_ISSUE_CAP, VALIDATION_METRICS } from './chunk-DCEDJQGG.js';
import { hashJson } from './chunk-UNPLAVE7.js';
import { createCounter } from './chunk-TQ5UWA7S.js';
import { createStructuredError } from './chunk-LVIPBYFE.js';
import './chunk-J5QENANM.js';
import './chunk-HA2WBOGQ.js';
import { trace } from '@opentelemetry/api';
var mismatchCounter;
function counter() {
if (!mismatchCounter) {
mismatchCounter = createCounter(VALIDATION_METRICS.mismatches, {
description: "Input payloads that did not match their declared shape"
});
}
return mismatchCounter;
}
var listeners = /* @__PURE__ */ new Set();
function onValidationMismatch(handler) {
listeners.add(handler);
return () => {
listeners.delete(handler);
};
}
var truncate = (values) => values.slice(0, VALIDATION_ISSUE_CAP).join(",");
function recordValidationMismatch(mismatch) {
try {
const paths = mismatch.issues.map((i) => i.path).filter(Boolean);
const codes = [...new Set(mismatch.issues.map((i) => i.code))];
const span = trace.getActiveSpan();
if (span) {
span.setAttributes({
[VALIDATION_ATTR.name]: mismatch.name,
[VALIDATION_ATTR.boundary]: mismatch.boundary,
[VALIDATION_ATTR.mode]: mismatch.mode,
[VALIDATION_ATTR.issueCount]: mismatch.issues.length,
[VALIDATION_ATTR.issuePaths]: truncate(paths),
[VALIDATION_ATTR.issueCodes]: truncate(codes),
...mismatch.hash ? { [VALIDATION_ATTR.hash]: mismatch.hash } : {},
...mismatch.severity ? { [VALIDATION_ATTR.severity]: mismatch.severity } : {}
});
}
try {
counter().add(1, {
boundary: mismatch.boundary,
validation: mismatch.name,
mode: mismatch.mode
});
} catch {
}
for (const listener of listeners) {
try {
listener(mismatch);
} catch {
}
}
} catch {
}
}
function formatValidationIssues(error) {
const raw = extractRawIssues(error);
return raw.map((issue) => toSafeIssue(issue));
}
function extractRawIssues(error) {
if (error && typeof error === "object") {
const candidate = error.issues ?? error.errors;
if (Array.isArray(candidate)) {
return candidate.filter(
(i) => i !== null && typeof i === "object"
);
}
}
return [];
}
function toSafeIssue(issue) {
const rawPath = issue.path;
const path = Array.isArray(rawPath) ? rawPath.map(String).join(".") : typeof rawPath === "string" ? rawPath : "";
const code = typeof issue.code === "string" ? issue.code : "invalid";
const expected = typeof issue.expected === "string" ? issue.expected : void 0;
return expected ? { path, code, expected } : { path, code };
}
function defaultRejectError(issues, name) {
return createStructuredError({
name: "ValidationError",
status: 400,
code: "validation_failed",
message: `Input for "${name}" did not match its declared shape.`,
why: `${issues.length} field(s) failed validation: ${issues.map((i) => i.path || "(root)").slice(0, VALIDATION_ISSUE_CAP).join(", ")}.`,
fix: "Send a payload that matches the schema, or switch this validator to observe mode while you investigate.",
// PII-safe: paths + codes only, no received values.
details: { validation: name, issues }
});
}
function defineValidator(name, schema, options = {}) {
const mode = options.onMismatch ?? "reject";
const boundary = options.boundary ?? "input";
const hash = options.toJsonSchema ? hashJson(options.toJsonSchema(schema)) : void 0;
const record = (issues) => {
recordValidationMismatch({
name,
boundary,
mode,
issues,
hash,
severity: options.severity
});
};
return {
name,
mode,
safeParse(input) {
const parsed = schema.safeParse(input);
if (parsed.success) return { success: true, data: parsed.data };
const issues = formatValidationIssues(parsed.error);
record(issues);
return { success: false, issues };
},
parse(input) {
const parsed = schema.safeParse(input);
if (parsed.success) return parsed.data;
const issues = formatValidationIssues(parsed.error);
record(issues);
if (mode === "reject") {
throw options.onReject?.(issues, name) ?? defaultRejectError(issues, name);
}
return input;
}
};
}
export { defineValidator, formatValidationIssues, onValidationMismatch, recordValidationMismatch };
//# sourceMappingURL=validate.js.map
//# sourceMappingURL=validate.js.map