@ereo/data 0.1.6

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/index.js ADDED
@@ -0,0 +1,1587 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true,
8
+ configurable: true,
9
+ set: (newValue) => all[name] = () => newValue
10
+ });
11
+ };
12
+
13
+ // src/cache.ts
14
+ var exports_cache = {};
15
+ __export(exports_cache, {
16
+ setCache: () => setCache,
17
+ parseCacheControl: () => parseCacheControl,
18
+ getCache: () => getCache,
19
+ generateCacheKey: () => generateCacheKey,
20
+ createDataCacheAdapter: () => createDataCacheAdapter,
21
+ cached: () => cached,
22
+ cacheKey: () => cacheKey,
23
+ buildCacheControl: () => buildCacheControl,
24
+ MemoryCache: () => MemoryCache,
25
+ Cached: () => Cached
26
+ });
27
+
28
+ class MemoryCache {
29
+ cache = new Map;
30
+ tagIndex = new Map;
31
+ async get(key) {
32
+ const entry = this.cache.get(key);
33
+ if (!entry)
34
+ return null;
35
+ const age = Date.now() - entry.timestamp;
36
+ const isStale = age > entry.maxAge * 1000;
37
+ const isExpired = isStale && (!entry.staleWhileRevalidate || age > (entry.maxAge + entry.staleWhileRevalidate) * 1000);
38
+ if (isExpired) {
39
+ await this.delete(key);
40
+ return null;
41
+ }
42
+ return entry;
43
+ }
44
+ async set(key, entry) {
45
+ if (this.cache.has(key)) {
46
+ await this.delete(key);
47
+ }
48
+ this.cache.set(key, entry);
49
+ for (const tag of entry.tags) {
50
+ if (!this.tagIndex.has(tag)) {
51
+ this.tagIndex.set(tag, new Set);
52
+ }
53
+ this.tagIndex.get(tag).add(key);
54
+ }
55
+ }
56
+ async delete(key) {
57
+ const entry = this.cache.get(key);
58
+ if (entry) {
59
+ for (const tag of entry.tags) {
60
+ const tagSet = this.tagIndex.get(tag);
61
+ if (tagSet) {
62
+ tagSet.delete(key);
63
+ if (tagSet.size === 0) {
64
+ this.tagIndex.delete(tag);
65
+ }
66
+ }
67
+ }
68
+ this.cache.delete(key);
69
+ return true;
70
+ }
71
+ return false;
72
+ }
73
+ async deleteByTag(tag) {
74
+ const keys = this.tagIndex.get(tag);
75
+ if (keys) {
76
+ const keysCopy = [...keys];
77
+ for (const key of keysCopy) {
78
+ await this.delete(key);
79
+ }
80
+ }
81
+ }
82
+ async clear() {
83
+ this.cache.clear();
84
+ this.tagIndex.clear();
85
+ }
86
+ async keys() {
87
+ return Array.from(this.cache.keys());
88
+ }
89
+ getStats() {
90
+ return {
91
+ size: this.cache.size,
92
+ tags: this.tagIndex.size
93
+ };
94
+ }
95
+ async getValue(key) {
96
+ const entry = await this.get(key);
97
+ return entry?.value;
98
+ }
99
+ async setValue(key, value, options) {
100
+ const entry = {
101
+ value,
102
+ timestamp: Date.now(),
103
+ maxAge: options?.ttl ?? 60,
104
+ tags: options?.tags ?? []
105
+ };
106
+ await this.set(key, entry);
107
+ }
108
+ async has(key) {
109
+ const entry = await this.get(key);
110
+ return entry !== null;
111
+ }
112
+ async invalidateTag(tag) {
113
+ return this.deleteByTag(tag);
114
+ }
115
+ async invalidateTags(tags) {
116
+ for (const tag of tags) {
117
+ await this.invalidateTag(tag);
118
+ }
119
+ }
120
+ async getByTag(tag) {
121
+ const keys = this.tagIndex.get(tag);
122
+ if (!keys) {
123
+ return [];
124
+ }
125
+ const validKeys = [];
126
+ for (const key of keys) {
127
+ if (await this.has(key)) {
128
+ validKeys.push(key);
129
+ }
130
+ }
131
+ return validKeys;
132
+ }
133
+ asCacheAdapter() {
134
+ return {
135
+ get: (key) => this.getValue(key),
136
+ set: (key, value, options) => this.setValue(key, value, options),
137
+ delete: (key) => this.delete(key),
138
+ has: (key) => this.has(key),
139
+ clear: () => this.clear(),
140
+ invalidateTag: (tag) => this.invalidateTag(tag),
141
+ invalidateTags: (tags) => this.invalidateTags(tags),
142
+ getByTag: (tag) => this.getByTag(tag)
143
+ };
144
+ }
145
+ }
146
+ function createDataCacheAdapter() {
147
+ const memoryCache = new MemoryCache;
148
+ return memoryCache.asCacheAdapter();
149
+ }
150
+ function getCache() {
151
+ if (!globalCache) {
152
+ globalCache = new MemoryCache;
153
+ }
154
+ return globalCache;
155
+ }
156
+ function setCache(storage) {
157
+ globalCache = storage;
158
+ }
159
+ async function cached(key, fn, options) {
160
+ const cache = getCache();
161
+ const entry = await cache.get(key);
162
+ if (entry) {
163
+ const age = Date.now() - entry.timestamp;
164
+ const isStale = age > entry.maxAge * 1000;
165
+ if (!isStale) {
166
+ return entry.value;
167
+ }
168
+ if (entry.staleWhileRevalidate) {
169
+ revalidate(key, fn, options);
170
+ return entry.value;
171
+ }
172
+ }
173
+ const value = await fn();
174
+ await cache.set(key, {
175
+ value,
176
+ timestamp: Date.now(),
177
+ maxAge: options.maxAge ?? 60,
178
+ staleWhileRevalidate: options.staleWhileRevalidate,
179
+ tags: options.tags ?? []
180
+ });
181
+ return value;
182
+ }
183
+ async function revalidate(key, fn, options) {
184
+ try {
185
+ const value = await fn();
186
+ const cache = getCache();
187
+ await cache.set(key, {
188
+ value,
189
+ timestamp: Date.now(),
190
+ maxAge: options.maxAge ?? 60,
191
+ staleWhileRevalidate: options.staleWhileRevalidate,
192
+ tags: options.tags ?? []
193
+ });
194
+ } catch (error2) {
195
+ console.error(`Failed to revalidate cache key: ${key}`, error2);
196
+ }
197
+ }
198
+ function generateCacheKey(request) {
199
+ const url = new URL(request.url);
200
+ return `${request.method}:${url.pathname}${url.search}`;
201
+ }
202
+ function cacheKey(prefix, ...parts) {
203
+ return `${prefix}:${parts.join(":")}`;
204
+ }
205
+ function buildCacheControl(options) {
206
+ const parts = [];
207
+ if (options.private) {
208
+ parts.push("private");
209
+ } else {
210
+ parts.push("public");
211
+ }
212
+ if (options.maxAge !== undefined) {
213
+ parts.push(`max-age=${options.maxAge}`);
214
+ }
215
+ if (options.staleWhileRevalidate !== undefined) {
216
+ parts.push(`stale-while-revalidate=${options.staleWhileRevalidate}`);
217
+ }
218
+ return parts.join(", ");
219
+ }
220
+ function parseCacheControl(header) {
221
+ const options = {};
222
+ const directives = header.split(",").map((d) => d.trim().toLowerCase());
223
+ for (const directive of directives) {
224
+ if (directive === "private") {
225
+ options.private = true;
226
+ } else if (directive.startsWith("max-age=")) {
227
+ options.maxAge = parseInt(directive.slice(8), 10);
228
+ } else if (directive.startsWith("stale-while-revalidate=")) {
229
+ options.staleWhileRevalidate = parseInt(directive.slice(23), 10);
230
+ }
231
+ }
232
+ return options;
233
+ }
234
+ function Cached(options) {
235
+ return function(_target, propertyKey, descriptor) {
236
+ const originalMethod = descriptor.value;
237
+ descriptor.value = async function(...args) {
238
+ const key = cacheKey(propertyKey, JSON.stringify(args));
239
+ return cached(key, () => originalMethod.apply(this, args), options);
240
+ };
241
+ return descriptor;
242
+ };
243
+ }
244
+ var globalCache = null;
245
+
246
+ // src/loader.ts
247
+ function createLoader(options) {
248
+ return async (args) => {
249
+ const { context } = args;
250
+ if (options.cache) {
251
+ context.cache.set(options.cache);
252
+ }
253
+ try {
254
+ const rawData = await options.load(args);
255
+ if (options.transform) {
256
+ const transformed = await options.transform(rawData, args);
257
+ return transformed;
258
+ }
259
+ return rawData;
260
+ } catch (error) {
261
+ if (options.onError && error instanceof Error) {
262
+ const result = await options.onError(error, args);
263
+ if (result instanceof Response) {
264
+ throw result;
265
+ }
266
+ return result;
267
+ }
268
+ throw error;
269
+ }
270
+ };
271
+ }
272
+ function defer(promise) {
273
+ const deferred = {
274
+ promise,
275
+ status: "pending"
276
+ };
277
+ promise.then((value) => {
278
+ deferred.status = "resolved";
279
+ deferred.value = value;
280
+ }).catch((error) => {
281
+ deferred.status = "rejected";
282
+ deferred.error = error;
283
+ });
284
+ return deferred;
285
+ }
286
+ function isDeferred(value) {
287
+ return typeof value === "object" && value !== null && "promise" in value && "status" in value;
288
+ }
289
+ async function resolveDeferred(deferred) {
290
+ return deferred.promise;
291
+ }
292
+ async function fetchData(input, init) {
293
+ const response = await fetch(input, init);
294
+ if (!response.ok) {
295
+ throw new FetchError(`Fetch failed: ${response.status} ${response.statusText}`, response);
296
+ }
297
+ const contentType = response.headers.get("Content-Type");
298
+ if (contentType?.includes("application/json")) {
299
+ return response.json();
300
+ }
301
+ return response.text();
302
+ }
303
+
304
+ class FetchError extends Error {
305
+ response;
306
+ constructor(message, response) {
307
+ super(message);
308
+ this.response = response;
309
+ this.name = "FetchError";
310
+ }
311
+ get status() {
312
+ return this.response.status;
313
+ }
314
+ get statusText() {
315
+ return this.response.statusText;
316
+ }
317
+ }
318
+ function serializeLoaderData(data) {
319
+ const json = JSON.stringify(data);
320
+ return json.replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/'/g, "\\u0027");
321
+ }
322
+ function parseLoaderData(serialized) {
323
+ return JSON.parse(serialized);
324
+ }
325
+ function combineLoaders(loaders) {
326
+ return async (args) => {
327
+ const entries = Object.entries(loaders);
328
+ const results = await Promise.all(entries.map(async ([key, loader]) => [key, await loader(args)]));
329
+ return Object.fromEntries(results);
330
+ };
331
+ }
332
+ function clientLoader(load) {
333
+ return async ({ params }) => {
334
+ return load(params);
335
+ };
336
+ }
337
+ // src/action.ts
338
+ function createAction(options) {
339
+ return async (args) => {
340
+ const { request } = args;
341
+ const formData = await request.formData();
342
+ if (options.validate) {
343
+ const validation = await options.validate(formData);
344
+ if (!validation.success) {
345
+ return {
346
+ success: false,
347
+ errors: validation.errors
348
+ };
349
+ }
350
+ }
351
+ try {
352
+ const data = await options.handler({ ...args, formData });
353
+ return { success: true, data };
354
+ } catch (error) {
355
+ if (options.onError && error instanceof Error) {
356
+ const result = await options.onError(error, args);
357
+ if (result instanceof Response) {
358
+ throw result;
359
+ }
360
+ return { success: true, data: result };
361
+ }
362
+ throw error;
363
+ }
364
+ };
365
+ }
366
+ function action(handler) {
367
+ return createAction({ handler });
368
+ }
369
+ function typedAction(options) {
370
+ return async (args) => {
371
+ const { request } = args;
372
+ try {
373
+ const { body: rawBody, formData, contentType } = await parseRequestBody(request);
374
+ let body;
375
+ if (options.transform) {
376
+ body = options.transform(rawBody);
377
+ } else if (options.schema) {
378
+ if (options.schema.safeParse) {
379
+ const result = options.schema.safeParse(rawBody);
380
+ if (!result.success) {
381
+ const errors = {};
382
+ for (const err of result.error.errors) {
383
+ const path = err.path.join(".") || "_root";
384
+ if (!errors[path])
385
+ errors[path] = [];
386
+ errors[path].push(err.message);
387
+ }
388
+ return { success: false, errors };
389
+ }
390
+ body = result.data;
391
+ } else {
392
+ body = options.schema.parse(rawBody);
393
+ }
394
+ } else {
395
+ body = rawBody;
396
+ }
397
+ if (options.validate) {
398
+ const validation = await options.validate(body);
399
+ if (!validation.success) {
400
+ return { success: false, errors: validation.errors };
401
+ }
402
+ }
403
+ const typedArgs = {
404
+ ...args,
405
+ body,
406
+ formData,
407
+ contentType
408
+ };
409
+ const data = await options.handler(typedArgs);
410
+ return { success: true, data };
411
+ } catch (error) {
412
+ if (options.onError && error instanceof Error) {
413
+ const result = await options.onError(error, args);
414
+ if (result instanceof Response) {
415
+ throw result;
416
+ }
417
+ return { success: true, data: result };
418
+ }
419
+ throw error;
420
+ }
421
+ };
422
+ }
423
+ async function parseRequestBody(request) {
424
+ const contentType = request.headers.get("Content-Type") || "";
425
+ if (contentType.includes("application/json")) {
426
+ const body = await request.json();
427
+ return { body, contentType: "json" };
428
+ }
429
+ if (contentType.includes("multipart/form-data") || contentType.includes("application/x-www-form-urlencoded")) {
430
+ const formData = await request.formData();
431
+ const body = formDataToObject(formData);
432
+ return { body, formData, contentType: "form" };
433
+ }
434
+ if (contentType.includes("text/")) {
435
+ const body = await request.text();
436
+ return { body, contentType: "text" };
437
+ }
438
+ try {
439
+ const text = await request.text();
440
+ const body = JSON.parse(text);
441
+ return { body, contentType: "json" };
442
+ } catch {
443
+ return { body: null, contentType: "unknown" };
444
+ }
445
+ }
446
+ function formDataToObject(formData, options = {}) {
447
+ const { coerce = true } = options;
448
+ const result = {};
449
+ for (const [key, value] of formData.entries()) {
450
+ if (typeof value === "object" && value !== null && "name" in value && "size" in value) {
451
+ setNestedValue(result, key, value);
452
+ continue;
453
+ }
454
+ const coercedValue = coerce ? coerceValue(value) : value;
455
+ setNestedValue(result, key, coercedValue);
456
+ }
457
+ return result;
458
+ }
459
+ function setNestedValue(obj, path, value) {
460
+ if (path.endsWith("[]")) {
461
+ const arrayPath = path.slice(0, -2);
462
+ const existing = getNestedValue(obj, arrayPath);
463
+ if (Array.isArray(existing)) {
464
+ existing.push(value);
465
+ } else {
466
+ setNestedValueDirect(obj, arrayPath, [value]);
467
+ }
468
+ return;
469
+ }
470
+ const segments = parsePath(path);
471
+ let current = obj;
472
+ for (let i = 0;i < segments.length - 1; i++) {
473
+ const segment = segments[i];
474
+ const nextSegment = segments[i + 1];
475
+ const isNextArray = typeof nextSegment === "number";
476
+ if (current[segment] === undefined) {
477
+ current[segment] = isNextArray ? [] : {};
478
+ }
479
+ current = current[segment];
480
+ }
481
+ const lastSegment = segments[segments.length - 1];
482
+ if (current[lastSegment] !== undefined && !Array.isArray(current[lastSegment])) {
483
+ current[lastSegment] = [current[lastSegment], value];
484
+ } else if (Array.isArray(current[lastSegment]) && typeof lastSegment === "string") {
485
+ current[lastSegment].push(value);
486
+ } else {
487
+ current[lastSegment] = value;
488
+ }
489
+ }
490
+ function parsePath(path) {
491
+ const segments = [];
492
+ let current = "";
493
+ for (let i = 0;i < path.length; i++) {
494
+ const char = path[i];
495
+ if (char === ".") {
496
+ if (current) {
497
+ segments.push(current);
498
+ current = "";
499
+ }
500
+ } else if (char === "[") {
501
+ if (current) {
502
+ segments.push(current);
503
+ current = "";
504
+ }
505
+ const closeBracket = path.indexOf("]", i);
506
+ if (closeBracket !== -1) {
507
+ const indexStr = path.slice(i + 1, closeBracket);
508
+ const index = parseInt(indexStr, 10);
509
+ if (!isNaN(index)) {
510
+ segments.push(index);
511
+ } else if (indexStr) {
512
+ segments.push(indexStr);
513
+ }
514
+ i = closeBracket;
515
+ }
516
+ } else {
517
+ current += char;
518
+ }
519
+ }
520
+ if (current) {
521
+ segments.push(current);
522
+ }
523
+ return segments;
524
+ }
525
+ function getNestedValue(obj, path) {
526
+ const segments = parsePath(path);
527
+ let current = obj;
528
+ for (const segment of segments) {
529
+ if (current == null || typeof current !== "object") {
530
+ return;
531
+ }
532
+ current = current[segment];
533
+ }
534
+ return current;
535
+ }
536
+ function setNestedValueDirect(obj, path, value) {
537
+ const segments = parsePath(path);
538
+ let current = obj;
539
+ for (let i = 0;i < segments.length - 1; i++) {
540
+ const segment = segments[i];
541
+ const nextSegment = segments[i + 1];
542
+ const isNextArray = typeof nextSegment === "number";
543
+ if (current[segment] === undefined) {
544
+ current[segment] = isNextArray ? [] : {};
545
+ }
546
+ current = current[segment];
547
+ }
548
+ current[segments[segments.length - 1]] = value;
549
+ }
550
+ function coerceValue(value) {
551
+ if (value === "true")
552
+ return true;
553
+ if (value === "false")
554
+ return false;
555
+ if (value === "null")
556
+ return null;
557
+ if (value === "undefined")
558
+ return;
559
+ if (value !== "" && !isNaN(Number(value)) && isFinite(Number(value))) {
560
+ return Number(value);
561
+ }
562
+ if (/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2})?/.test(value)) {
563
+ const date = new Date(value);
564
+ if (!isNaN(date.getTime())) {
565
+ return date;
566
+ }
567
+ }
568
+ if (value.startsWith("{") && value.endsWith("}") || value.startsWith("[") && value.endsWith("]")) {
569
+ try {
570
+ return JSON.parse(value);
571
+ } catch {}
572
+ }
573
+ return value;
574
+ }
575
+ function jsonAction(options) {
576
+ return async (args) => {
577
+ const { request } = args;
578
+ const contentType = request.headers.get("Content-Type") || "";
579
+ if (options.strict && !contentType.includes("application/json")) {
580
+ return {
581
+ success: false,
582
+ errors: { _request: ["Content-Type must be application/json"] }
583
+ };
584
+ }
585
+ return typedAction(options)(args);
586
+ };
587
+ }
588
+ function redirect(url, status = 302) {
589
+ return new Response(null, {
590
+ status,
591
+ headers: { Location: url }
592
+ });
593
+ }
594
+ function json(data, init) {
595
+ return new Response(JSON.stringify(data), {
596
+ ...init,
597
+ headers: {
598
+ "Content-Type": "application/json",
599
+ ...init?.headers
600
+ }
601
+ });
602
+ }
603
+ function error(message, status = 500) {
604
+ return new Response(JSON.stringify({ error: message }), {
605
+ status,
606
+ headers: { "Content-Type": "application/json" }
607
+ });
608
+ }
609
+ function parseFormData(formData) {
610
+ const result = {};
611
+ for (const [key, value] of formData.entries()) {
612
+ if (key.endsWith("[]")) {
613
+ const arrayKey = key.slice(0, -2);
614
+ if (!result[arrayKey]) {
615
+ result[arrayKey] = [];
616
+ }
617
+ result[arrayKey].push(value);
618
+ } else if (result[key] !== undefined) {
619
+ if (!Array.isArray(result[key])) {
620
+ result[key] = [result[key]];
621
+ }
622
+ result[key].push(value);
623
+ } else {
624
+ result[key] = value;
625
+ }
626
+ }
627
+ return result;
628
+ }
629
+ function validateRequired(formData, fields) {
630
+ const errors = {};
631
+ for (const field of fields) {
632
+ const value = formData.get(field);
633
+ if (!value || typeof value === "string" && value.trim() === "") {
634
+ errors[field] = [`${field} is required`];
635
+ }
636
+ }
637
+ return {
638
+ success: Object.keys(errors).length === 0,
639
+ errors: Object.keys(errors).length > 0 ? errors : undefined
640
+ };
641
+ }
642
+ function combineValidators(...validators) {
643
+ return async (formData) => {
644
+ const allErrors = {};
645
+ for (const validator of validators) {
646
+ const result = await validator(formData);
647
+ if (!result.success && result.errors) {
648
+ for (const [field, fieldErrors] of Object.entries(result.errors)) {
649
+ if (!allErrors[field]) {
650
+ allErrors[field] = [];
651
+ }
652
+ allErrors[field].push(...fieldErrors);
653
+ }
654
+ }
655
+ }
656
+ return {
657
+ success: Object.keys(allErrors).length === 0,
658
+ errors: Object.keys(allErrors).length > 0 ? allErrors : undefined
659
+ };
660
+ };
661
+ }
662
+ // src/revalidate.ts
663
+ async function revalidateTag(...tags) {
664
+ const cache = getCache();
665
+ const revalidatedTags = [];
666
+ for (const tag of tags) {
667
+ await cache.deleteByTag(tag);
668
+ revalidatedTags.push(tag);
669
+ }
670
+ return {
671
+ success: true,
672
+ revalidated: {
673
+ tags: revalidatedTags,
674
+ paths: []
675
+ },
676
+ timestamp: Date.now()
677
+ };
678
+ }
679
+ async function revalidatePath(...paths) {
680
+ const cache = getCache();
681
+ const revalidatedPaths = [];
682
+ const allKeys = await cache.keys();
683
+ for (const path of paths) {
684
+ for (const key of allKeys) {
685
+ if (key.includes(`:${path}`) || key.endsWith(path)) {
686
+ await cache.delete(key);
687
+ revalidatedPaths.push(path);
688
+ }
689
+ }
690
+ }
691
+ return {
692
+ success: true,
693
+ revalidated: {
694
+ tags: [],
695
+ paths: [...new Set(revalidatedPaths)]
696
+ },
697
+ timestamp: Date.now()
698
+ };
699
+ }
700
+ async function revalidate2(options) {
701
+ const cache = getCache();
702
+ if (options.all) {
703
+ await cache.clear();
704
+ return {
705
+ success: true,
706
+ revalidated: { tags: ["*"], paths: ["*"] },
707
+ timestamp: Date.now()
708
+ };
709
+ }
710
+ const tagResult = options.tags ? await revalidateTag(...options.tags) : null;
711
+ const pathResult = options.paths ? await revalidatePath(...options.paths) : null;
712
+ return {
713
+ success: true,
714
+ revalidated: {
715
+ tags: tagResult?.revalidated.tags ?? [],
716
+ paths: pathResult?.revalidated.paths ?? []
717
+ },
718
+ timestamp: Date.now()
719
+ };
720
+ }
721
+ function unstable_cache(fn, keyParts, options = {}) {
722
+ return async (...args) => {
723
+ const { cached: cached2, cacheKey: cacheKey2 } = await Promise.resolve().then(() => exports_cache);
724
+ const key = cacheKey2(keyParts.join(":"), JSON.stringify(args));
725
+ return cached2(key, () => fn(...args), {
726
+ maxAge: options.revalidate ?? 3600,
727
+ tags: options.tags ?? []
728
+ });
729
+ };
730
+ }
731
+ function createRevalidationHandler(secret) {
732
+ return async (request) => {
733
+ if (secret) {
734
+ const authHeader = request.headers.get("Authorization");
735
+ if (authHeader !== `Bearer ${secret}`) {
736
+ return new Response(JSON.stringify({ error: "Unauthorized" }), {
737
+ status: 401,
738
+ headers: { "Content-Type": "application/json" }
739
+ });
740
+ }
741
+ }
742
+ try {
743
+ const body = await request.json();
744
+ const result = await revalidate2(body);
745
+ return new Response(JSON.stringify(result), {
746
+ status: 200,
747
+ headers: { "Content-Type": "application/json" }
748
+ });
749
+ } catch (error2) {
750
+ return new Response(JSON.stringify({
751
+ error: error2 instanceof Error ? error2.message : "Unknown error"
752
+ }), {
753
+ status: 500,
754
+ headers: { "Content-Type": "application/json" }
755
+ });
756
+ }
757
+ };
758
+ }
759
+ var tags = {
760
+ resource: (type, id) => `${type}:${id}`,
761
+ collection: (type) => type,
762
+ userScoped: (userId, type) => `user:${userId}:${type}`
763
+ };
764
+ async function onDemandRevalidate(...tagsOrPaths) {
765
+ const tags2 = [];
766
+ const paths = [];
767
+ for (const item of tagsOrPaths) {
768
+ if (item.startsWith("/")) {
769
+ paths.push(item);
770
+ } else {
771
+ tags2.push(item);
772
+ }
773
+ }
774
+ return revalidate2({ tags: tags2, paths });
775
+ }
776
+ // src/pipeline.ts
777
+ function createPipeline(config) {
778
+ const { loaders, dependencies = {}, onError, metrics: enableMetrics = false } = config;
779
+ const graph = buildDependencyGraph(loaders, dependencies);
780
+ return {
781
+ async execute(args) {
782
+ const startTime = performance.now();
783
+ const results = new Map;
784
+ const errors = new Map;
785
+ const loaderMetrics = new Map;
786
+ const executionOrder = [];
787
+ const completed = new Set;
788
+ const inProgress = new Map;
789
+ const executeLoader = async (key) => {
790
+ if (completed.has(key) || inProgress.has(key)) {
791
+ return inProgress.get(key);
792
+ }
793
+ const deps = graph.get(key) || [];
794
+ const waitingFor = [];
795
+ for (const dep of deps) {
796
+ if (!completed.has(dep)) {
797
+ waitingFor.push(dep);
798
+ await executeLoader(dep);
799
+ }
800
+ }
801
+ const loaderStartTime = performance.now() - startTime;
802
+ executionOrder.push({ time: loaderStartTime, type: "start", loader: key });
803
+ const promise = (async () => {
804
+ const loader = loaders[key];
805
+ try {
806
+ const extendedArgs = {
807
+ ...args,
808
+ data: Object.fromEntries(results)
809
+ };
810
+ const result = await loader.load(extendedArgs);
811
+ results.set(key, result);
812
+ } catch (error2) {
813
+ const err = error2 instanceof Error ? error2 : new Error(String(error2));
814
+ if (loader.fallback !== undefined) {
815
+ results.set(key, loader.fallback);
816
+ } else if (loader.required !== false) {
817
+ errors.set(key, err);
818
+ }
819
+ onError?.(err, key);
820
+ }
821
+ const loaderEndTime = performance.now() - startTime;
822
+ executionOrder.push({ time: loaderEndTime, type: "end", loader: key });
823
+ loaderMetrics.set(key, {
824
+ key,
825
+ startTime: loaderStartTime,
826
+ endTime: loaderEndTime,
827
+ duration: loaderEndTime - loaderStartTime,
828
+ cacheHit: false,
829
+ waitingFor
830
+ });
831
+ completed.add(key);
832
+ })();
833
+ inProgress.set(key, promise);
834
+ return promise;
835
+ };
836
+ const roots = Object.keys(loaders).filter((key) => {
837
+ const deps = graph.get(key) || [];
838
+ return deps.length === 0;
839
+ });
840
+ await Promise.all(roots.map(executeLoader));
841
+ await Promise.all(Object.keys(loaders).map(executeLoader));
842
+ const totalTime = performance.now() - startTime;
843
+ const waterfalls = detectWaterfalls(loaderMetrics, graph);
844
+ const parallelEfficiency = calculateParallelEfficiency(loaderMetrics, totalTime);
845
+ return {
846
+ data: Object.fromEntries(results),
847
+ metrics: {
848
+ total: totalTime,
849
+ loaders: loaderMetrics,
850
+ executionOrder,
851
+ parallelEfficiency,
852
+ waterfalls
853
+ },
854
+ errors
855
+ };
856
+ },
857
+ toLoader() {
858
+ return async (args) => {
859
+ const result = await this.execute(args);
860
+ if (result.errors.size > 0) {
861
+ const [key, error2] = result.errors.entries().next().value;
862
+ throw new Error(`Loader '${String(key)}' failed: ${error2.message}`);
863
+ }
864
+ if (enableMetrics && args.context) {
865
+ args.context.set("__pipeline_metrics", result.metrics);
866
+ }
867
+ return result.data;
868
+ };
869
+ },
870
+ getDependencyGraph() {
871
+ return graph;
872
+ }
873
+ };
874
+ }
875
+ function buildDependencyGraph(loaders, dependencies) {
876
+ const graph = new Map;
877
+ for (const key of Object.keys(loaders)) {
878
+ graph.set(key, dependencies[key] || []);
879
+ }
880
+ for (const [key, deps] of graph) {
881
+ for (const dep of deps) {
882
+ if (!loaders[dep]) {
883
+ throw new Error(`Loader '${key}' depends on '${dep}' which does not exist`);
884
+ }
885
+ }
886
+ }
887
+ const visited = new Set;
888
+ const recursionStack = new Set;
889
+ const hasCycle = (node) => {
890
+ visited.add(node);
891
+ recursionStack.add(node);
892
+ const deps = graph.get(node) || [];
893
+ for (const dep of deps) {
894
+ if (!visited.has(dep)) {
895
+ if (hasCycle(dep))
896
+ return true;
897
+ } else if (recursionStack.has(dep)) {
898
+ return true;
899
+ }
900
+ }
901
+ recursionStack.delete(node);
902
+ return false;
903
+ };
904
+ for (const key of graph.keys()) {
905
+ if (!visited.has(key) && hasCycle(key)) {
906
+ throw new Error(`Circular dependency detected involving '${key}'`);
907
+ }
908
+ }
909
+ return graph;
910
+ }
911
+ function detectWaterfalls(metrics, graph) {
912
+ const waterfalls = [];
913
+ for (const [key, metric] of metrics) {
914
+ if (metric.waitingFor.length > 0) {
915
+ const deps = graph.get(key) || [];
916
+ const necessary = metric.waitingFor.every((w) => deps.includes(w));
917
+ if (!necessary) {
918
+ waterfalls.push({
919
+ loader: key,
920
+ waitedFor: metric.waitingFor,
921
+ necessary: false,
922
+ suggestion: `'${key}' waited for ${metric.waitingFor.join(", ")} but doesn't depend on them. Consider running in parallel.`
923
+ });
924
+ } else if (metric.waitingFor.length > 1) {
925
+ waterfalls.push({
926
+ loader: key,
927
+ waitedFor: metric.waitingFor,
928
+ necessary: true,
929
+ suggestion: `'${key}' waited for multiple loaders. Consider if all dependencies are necessary.`
930
+ });
931
+ }
932
+ }
933
+ }
934
+ return waterfalls;
935
+ }
936
+ function calculateParallelEfficiency(metrics, totalTime) {
937
+ if (metrics.size === 0)
938
+ return 1;
939
+ let sequentialTime = 0;
940
+ for (const metric of metrics.values()) {
941
+ sequentialTime += metric.duration;
942
+ }
943
+ if (totalTime === 0)
944
+ return 1;
945
+ return Math.min(1, sequentialTime / (totalTime * metrics.size));
946
+ }
947
+ function dataSource(load, options = {}) {
948
+ return { load, ...options };
949
+ }
950
+ function cachedSource(load, options) {
951
+ return {
952
+ load,
953
+ tags: options.tags,
954
+ ttl: options.ttl
955
+ };
956
+ }
957
+ function optionalSource(load, fallback) {
958
+ return {
959
+ load,
960
+ fallback,
961
+ required: false
962
+ };
963
+ }
964
+ function combinePipelines(pipelines) {
965
+ return {
966
+ async execute(args) {
967
+ const results = await Promise.all(Object.entries(pipelines).map(async ([key, pipeline]) => {
968
+ const result = await pipeline.execute(args);
969
+ return [key, result.data];
970
+ }));
971
+ return Object.fromEntries(results);
972
+ }
973
+ };
974
+ }
975
+ function formatMetrics(metrics) {
976
+ const lines = [
977
+ `Pipeline completed in ${metrics.total.toFixed(1)}ms`,
978
+ `Parallel efficiency: ${(metrics.parallelEfficiency * 100).toFixed(0)}%`,
979
+ "",
980
+ "Loader Timings:"
981
+ ];
982
+ const sorted = Array.from(metrics.loaders.values()).sort((a, b) => a.startTime - b.startTime);
983
+ for (const loader of sorted) {
984
+ const bar = generateTimeBar(loader.startTime, loader.endTime, metrics.total);
985
+ const cacheIndicator = loader.cacheHit ? " \x1B[32m(cache)\x1B[0m" : "";
986
+ lines.push(` ${loader.key.padEnd(20)} ${bar} ${loader.duration.toFixed(1)}ms${cacheIndicator}`);
987
+ }
988
+ if (metrics.waterfalls.length > 0) {
989
+ lines.push("");
990
+ lines.push("\u26A0\uFE0F Detected Waterfalls:");
991
+ for (const waterfall of metrics.waterfalls) {
992
+ lines.push(` - ${waterfall.loader}: ${waterfall.suggestion}`);
993
+ }
994
+ }
995
+ return lines.join(`
996
+ `);
997
+ }
998
+ function generateTimeBar(start, end, total, width = 40) {
999
+ if (total === 0)
1000
+ return "\u2501".repeat(width);
1001
+ const startPos = Math.floor(start / total * width);
1002
+ const endPos = Math.ceil(end / total * width);
1003
+ let bar = "";
1004
+ for (let i = 0;i < width; i++) {
1005
+ if (i < startPos) {
1006
+ bar += "\u2500";
1007
+ } else if (i < endPos) {
1008
+ bar += "\u2501";
1009
+ } else {
1010
+ bar += "\u2500";
1011
+ }
1012
+ }
1013
+ return bar;
1014
+ }
1015
+ function generateMetricsVisualization(metrics) {
1016
+ const timeline = Array.from(metrics.loaders.values()).sort((a, b) => a.startTime - b.startTime).map((m) => ({
1017
+ key: m.key,
1018
+ start: m.startTime,
1019
+ end: m.endTime,
1020
+ duration: m.duration,
1021
+ cacheHit: m.cacheHit,
1022
+ waitingFor: m.waitingFor
1023
+ }));
1024
+ return {
1025
+ timeline,
1026
+ total: metrics.total,
1027
+ efficiency: metrics.parallelEfficiency,
1028
+ waterfalls: metrics.waterfalls
1029
+ };
1030
+ }
1031
+ // src/define-route.ts
1032
+ function defineRoute(path) {
1033
+ const state = {
1034
+ path,
1035
+ middleware: []
1036
+ };
1037
+ const createBuilder = () => ({
1038
+ [Symbol()]: path,
1039
+ loader(fn) {
1040
+ state.loader = fn;
1041
+ return createBuilderWithLoader();
1042
+ },
1043
+ searchParams(schema) {
1044
+ state.searchParamsSchema = schema;
1045
+ return createBuilder();
1046
+ },
1047
+ hashParams(schema) {
1048
+ state.hashParamsSchema = schema;
1049
+ return createBuilder();
1050
+ },
1051
+ middleware(...handlers) {
1052
+ state.middleware = [...state.middleware || [], ...handlers];
1053
+ return createBuilder();
1054
+ },
1055
+ configure(config) {
1056
+ state.config = config;
1057
+ return createBuilder();
1058
+ },
1059
+ build() {
1060
+ return {
1061
+ path,
1062
+ middleware: state.middleware,
1063
+ config: state.config,
1064
+ searchParamsSchema: state.searchParamsSchema,
1065
+ hashParamsSchema: state.hashParamsSchema,
1066
+ _types: {}
1067
+ };
1068
+ }
1069
+ });
1070
+ const createBuilderWithLoader = () => ({
1071
+ [Symbol()]: path,
1072
+ [Symbol()]: {},
1073
+ action(fn, options) {
1074
+ state.action = fn;
1075
+ if (options?.schema) {
1076
+ state.actionBodySchema = options.schema;
1077
+ }
1078
+ return createBuilderWithLoaderAndAction();
1079
+ },
1080
+ head(fn) {
1081
+ state.head = fn;
1082
+ return createBuilderWithLoader();
1083
+ },
1084
+ meta(fn) {
1085
+ state.meta = fn;
1086
+ return createBuilderWithLoader();
1087
+ },
1088
+ cache(options) {
1089
+ state.cache = options;
1090
+ return createBuilderWithLoader();
1091
+ },
1092
+ middleware(...handlers) {
1093
+ state.middleware = [...state.middleware || [], ...handlers];
1094
+ return createBuilderWithLoader();
1095
+ },
1096
+ configure(config) {
1097
+ state.config = config;
1098
+ return createBuilderWithLoader();
1099
+ },
1100
+ build() {
1101
+ return {
1102
+ path,
1103
+ loader: createWrappedLoader(),
1104
+ head: state.head,
1105
+ meta: state.meta,
1106
+ middleware: state.middleware,
1107
+ config: state.config,
1108
+ cache: state.cache,
1109
+ searchParamsSchema: state.searchParamsSchema,
1110
+ hashParamsSchema: state.hashParamsSchema,
1111
+ _types: {}
1112
+ };
1113
+ }
1114
+ });
1115
+ const createBuilderWithLoaderAndAction = () => ({
1116
+ [Symbol()]: path,
1117
+ [Symbol()]: {},
1118
+ [Symbol()]: {},
1119
+ head(fn) {
1120
+ state.head = fn;
1121
+ return createBuilderWithLoaderAndAction();
1122
+ },
1123
+ meta(fn) {
1124
+ state.meta = fn;
1125
+ return createBuilderWithLoaderAndAction();
1126
+ },
1127
+ cache(options) {
1128
+ state.cache = options;
1129
+ return createBuilderWithLoaderAndAction();
1130
+ },
1131
+ middleware(...handlers) {
1132
+ state.middleware = [...state.middleware || [], ...handlers];
1133
+ return createBuilderWithLoaderAndAction();
1134
+ },
1135
+ configure(config) {
1136
+ state.config = config;
1137
+ return createBuilderWithLoaderAndAction();
1138
+ },
1139
+ build() {
1140
+ return {
1141
+ path,
1142
+ loader: createWrappedLoader(),
1143
+ action: createWrappedAction(),
1144
+ head: state.head,
1145
+ meta: state.meta,
1146
+ middleware: state.middleware,
1147
+ config: state.config,
1148
+ cache: state.cache,
1149
+ searchParamsSchema: state.searchParamsSchema,
1150
+ hashParamsSchema: state.hashParamsSchema,
1151
+ actionBodySchema: state.actionBodySchema,
1152
+ _types: {}
1153
+ };
1154
+ }
1155
+ });
1156
+ const createWrappedLoader = () => {
1157
+ return async (args) => {
1158
+ if (state.cache) {
1159
+ args.context.cache.set(state.cache);
1160
+ }
1161
+ let searchParams;
1162
+ if (state.searchParamsSchema) {
1163
+ const url = new URL(args.request.url);
1164
+ const rawParams = {};
1165
+ url.searchParams.forEach((value, key) => {
1166
+ if (rawParams[key]) {
1167
+ const existing = rawParams[key];
1168
+ rawParams[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];
1169
+ } else {
1170
+ rawParams[key] = value;
1171
+ }
1172
+ });
1173
+ searchParams = state.searchParamsSchema.parse(rawParams);
1174
+ }
1175
+ let hashParams;
1176
+ if (state.hashParamsSchema) {
1177
+ const url = new URL(args.request.url);
1178
+ if (url.hash) {
1179
+ const hashSearchParams = new URLSearchParams(url.hash.slice(1));
1180
+ const rawParams = {};
1181
+ hashSearchParams.forEach((value, key) => {
1182
+ rawParams[key] = value;
1183
+ });
1184
+ hashParams = state.hashParamsSchema.parse(rawParams);
1185
+ }
1186
+ }
1187
+ const typedArgs = {
1188
+ ...args,
1189
+ searchParams,
1190
+ hashParams
1191
+ };
1192
+ return state.loader(typedArgs);
1193
+ };
1194
+ };
1195
+ const createWrappedAction = () => {
1196
+ return async (args) => {
1197
+ const { request } = args;
1198
+ const contentType = request.headers.get("Content-Type") || "";
1199
+ let body;
1200
+ let formData;
1201
+ if (contentType.includes("application/json")) {
1202
+ const rawBody = await request.json();
1203
+ body = state.actionBodySchema ? state.actionBodySchema.parse(rawBody) : rawBody;
1204
+ } else if (contentType.includes("multipart/form-data") || contentType.includes("application/x-www-form-urlencoded")) {
1205
+ formData = await request.formData();
1206
+ const rawBody = formDataToObject2(formData);
1207
+ body = state.actionBodySchema ? state.actionBodySchema.parse(rawBody) : rawBody;
1208
+ } else {
1209
+ try {
1210
+ const text = await request.text();
1211
+ const rawBody = JSON.parse(text);
1212
+ body = state.actionBodySchema ? state.actionBodySchema.parse(rawBody) : rawBody;
1213
+ } catch {
1214
+ body = {};
1215
+ }
1216
+ }
1217
+ const typedArgs = {
1218
+ ...args,
1219
+ body,
1220
+ formData
1221
+ };
1222
+ return state.action(typedArgs);
1223
+ };
1224
+ };
1225
+ return createBuilder();
1226
+ }
1227
+ function formDataToObject2(formData) {
1228
+ const result = {};
1229
+ for (const [key, value] of formData.entries()) {
1230
+ if (key.endsWith("[]")) {
1231
+ const arrayKey = key.slice(0, -2);
1232
+ if (!result[arrayKey]) {
1233
+ result[arrayKey] = [];
1234
+ }
1235
+ result[arrayKey].push(value);
1236
+ } else if (result[key] !== undefined) {
1237
+ if (!Array.isArray(result[key])) {
1238
+ result[key] = [result[key]];
1239
+ }
1240
+ result[key].push(value);
1241
+ } else {
1242
+ result[key] = value;
1243
+ }
1244
+ }
1245
+ return result;
1246
+ }
1247
+ // src/schema-adapters.ts
1248
+ function ereoSchema(schema) {
1249
+ return {
1250
+ parse: (data) => {
1251
+ return schema.parse(data);
1252
+ },
1253
+ safeParse: (data) => {
1254
+ const result = schema.safeParse(data);
1255
+ if (result.success) {
1256
+ return { success: true, data: result.data };
1257
+ }
1258
+ return {
1259
+ success: false,
1260
+ error: {
1261
+ errors: result.error.errors.map((err) => ({
1262
+ path: err.path,
1263
+ message: err.message
1264
+ }))
1265
+ }
1266
+ };
1267
+ },
1268
+ _original: schema,
1269
+ _ereoSchema: true,
1270
+ _output: {}
1271
+ };
1272
+ }
1273
+ function isEreoSchema(value) {
1274
+ return typeof value === "object" && value !== null && "_ereoSchema" in value && value._ereoSchema === true;
1275
+ }
1276
+ function createPaginationParser(options = {}) {
1277
+ const { defaultPage = 1, defaultLimit = 10, maxLimit = 100 } = options;
1278
+ return {
1279
+ parse: (data) => {
1280
+ const input = data;
1281
+ const page = parseNumber(input.page, defaultPage);
1282
+ const limit = Math.min(parseNumber(input.limit, defaultLimit), maxLimit);
1283
+ const offset = parseNumber(input.offset, undefined);
1284
+ return {
1285
+ page: page > 0 ? page : defaultPage,
1286
+ limit: limit > 0 ? limit : defaultLimit,
1287
+ offset: offset !== undefined && offset >= 0 ? offset : undefined
1288
+ };
1289
+ },
1290
+ safeParse: (data) => {
1291
+ try {
1292
+ const result = createPaginationParser(options).parse(data);
1293
+ return { success: true, data: result };
1294
+ } catch (error2) {
1295
+ return {
1296
+ success: false,
1297
+ error: {
1298
+ errors: [
1299
+ {
1300
+ path: [],
1301
+ message: error2 instanceof Error ? error2.message : "Invalid pagination params"
1302
+ }
1303
+ ]
1304
+ }
1305
+ };
1306
+ }
1307
+ }
1308
+ };
1309
+ }
1310
+ function createSortParser(allowedFields, defaultField, defaultOrder = "asc") {
1311
+ return {
1312
+ parse: (data) => {
1313
+ const input = data;
1314
+ const sortBy = allowedFields.includes(input.sortBy) ? input.sortBy : defaultField;
1315
+ const sortOrder = input.sortOrder === "asc" || input.sortOrder === "desc" ? input.sortOrder : defaultOrder;
1316
+ return { sortBy, sortOrder };
1317
+ },
1318
+ safeParse: (data) => {
1319
+ try {
1320
+ const result = createSortParser(allowedFields, defaultField, defaultOrder).parse(data);
1321
+ return { success: true, data: result };
1322
+ } catch (error2) {
1323
+ return {
1324
+ success: false,
1325
+ error: {
1326
+ errors: [
1327
+ {
1328
+ path: [],
1329
+ message: error2 instanceof Error ? error2.message : "Invalid sort params"
1330
+ }
1331
+ ]
1332
+ }
1333
+ };
1334
+ }
1335
+ }
1336
+ };
1337
+ }
1338
+ function createFilterParser(allowedFilters) {
1339
+ return {
1340
+ parse: (data) => {
1341
+ const input = data;
1342
+ const result = {};
1343
+ for (const [key, allowedValues] of Object.entries(allowedFilters)) {
1344
+ const value = input[key];
1345
+ if (value === undefined)
1346
+ continue;
1347
+ if (Array.isArray(value)) {
1348
+ const validValues = value.filter((v) => allowedValues.includes(String(v)));
1349
+ if (validValues.length > 0) {
1350
+ result[key] = validValues;
1351
+ }
1352
+ } else if (allowedValues.includes(String(value))) {
1353
+ result[key] = value;
1354
+ }
1355
+ }
1356
+ return result;
1357
+ },
1358
+ safeParse: (data) => {
1359
+ try {
1360
+ const res = createFilterParser(allowedFilters).parse(data);
1361
+ return { success: true, data: res };
1362
+ } catch (error2) {
1363
+ return {
1364
+ success: false,
1365
+ error: {
1366
+ errors: [
1367
+ {
1368
+ path: [],
1369
+ message: error2 instanceof Error ? error2.message : "Invalid filter params"
1370
+ }
1371
+ ]
1372
+ }
1373
+ };
1374
+ }
1375
+ }
1376
+ };
1377
+ }
1378
+ function parseNumber(value, fallback) {
1379
+ if (value === undefined || value === null || value === "") {
1380
+ return fallback;
1381
+ }
1382
+ const num = Number(value);
1383
+ return isNaN(num) ? fallback : num;
1384
+ }
1385
+ function parseBoolean(value, fallback = false) {
1386
+ if (value === undefined || value === null || value === "") {
1387
+ return fallback;
1388
+ }
1389
+ if (typeof value === "boolean") {
1390
+ return value;
1391
+ }
1392
+ const str = String(value).toLowerCase();
1393
+ if (str === "true" || str === "1" || str === "yes") {
1394
+ return true;
1395
+ }
1396
+ if (str === "false" || str === "0" || str === "no") {
1397
+ return false;
1398
+ }
1399
+ return fallback;
1400
+ }
1401
+ function parseStringArray(value) {
1402
+ if (Array.isArray(value)) {
1403
+ return value.map(String);
1404
+ }
1405
+ if (typeof value === "string") {
1406
+ if (value.includes(",")) {
1407
+ return value.split(",").map((s) => s.trim());
1408
+ }
1409
+ return [value];
1410
+ }
1411
+ return [];
1412
+ }
1413
+ function parseDate(value, fallback) {
1414
+ if (value === undefined || value === null || value === "") {
1415
+ return fallback;
1416
+ }
1417
+ if (value instanceof Date) {
1418
+ return isNaN(value.getTime()) ? fallback : value;
1419
+ }
1420
+ const date = new Date(String(value));
1421
+ return isNaN(date.getTime()) ? fallback : date;
1422
+ }
1423
+ function parseEnum(value, allowedValues, fallback) {
1424
+ if (value === undefined || value === null || value === "") {
1425
+ return fallback;
1426
+ }
1427
+ const str = String(value);
1428
+ return allowedValues.includes(str) ? str : fallback;
1429
+ }
1430
+ function schemaBuilder() {
1431
+ return new SchemaBuilderImpl({});
1432
+ }
1433
+
1434
+ class SchemaBuilderImpl {
1435
+ fields;
1436
+ constructor(fields) {
1437
+ this.fields = fields;
1438
+ }
1439
+ string(key, options) {
1440
+ return new SchemaBuilderImpl({
1441
+ ...this.fields,
1442
+ [key]: { type: "string", ...options }
1443
+ });
1444
+ }
1445
+ number(key, options) {
1446
+ return new SchemaBuilderImpl({
1447
+ ...this.fields,
1448
+ [key]: { type: "number", ...options }
1449
+ });
1450
+ }
1451
+ boolean(key, options) {
1452
+ return new SchemaBuilderImpl({
1453
+ ...this.fields,
1454
+ [key]: { type: "boolean", ...options }
1455
+ });
1456
+ }
1457
+ enum(key, values, options) {
1458
+ return new SchemaBuilderImpl({
1459
+ ...this.fields,
1460
+ [key]: { type: "enum", values: [...values], ...options }
1461
+ });
1462
+ }
1463
+ array(key, options) {
1464
+ return new SchemaBuilderImpl({
1465
+ ...this.fields,
1466
+ [key]: { type: "array", ...options }
1467
+ });
1468
+ }
1469
+ build() {
1470
+ const fields = this.fields;
1471
+ return {
1472
+ parse: (data) => {
1473
+ const input = data || {};
1474
+ const result = {};
1475
+ for (const [key, config] of Object.entries(fields)) {
1476
+ const value = input[key];
1477
+ switch (config.type) {
1478
+ case "string":
1479
+ result[key] = value !== undefined ? String(value) : config.default;
1480
+ break;
1481
+ case "number": {
1482
+ const num = parseNumber(value, config.default);
1483
+ if (config.min !== undefined && num !== undefined && num < config.min) {
1484
+ result[key] = config.min;
1485
+ } else if (config.max !== undefined && num !== undefined && num > config.max) {
1486
+ result[key] = config.max;
1487
+ } else {
1488
+ result[key] = num;
1489
+ }
1490
+ break;
1491
+ }
1492
+ case "boolean":
1493
+ result[key] = parseBoolean(value, config.default);
1494
+ break;
1495
+ case "enum":
1496
+ result[key] = parseEnum(value, config.values, config.default);
1497
+ break;
1498
+ case "array": {
1499
+ const arr = parseStringArray(value);
1500
+ result[key] = config.of === "number" ? arr.map(Number).filter((n) => !isNaN(n)) : arr;
1501
+ break;
1502
+ }
1503
+ }
1504
+ }
1505
+ return result;
1506
+ },
1507
+ safeParse: (data) => {
1508
+ try {
1509
+ const result = schemaBuilder().build().parse(data);
1510
+ return { success: true, data: result };
1511
+ } catch (error2) {
1512
+ return {
1513
+ success: false,
1514
+ error: {
1515
+ errors: [
1516
+ {
1517
+ path: [],
1518
+ message: error2 instanceof Error ? error2.message : "Validation failed"
1519
+ }
1520
+ ]
1521
+ }
1522
+ };
1523
+ }
1524
+ }
1525
+ };
1526
+ }
1527
+ }
1528
+ export {
1529
+ validateRequired,
1530
+ unstable_cache,
1531
+ typedAction,
1532
+ tags,
1533
+ setCache,
1534
+ serializeLoaderData,
1535
+ schemaBuilder,
1536
+ revalidateTag,
1537
+ revalidatePath,
1538
+ revalidate2 as revalidate,
1539
+ resolveDeferred,
1540
+ redirect,
1541
+ parseStringArray,
1542
+ parseRequestBody,
1543
+ parseLoaderData,
1544
+ parseFormData,
1545
+ parseEnum,
1546
+ parseDate,
1547
+ parseCacheControl,
1548
+ parseBoolean,
1549
+ optionalSource,
1550
+ onDemandRevalidate,
1551
+ jsonAction,
1552
+ json,
1553
+ isEreoSchema,
1554
+ isDeferred,
1555
+ getCache,
1556
+ generateMetricsVisualization,
1557
+ generateCacheKey,
1558
+ formatMetrics,
1559
+ formDataToObject,
1560
+ fetchData,
1561
+ error,
1562
+ ereoSchema,
1563
+ defineRoute,
1564
+ defer,
1565
+ dataSource,
1566
+ createSortParser,
1567
+ createRevalidationHandler,
1568
+ createPipeline,
1569
+ createPaginationParser,
1570
+ createLoader,
1571
+ createFilterParser,
1572
+ createDataCacheAdapter,
1573
+ createAction,
1574
+ combineValidators,
1575
+ combinePipelines,
1576
+ combineLoaders,
1577
+ coerceValue,
1578
+ clientLoader,
1579
+ cachedSource,
1580
+ cached,
1581
+ cacheKey,
1582
+ buildCacheControl,
1583
+ action,
1584
+ MemoryCache,
1585
+ FetchError,
1586
+ Cached
1587
+ };