feat: add form and page platform
This commit is contained in:
@@ -195,6 +195,7 @@ export const ERROR_REGISTRY = Object.freeze({
|
||||
* requestId?: string,
|
||||
* traceId?: string,
|
||||
* retryAfterMs?: number,
|
||||
* validationIssues?: readonly Readonly<{path: string, code: string}>[],
|
||||
* userMessageKey: string,
|
||||
* action: ErrorAction,
|
||||
* causeClass?: string
|
||||
@@ -211,6 +212,7 @@ export const ERROR_REGISTRY = Object.freeze({
|
||||
* requestId?: string,
|
||||
* traceId?: string,
|
||||
* retryAfterMs?: number,
|
||||
* validationIssues?: readonly Readonly<{path: string, code: string}>[],
|
||||
* causeClass?: string
|
||||
* }} [details]
|
||||
* @returns {ApiFailure}
|
||||
@@ -236,6 +238,24 @@ export function createFailure(kind, operationId, attempt, details = {}) {
|
||||
...(typeof details.retryAfterMs === "number"
|
||||
? { retryAfterMs: details.retryAfterMs }
|
||||
: {}),
|
||||
...(Array.isArray(details.validationIssues)
|
||||
? {
|
||||
validationIssues: Object.freeze(
|
||||
details.validationIssues
|
||||
.filter(
|
||||
(issue) =>
|
||||
issue &&
|
||||
typeof issue === "object" &&
|
||||
typeof issue.path === "string" &&
|
||||
typeof issue.code === "string",
|
||||
)
|
||||
.slice(0, 50)
|
||||
.map((issue) =>
|
||||
Object.freeze({ path: issue.path, code: issue.code }),
|
||||
),
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
...(typeof details.causeClass === "string"
|
||||
? { causeClass: details.causeClass }
|
||||
: {}),
|
||||
@@ -244,6 +264,44 @@ export function createFailure(kind, operationId, attempt, details = {}) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Projects an untrusted 422 details payload into the only validation metadata
|
||||
* allowed to cross the HTTP boundary. Backend copy and additional values are
|
||||
* deliberately discarded.
|
||||
*
|
||||
* @param {unknown} value
|
||||
* @returns {readonly Readonly<{path: string, code: string}>[]}
|
||||
*/
|
||||
export function safeValidationIssues(value) {
|
||||
if (!value || typeof value !== "object") return Object.freeze([]);
|
||||
const candidate =
|
||||
/** @type {{issues?: unknown, fieldErrors?: unknown}} */ (value);
|
||||
const issues = Array.isArray(candidate.issues)
|
||||
? candidate.issues
|
||||
: Array.isArray(candidate.fieldErrors)
|
||||
? candidate.fieldErrors
|
||||
: [];
|
||||
return Object.freeze(
|
||||
issues
|
||||
.filter(
|
||||
(issue) =>
|
||||
issue &&
|
||||
typeof issue === "object" &&
|
||||
typeof issue.path === "string" &&
|
||||
typeof issue.code === "string" &&
|
||||
issue.path.length <= 120 &&
|
||||
issue.code.length <= 80,
|
||||
)
|
||||
.slice(0, 50)
|
||||
.map((issue) =>
|
||||
Object.freeze({
|
||||
path: issue.path,
|
||||
code: issue.code,
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/** @param {number} status */
|
||||
export function kindForStatus(status) {
|
||||
if (status === 401) return "AUTH_REQUIRED";
|
||||
|
||||
Reference in New Issue
Block a user