@holo-js/forms 0.1.4 → 0.1.5
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/dist/chunk-GH4IN2OV.mjs +59 -0
- package/dist/chunk-GPWXGHZE.mjs +40 -0
- package/dist/chunk-OFPH5LBY.mjs +11 -0
- package/dist/chunk-WJOAU4V2.mjs +162 -0
- package/dist/contracts-D1dERmQn.d.ts +131 -0
- package/dist/index.d.ts +4 -97
- package/dist/index.mjs +500 -12
- package/dist/internal/client.d.ts +68 -0
- package/dist/internal/client.mjs +833 -0
- package/dist/schema.d.ts +13 -0
- package/dist/schema.mjs +26 -0
- package/dist/security-ODATEIFI.mjs +48 -0
- package/package.json +13 -8
- package/dist/chunk-663LOLKH.mjs +0 -421
- package/dist/client.d.ts +0 -52
- package/dist/client.mjs +0 -527
package/dist/index.mjs
CHANGED
|
@@ -1,23 +1,508 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
createSuccessfulSubmission,
|
|
5
|
-
formsInternals,
|
|
6
|
-
isFormSchema,
|
|
7
|
-
schema,
|
|
8
|
-
validate
|
|
9
|
-
} from "./chunk-663LOLKH.mjs";
|
|
10
|
-
|
|
11
|
-
// src/index.ts
|
|
12
|
-
import {
|
|
2
|
+
DEFAULT_VALIDATION_BAG,
|
|
3
|
+
ValidationException,
|
|
13
4
|
createErrorBag,
|
|
14
5
|
defineSchema,
|
|
15
6
|
field,
|
|
7
|
+
isFormSchema,
|
|
8
|
+
isValidationException,
|
|
16
9
|
parse,
|
|
17
|
-
|
|
10
|
+
schema
|
|
11
|
+
} from "./chunk-GPWXGHZE.mjs";
|
|
12
|
+
import {
|
|
13
|
+
normalizeFailureErrors,
|
|
14
|
+
normalizeFailureInput,
|
|
15
|
+
normalizeStatus,
|
|
16
|
+
sanitizeFlashedInput,
|
|
17
|
+
sensitiveInputInternals
|
|
18
|
+
} from "./chunk-WJOAU4V2.mjs";
|
|
19
|
+
import {
|
|
20
|
+
FormContractError
|
|
21
|
+
} from "./chunk-OFPH5LBY.mjs";
|
|
22
|
+
|
|
23
|
+
// src/contracts.ts
|
|
24
|
+
import {
|
|
25
|
+
ValidationException as ValidationException2,
|
|
26
|
+
createErrorBag as createErrorBag2,
|
|
27
|
+
safeParse as safeParseInput,
|
|
28
|
+
validationInternals
|
|
18
29
|
} from "@holo-js/validation";
|
|
30
|
+
var nextHeadersModuleSpecifier = "next/headers";
|
|
31
|
+
var h3RawBodySymbol = /* @__PURE__ */ Symbol.for("h3RawBody");
|
|
32
|
+
function serializeSubmissionState(valid, values, errors, schemaDefinition) {
|
|
33
|
+
return Object.freeze({
|
|
34
|
+
valid,
|
|
35
|
+
submitted: true,
|
|
36
|
+
values: sanitizeFlashedInput(values, schemaDefinition),
|
|
37
|
+
errors: errors.flatten()
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function createSubmission(valid, values, errors, failureStatus = 422, schemaDefinition, failureMetadata = {}) {
|
|
41
|
+
const normalizedFailureStatus = normalizeStatus(failureStatus, 422);
|
|
42
|
+
const serialize = () => serializeSubmissionState(valid, values, errors, schemaDefinition);
|
|
43
|
+
const failure = (input) => {
|
|
44
|
+
const normalized = normalizeFailureInput(input, normalizedFailureStatus);
|
|
45
|
+
return {
|
|
46
|
+
ok: false,
|
|
47
|
+
status: normalized.status,
|
|
48
|
+
valid: false,
|
|
49
|
+
values: sanitizeFlashedInput(values, schemaDefinition),
|
|
50
|
+
errors: normalizeFailureErrors(errors.flatten(), normalized.errors),
|
|
51
|
+
...normalized.status === 429 ? failureMetadata : {}
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
const success = (payload, status) => ({
|
|
55
|
+
ok: true,
|
|
56
|
+
status: normalizeStatus(status, 200),
|
|
57
|
+
data: payload
|
|
58
|
+
});
|
|
59
|
+
if (valid) {
|
|
60
|
+
const data = values;
|
|
61
|
+
return Object.freeze({
|
|
62
|
+
valid: true,
|
|
63
|
+
submitted: true,
|
|
64
|
+
data,
|
|
65
|
+
values: data,
|
|
66
|
+
errors,
|
|
67
|
+
serialize,
|
|
68
|
+
success,
|
|
69
|
+
fail(input) {
|
|
70
|
+
return failure(input);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return Object.freeze({
|
|
75
|
+
valid: false,
|
|
76
|
+
submitted: true,
|
|
77
|
+
data: void 0,
|
|
78
|
+
values,
|
|
79
|
+
errors,
|
|
80
|
+
serialize,
|
|
81
|
+
success,
|
|
82
|
+
fail(input) {
|
|
83
|
+
return failure(input);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function createSuccessfulSubmission(schemaDefinition, data) {
|
|
88
|
+
void schemaDefinition;
|
|
89
|
+
return createSubmission(
|
|
90
|
+
true,
|
|
91
|
+
data,
|
|
92
|
+
createErrorBag2(),
|
|
93
|
+
422,
|
|
94
|
+
schemaDefinition
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
function createFailedSubmission(schemaDefinition, values, flattenedErrors, status = 422, failureMetadata = {}) {
|
|
98
|
+
void schemaDefinition;
|
|
99
|
+
const normalizedStatus = normalizeStatus(status, 422);
|
|
100
|
+
return createSubmission(
|
|
101
|
+
false,
|
|
102
|
+
values,
|
|
103
|
+
createErrorBag2(flattenedErrors),
|
|
104
|
+
normalizedStatus,
|
|
105
|
+
schemaDefinition,
|
|
106
|
+
failureMetadata
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
function isRequestInput(input) {
|
|
110
|
+
return typeof Request !== "undefined" && input instanceof Request;
|
|
111
|
+
}
|
|
112
|
+
function isRequestLikeBody(value) {
|
|
113
|
+
if (typeof value === "string" || value instanceof URLSearchParams) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
if (typeof FormData !== "undefined" && value instanceof FormData) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
if (typeof Blob !== "undefined" && value instanceof Blob) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
if (typeof ArrayBuffer !== "undefined" && value instanceof ArrayBuffer) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
if (ArrayBuffer.isView(value)) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
return !!value && typeof value === "object" && (Symbol.asyncIterator in value || "pipe" in value || "getReader" in value);
|
|
129
|
+
}
|
|
130
|
+
function isFormDataInput(value) {
|
|
131
|
+
return typeof FormData !== "undefined" && value instanceof FormData;
|
|
132
|
+
}
|
|
133
|
+
function isHeadersTupleArray(value) {
|
|
134
|
+
return Array.isArray(value) && value.every((entry) => Array.isArray(entry) && entry.length === 2 && typeof entry[0] === "string" && typeof entry[1] === "string");
|
|
135
|
+
}
|
|
136
|
+
function isPlainObject(value) {
|
|
137
|
+
return !!value && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype;
|
|
138
|
+
}
|
|
139
|
+
function isHeaderAccessorObject(value) {
|
|
140
|
+
if (!value || typeof value !== "object" || isPlainObject(value)) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
const candidate = value;
|
|
144
|
+
return typeof candidate.get === "function" || typeof candidate.forEach === "function" || typeof candidate.entries === "function";
|
|
145
|
+
}
|
|
146
|
+
function isRequestLikeHeaders(value) {
|
|
147
|
+
return value instanceof Headers || isHeadersTupleArray(value) || isHeaderAccessorObject(value);
|
|
148
|
+
}
|
|
149
|
+
function normalizeRequestHeaders(input) {
|
|
150
|
+
if (input instanceof Headers) {
|
|
151
|
+
return new Headers(input);
|
|
152
|
+
}
|
|
153
|
+
const headers = new Headers();
|
|
154
|
+
if (isHeadersTupleArray(input)) {
|
|
155
|
+
for (const [name, value] of input) {
|
|
156
|
+
headers.append(name, value);
|
|
157
|
+
}
|
|
158
|
+
return headers;
|
|
159
|
+
}
|
|
160
|
+
if (isHeaderAccessorObject(input)) {
|
|
161
|
+
if (typeof input.forEach === "function") {
|
|
162
|
+
input.forEach((value, name) => {
|
|
163
|
+
headers.append(name, value);
|
|
164
|
+
});
|
|
165
|
+
return headers;
|
|
166
|
+
}
|
|
167
|
+
if (typeof input.entries === "function") {
|
|
168
|
+
for (const [name, value] of input.entries()) {
|
|
169
|
+
headers.append(name, value);
|
|
170
|
+
}
|
|
171
|
+
return headers;
|
|
172
|
+
}
|
|
173
|
+
throw new TypeError("get-only header accessor is not iterable.");
|
|
174
|
+
}
|
|
175
|
+
if (input && typeof input === "object") {
|
|
176
|
+
for (const [name, value] of Object.entries(input)) {
|
|
177
|
+
if (typeof value === "string") {
|
|
178
|
+
headers.append(name, value);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (Array.isArray(value)) {
|
|
182
|
+
const separator = name.toLowerCase() === "cookie" ? "; " : ",";
|
|
183
|
+
const joined = value.filter((entry) => typeof entry === "string").join(separator);
|
|
184
|
+
if (joined) {
|
|
185
|
+
headers.append(name, joined);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return headers;
|
|
191
|
+
}
|
|
192
|
+
function createFormDataRequestHeaders(requestHeaders) {
|
|
193
|
+
const formHeaders = new Headers();
|
|
194
|
+
requestHeaders.forEach((value, name) => {
|
|
195
|
+
const normalizedName = name.toLowerCase();
|
|
196
|
+
if (normalizedName !== "content-length" && normalizedName !== "content-type") {
|
|
197
|
+
formHeaders.append(name, value);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
return formHeaders;
|
|
201
|
+
}
|
|
202
|
+
function resolveAmbientRequestUrl(headers) {
|
|
203
|
+
const referer = headers.get("referer");
|
|
204
|
+
if (referer) {
|
|
205
|
+
try {
|
|
206
|
+
return new URL(referer).href;
|
|
207
|
+
} catch {
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
const protocol = headers.get("x-forwarded-proto") ?? "http";
|
|
211
|
+
const host = headers.get("x-forwarded-host") ?? headers.get("host") ?? "localhost";
|
|
212
|
+
return `${protocol}://${host}/`;
|
|
213
|
+
}
|
|
214
|
+
function isNextHeadersModule(value) {
|
|
215
|
+
return !!value && typeof value === "object" && typeof value.headers === "function";
|
|
216
|
+
}
|
|
217
|
+
async function importNextHeadersModule() {
|
|
218
|
+
try {
|
|
219
|
+
const runtime = globalThis;
|
|
220
|
+
const module = runtime.__holoFormsNextHeadersImport__ ? await runtime.__holoFormsNextHeadersImport__() : await import(
|
|
221
|
+
/* @vite-ignore */
|
|
222
|
+
nextHeadersModuleSpecifier
|
|
223
|
+
);
|
|
224
|
+
if (isNextHeadersModule(module)) {
|
|
225
|
+
return module;
|
|
226
|
+
}
|
|
227
|
+
return void 0;
|
|
228
|
+
} catch {
|
|
229
|
+
return void 0;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async function resolveAmbientFormDataRequest(input) {
|
|
233
|
+
if (!isFormDataInput(input)) {
|
|
234
|
+
return void 0;
|
|
235
|
+
}
|
|
236
|
+
const nextHeadersModule = await importNextHeadersModule();
|
|
237
|
+
if (!nextHeadersModule) {
|
|
238
|
+
return void 0;
|
|
239
|
+
}
|
|
240
|
+
const requestHeaders = await nextHeadersModule.headers();
|
|
241
|
+
return new Request(resolveAmbientRequestUrl(requestHeaders), {
|
|
242
|
+
method: "POST",
|
|
243
|
+
headers: createFormDataRequestHeaders(requestHeaders),
|
|
244
|
+
body: input
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
function getStructuredWebRequest(input) {
|
|
248
|
+
return input.web?.request instanceof Request ? void 0 : input.web?.request;
|
|
249
|
+
}
|
|
250
|
+
function extractRequestLikeUrl(input, headers) {
|
|
251
|
+
const webRequest = getStructuredWebRequest(input);
|
|
252
|
+
const url = webRequest?.url ?? (typeof input.url === "string" ? input.url : input.url?.toString()) ?? (typeof input.req === "object" && !(input.req instanceof Request) ? input.req.url : void 0) ?? input.node?.req?.url ?? input.path ?? "/";
|
|
253
|
+
try {
|
|
254
|
+
return new URL(url).toString();
|
|
255
|
+
} catch {
|
|
256
|
+
const protocol = headers.get("x-forwarded-proto") ?? "http";
|
|
257
|
+
const host = headers.get("x-forwarded-host") ?? headers.get("host") ?? "localhost";
|
|
258
|
+
return new URL(url, `${protocol}://${host}`).toString();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
function extractRequestLikeMethod(input) {
|
|
262
|
+
const webRequest = getStructuredWebRequest(input);
|
|
263
|
+
return webRequest?.method ?? input.method ?? (typeof input.req === "object" && !(input.req instanceof Request) ? input.req.method : void 0) ?? input.node?.req?.method ?? "GET";
|
|
264
|
+
}
|
|
265
|
+
function extractRequestLikeBody(input, headers, method) {
|
|
266
|
+
if (method === "GET" || method === "HEAD") {
|
|
267
|
+
return void 0;
|
|
268
|
+
}
|
|
269
|
+
const webRequest = getStructuredWebRequest(input);
|
|
270
|
+
const rawBody = webRequest?.body ?? input.body ?? (typeof input.req === "object" && !(input.req instanceof Request) ? input.req.body : void 0) ?? input.node?.req?.body ?? input.node?.req;
|
|
271
|
+
if (typeof rawBody === "undefined" || rawBody === null) {
|
|
272
|
+
return void 0;
|
|
273
|
+
}
|
|
274
|
+
return normalizeRequestLikeBody(rawBody, headers);
|
|
275
|
+
}
|
|
276
|
+
async function resolveRequestLikeBody(input, headers, method) {
|
|
277
|
+
if (method === "GET" || method === "HEAD") {
|
|
278
|
+
return void 0;
|
|
279
|
+
}
|
|
280
|
+
const nodeRequest = input.node?.req;
|
|
281
|
+
const rawBody = nodeRequest?.[h3RawBodySymbol] ?? nodeRequest?.rawBody ?? extractRequestLikeBody(input, headers, method);
|
|
282
|
+
return normalizeRequestLikeBody(await rawBody, headers);
|
|
283
|
+
}
|
|
284
|
+
function normalizeRequestLikeBody(rawBody, headers) {
|
|
285
|
+
if (typeof rawBody === "undefined" || rawBody === null) {
|
|
286
|
+
return void 0;
|
|
287
|
+
}
|
|
288
|
+
if (isRequestLikeBody(rawBody)) {
|
|
289
|
+
return rawBody;
|
|
290
|
+
}
|
|
291
|
+
if (typeof rawBody === "object") {
|
|
292
|
+
if (!headers.has("content-type")) {
|
|
293
|
+
headers.set("content-type", "application/json");
|
|
294
|
+
}
|
|
295
|
+
return JSON.stringify(rawBody);
|
|
296
|
+
}
|
|
297
|
+
return String(rawBody);
|
|
298
|
+
}
|
|
299
|
+
function isStructuredRequestLikeObject(value) {
|
|
300
|
+
if (!value || typeof value !== "object") {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
const candidate = value;
|
|
304
|
+
return typeof candidate.method === "string" || typeof candidate.path === "string" || typeof candidate.url === "string" || candidate.url instanceof URL || isRequestLikeHeaders(candidate.headers) || typeof candidate.body !== "undefined";
|
|
305
|
+
}
|
|
306
|
+
function isRequestLikeInput(input) {
|
|
307
|
+
if (!input || typeof input !== "object") {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
const candidate = input;
|
|
311
|
+
if (candidate.web?.request instanceof Request || candidate.req instanceof Request) {
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
if (isStructuredRequestLikeObject(candidate.web?.request)) {
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
if (isStructuredRequestLikeObject(candidate.req)) {
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
if (isStructuredRequestLikeObject(candidate.node?.req)) {
|
|
321
|
+
return true;
|
|
322
|
+
}
|
|
323
|
+
const hasRequestMetadata = typeof candidate.method === "string" || typeof candidate.path === "string" || typeof candidate.url === "string" || candidate.url instanceof URL;
|
|
324
|
+
const hasStructuredHeaders = isRequestLikeHeaders(candidate.headers);
|
|
325
|
+
const hasPlainHeaderRecord = isPlainObject(candidate.headers);
|
|
326
|
+
const hasBody = typeof candidate.body !== "undefined";
|
|
327
|
+
return hasRequestMetadata && (hasStructuredHeaders || hasPlainHeaderRecord || hasBody);
|
|
328
|
+
}
|
|
329
|
+
function normalizeRequestLikeInput(input) {
|
|
330
|
+
if (isRequestInput(input)) {
|
|
331
|
+
return input;
|
|
332
|
+
}
|
|
333
|
+
if (!isRequestLikeInput(input)) {
|
|
334
|
+
return void 0;
|
|
335
|
+
}
|
|
336
|
+
if (input.web?.request instanceof Request) {
|
|
337
|
+
return input.web.request;
|
|
338
|
+
}
|
|
339
|
+
if (input.req instanceof Request) {
|
|
340
|
+
return input.req;
|
|
341
|
+
}
|
|
342
|
+
const headers = normalizeRequestHeaders(
|
|
343
|
+
getStructuredWebRequest(input)?.headers ?? input.headers ?? (typeof input.req === "object" && !(input.req instanceof Request) ? input.req.headers : void 0) ?? input.node?.req?.headers
|
|
344
|
+
);
|
|
345
|
+
const method = extractRequestLikeMethod(input);
|
|
346
|
+
const body = extractRequestLikeBody(input, headers, method);
|
|
347
|
+
return createRequestFromParts(input, headers, method, body);
|
|
348
|
+
}
|
|
349
|
+
async function normalizeRequestLikeInputForValidation(input) {
|
|
350
|
+
if (isRequestInput(input)) {
|
|
351
|
+
return input;
|
|
352
|
+
}
|
|
353
|
+
if (!isRequestLikeInput(input)) {
|
|
354
|
+
return void 0;
|
|
355
|
+
}
|
|
356
|
+
if (input.web?.request instanceof Request) {
|
|
357
|
+
return input.web.request;
|
|
358
|
+
}
|
|
359
|
+
if (input.req instanceof Request) {
|
|
360
|
+
return input.req;
|
|
361
|
+
}
|
|
362
|
+
const headers = normalizeRequestHeaders(
|
|
363
|
+
getStructuredWebRequest(input)?.headers ?? input.headers ?? (typeof input.req === "object" && !(input.req instanceof Request) ? input.req.headers : void 0) ?? input.node?.req?.headers
|
|
364
|
+
);
|
|
365
|
+
const method = extractRequestLikeMethod(input);
|
|
366
|
+
const body = await resolveRequestLikeBody(input, headers, method);
|
|
367
|
+
return createRequestFromParts(input, headers, method, body);
|
|
368
|
+
}
|
|
369
|
+
function createRequestFromParts(input, headers, method, body) {
|
|
370
|
+
return new Request(extractRequestLikeUrl(input, headers), {
|
|
371
|
+
method,
|
|
372
|
+
headers,
|
|
373
|
+
body,
|
|
374
|
+
// Undici requires duplex when constructing a Request from a stream/async iterable in Node.
|
|
375
|
+
...body && typeof body === "object" && (Symbol.asyncIterator in body || "pipe" in body || "getReader" in body) ? { duplex: "half" } : {}
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
function createSecurityFailureMetadata(error) {
|
|
379
|
+
if (error.status !== 429) {
|
|
380
|
+
return {};
|
|
381
|
+
}
|
|
382
|
+
const candidate = error;
|
|
383
|
+
const retryAfterSeconds = typeof candidate.retryAfterSeconds === "number" && Number.isFinite(candidate.retryAfterSeconds) ? candidate.retryAfterSeconds : void 0;
|
|
384
|
+
const retryAt = candidate.snapshot?.expiresAt instanceof Date ? candidate.snapshot.expiresAt.toISOString() : void 0;
|
|
385
|
+
return {
|
|
386
|
+
...typeof retryAfterSeconds === "number" ? { retryAfterSeconds } : {},
|
|
387
|
+
...typeof retryAt === "string" ? { retryAt } : {}
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
async function createSecurityFailureSubmission(input, schemaDefinition, error) {
|
|
391
|
+
let values = {};
|
|
392
|
+
let flattenedErrors = {};
|
|
393
|
+
try {
|
|
394
|
+
const inspection = await safeParseInput(input.clone(), schemaDefinition);
|
|
395
|
+
if (inspection.valid) {
|
|
396
|
+
values = inspection.data;
|
|
397
|
+
} else {
|
|
398
|
+
values = inspection.values;
|
|
399
|
+
flattenedErrors = inspection.errors.flatten();
|
|
400
|
+
}
|
|
401
|
+
} catch {
|
|
402
|
+
values = {};
|
|
403
|
+
flattenedErrors = {};
|
|
404
|
+
}
|
|
405
|
+
return createFailedSubmission(
|
|
406
|
+
schemaDefinition,
|
|
407
|
+
values,
|
|
408
|
+
{
|
|
409
|
+
...flattenedErrors,
|
|
410
|
+
_root: [
|
|
411
|
+
...flattenedErrors._root ?? [],
|
|
412
|
+
error.message
|
|
413
|
+
]
|
|
414
|
+
},
|
|
415
|
+
error.status,
|
|
416
|
+
createSecurityFailureMetadata(error)
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
async function safeParse(input, schemaDefinition, options = {}) {
|
|
420
|
+
let validatedSubmission;
|
|
421
|
+
const throttle = typeof options.throttle === "string" ? options.throttle : void 0;
|
|
422
|
+
const usesSecurityOptions = typeof throttle === "string";
|
|
423
|
+
const normalizedRequestInput = await normalizeRequestLikeInputForValidation(input) ?? (usesSecurityOptions ? await resolveAmbientFormDataRequest(input) : void 0);
|
|
424
|
+
const validationInput = normalizedRequestInput ?? input;
|
|
425
|
+
if (usesSecurityOptions && !normalizedRequestInput) {
|
|
426
|
+
throw new FormContractError(
|
|
427
|
+
"Security-aware safeParse() options require a Request or request-like event input."
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
if (usesSecurityOptions) {
|
|
431
|
+
const request = normalizedRequestInput;
|
|
432
|
+
try {
|
|
433
|
+
const { loadSecurityModule } = await import("./security-ODATEIFI.mjs");
|
|
434
|
+
const security = await loadSecurityModule();
|
|
435
|
+
const inspection = await safeParseInput(request.clone(), schemaDefinition);
|
|
436
|
+
const throttleValues = inspection.valid ? inspection.data : inspection.values;
|
|
437
|
+
validatedSubmission = inspection.valid ? createSuccessfulSubmission(schemaDefinition, inspection.data) : createFailedSubmission(schemaDefinition, inspection.values, inspection.errors.flatten());
|
|
438
|
+
await security.rateLimit(throttle, {
|
|
439
|
+
request,
|
|
440
|
+
values: throttleValues
|
|
441
|
+
});
|
|
442
|
+
} catch (error) {
|
|
443
|
+
const { formsSecurityInternals } = await import("./security-ODATEIFI.mjs");
|
|
444
|
+
if (formsSecurityInternals.isRootSecurityError(error)) {
|
|
445
|
+
if (validatedSubmission) {
|
|
446
|
+
return createFailedSubmission(
|
|
447
|
+
schemaDefinition,
|
|
448
|
+
validatedSubmission.valid ? validatedSubmission.data : validatedSubmission.values,
|
|
449
|
+
{
|
|
450
|
+
...validatedSubmission.valid ? {} : validatedSubmission.errors.flatten(),
|
|
451
|
+
_root: [
|
|
452
|
+
...!validatedSubmission.valid ? validatedSubmission.errors.flatten()._root ?? [] : [],
|
|
453
|
+
error.message
|
|
454
|
+
]
|
|
455
|
+
},
|
|
456
|
+
error.status,
|
|
457
|
+
createSecurityFailureMetadata(error)
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
return await createSecurityFailureSubmission(request, schemaDefinition, error);
|
|
461
|
+
}
|
|
462
|
+
throw error;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
if (validatedSubmission) {
|
|
466
|
+
return validatedSubmission;
|
|
467
|
+
}
|
|
468
|
+
const result = await safeParseInput(validationInput, schemaDefinition);
|
|
469
|
+
if (result.valid) {
|
|
470
|
+
return createSuccessfulSubmission(schemaDefinition, result.data);
|
|
471
|
+
}
|
|
472
|
+
return createFailedSubmission(schemaDefinition, result.values, result.errors.flatten());
|
|
473
|
+
}
|
|
474
|
+
async function validate(input, schemaDefinition, options = {}) {
|
|
475
|
+
const result = await safeParse(input, schemaDefinition, options);
|
|
476
|
+
if (result.valid) {
|
|
477
|
+
return result.data;
|
|
478
|
+
}
|
|
479
|
+
const failure = result.fail();
|
|
480
|
+
const exception = validationInternals.setValidationExceptionValues(
|
|
481
|
+
ValidationException2.withMessages(result.errors.flatten(), {
|
|
482
|
+
bag: options.bag
|
|
483
|
+
}),
|
|
484
|
+
result.values
|
|
485
|
+
);
|
|
486
|
+
validationInternals.setValidationExceptionStatus(exception, failure.status);
|
|
487
|
+
validationInternals.setValidationExceptionMetadata(exception, {
|
|
488
|
+
...typeof failure.retryAfterSeconds === "number" ? { retryAfterSeconds: failure.retryAfterSeconds } : {},
|
|
489
|
+
...typeof failure.retryAt === "string" ? { retryAt: failure.retryAt } : {}
|
|
490
|
+
});
|
|
491
|
+
return validationInternals.throwValidationException(exception);
|
|
492
|
+
}
|
|
493
|
+
var formsInternals = {
|
|
494
|
+
createSubmission,
|
|
495
|
+
isRequestLikeHeaders,
|
|
496
|
+
normalizeRequestLikeInput,
|
|
497
|
+
normalizeStatus,
|
|
498
|
+
normalizeRequestHeaders,
|
|
499
|
+
sanitizeFlashedInput,
|
|
500
|
+
serializeSubmissionState
|
|
501
|
+
};
|
|
19
502
|
export {
|
|
503
|
+
DEFAULT_VALIDATION_BAG,
|
|
20
504
|
FormContractError,
|
|
505
|
+
ValidationException,
|
|
21
506
|
createErrorBag,
|
|
22
507
|
createFailedSubmission,
|
|
23
508
|
createSuccessfulSubmission,
|
|
@@ -25,8 +510,11 @@ export {
|
|
|
25
510
|
field,
|
|
26
511
|
formsInternals,
|
|
27
512
|
isFormSchema,
|
|
513
|
+
isValidationException,
|
|
28
514
|
parse,
|
|
29
515
|
safeParse,
|
|
516
|
+
sanitizeFlashedInput,
|
|
30
517
|
schema,
|
|
518
|
+
sensitiveInputInternals,
|
|
31
519
|
validate
|
|
32
520
|
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { g as FormSubmissionResult, S as SerializedFormSubmission, c as FormFailurePayload, i as FormSuccessPayload } from '../contracts-D1dERmQn.js';
|
|
2
|
+
import { WebFileLike, SchemaInputShape, FieldBuilderInput, InferFieldOutput, ValidationErrorBag } from '@holo-js/validation';
|
|
3
|
+
import { FormSchema, InferFormData } from '../schema.js';
|
|
4
|
+
|
|
5
|
+
type PrimitiveLike = string | number | boolean | bigint | symbol | null | undefined | Date | Blob | WebFileLike;
|
|
6
|
+
type ValidateOnMode = 'submit' | 'blur' | 'change';
|
|
7
|
+
interface ClientSubmitContext<TData> {
|
|
8
|
+
readonly action?: string;
|
|
9
|
+
readonly method: string;
|
|
10
|
+
readonly values: TData;
|
|
11
|
+
readonly formData: FormData;
|
|
12
|
+
}
|
|
13
|
+
type ClientSubmitResult<TData, TSuccess = unknown> = FormSubmissionResult<TData> | SerializedFormSubmission<TData> | FormFailurePayload<TData> | FormSuccessPayload<TSuccess> | {
|
|
14
|
+
readonly ok: boolean;
|
|
15
|
+
readonly status: number;
|
|
16
|
+
readonly data: TSuccess;
|
|
17
|
+
};
|
|
18
|
+
type BrowserFormElement = {
|
|
19
|
+
readonly action?: string;
|
|
20
|
+
readonly method?: string;
|
|
21
|
+
};
|
|
22
|
+
interface UseFormOptions<TData, TSuccess = unknown> {
|
|
23
|
+
readonly action?: string;
|
|
24
|
+
readonly method?: string;
|
|
25
|
+
readonly validateOn?: ValidateOnMode;
|
|
26
|
+
readonly initialValues?: Partial<TData>;
|
|
27
|
+
readonly initialState?: SerializedFormSubmission<TData> | FormFailurePayload<TData> | null;
|
|
28
|
+
readonly submitter?: (context: ClientSubmitContext<TData>) => Promise<ClientSubmitResult<TData, TSuccess> | void> | ClientSubmitResult<TData, TSuccess> | void;
|
|
29
|
+
}
|
|
30
|
+
interface FormFieldState<TValue> {
|
|
31
|
+
value: TValue;
|
|
32
|
+
readonly errors: readonly string[];
|
|
33
|
+
readonly touched: boolean;
|
|
34
|
+
readonly dirty: boolean;
|
|
35
|
+
set(value: TValue): Promise<void>;
|
|
36
|
+
onInput(value: TValue): Promise<void>;
|
|
37
|
+
onBlur(): Promise<void>;
|
|
38
|
+
validate(): Promise<readonly string[]>;
|
|
39
|
+
}
|
|
40
|
+
type FormFieldTree<TData> = [TData] extends [readonly unknown[]] ? FormFieldState<TData> : [TData] extends [PrimitiveLike] ? FormFieldState<TData> : [TData] extends [Record<string, unknown>] ? {
|
|
41
|
+
readonly [K in keyof TData]: FormFieldTree<TData[K]>;
|
|
42
|
+
} : FormFieldState<TData>;
|
|
43
|
+
type FormFieldTreeFromShape<TShape extends SchemaInputShape> = {
|
|
44
|
+
readonly [K in Extract<keyof TShape, string>]: TShape[K] extends FieldBuilderInput ? FormFieldState<InferFieldOutput<TShape[K]>> : TShape[K] extends SchemaInputShape ? FormFieldTreeFromShape<TShape[K]> : never;
|
|
45
|
+
};
|
|
46
|
+
type InferFormFieldTree<TSchema extends FormSchema> = TSchema extends FormSchema<infer TShape> ? FormFieldTreeFromShape<TShape> : never;
|
|
47
|
+
interface UseFormResult<TData, TSuccess = unknown, TFields = FormFieldTree<TData>> {
|
|
48
|
+
readonly fields: TFields;
|
|
49
|
+
readonly values: TData;
|
|
50
|
+
readonly errors: ValidationErrorBag<TData>;
|
|
51
|
+
readonly submitting: boolean;
|
|
52
|
+
readonly valid: boolean;
|
|
53
|
+
readonly lastSubmission?: SerializedFormSubmission<TData> | FormFailurePayload<TData> | FormSuccessPayload<TSuccess>;
|
|
54
|
+
subscribe(listener: () => void): () => void;
|
|
55
|
+
validate(): Promise<FormSubmissionResult<TData>>;
|
|
56
|
+
validateField(path: string): Promise<readonly string[]>;
|
|
57
|
+
submit(): Promise<ClientSubmitResult<TData, TSuccess>>;
|
|
58
|
+
reset(values?: Partial<TData>): void;
|
|
59
|
+
setValue(path: string, value: unknown): Promise<void>;
|
|
60
|
+
applyServerState(result: ClientSubmitResult<TData, TSuccess>): ClientSubmitResult<TData, TSuccess>;
|
|
61
|
+
}
|
|
62
|
+
declare function runWithBrowserFormElement<TData, TSuccess>(formClient: Pick<UseFormResult<TData, TSuccess>, 'submit'>, form: BrowserFormElement): Promise<ClientSubmitResult<TData, TSuccess>>;
|
|
63
|
+
/**
|
|
64
|
+
* @internal Shared headless form runtime for framework adapters.
|
|
65
|
+
*/
|
|
66
|
+
declare function createFormClient<TSchema extends FormSchema, TSuccess = unknown>(schemaDefinition: TSchema, options?: UseFormOptions<InferFormData<TSchema>, TSuccess>): UseFormResult<InferFormData<TSchema>, TSuccess, InferFormFieldTree<TSchema>>;
|
|
67
|
+
|
|
68
|
+
export { type ClientSubmitContext, type ClientSubmitResult, type FormFieldState, type FormFieldTree, type InferFormFieldTree, type UseFormOptions, type UseFormResult, type ValidateOnMode, createFormClient, runWithBrowserFormElement };
|