@revealui/cache 0.1.0

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,760 @@
1
+ // src/cdn-config.ts
2
+ var DEFAULT_CDN_CONFIG = {
3
+ provider: "vercel",
4
+ ttl: 31536e3,
5
+ // 1 year for static assets
6
+ staleWhileRevalidate: 86400,
7
+ // 1 day
8
+ staleIfError: 604800,
9
+ // 1 week
10
+ bypassCache: false,
11
+ cacheKey: ["url", "headers.accept", "headers.accept-encoding"],
12
+ varyHeaders: ["Accept", "Accept-Encoding"]
13
+ };
14
+ function generateCacheControl(config) {
15
+ const directives = [];
16
+ if (config.noStore) {
17
+ directives.push("no-store");
18
+ return directives.join(", ");
19
+ }
20
+ if (config.noCache) {
21
+ directives.push("no-cache");
22
+ return directives.join(", ");
23
+ }
24
+ if (config.public) {
25
+ directives.push("public");
26
+ } else if (config.private) {
27
+ directives.push("private");
28
+ }
29
+ if (config.maxAge !== void 0) {
30
+ directives.push(`max-age=${config.maxAge}`);
31
+ }
32
+ if (config.sMaxAge !== void 0) {
33
+ directives.push(`s-maxage=${config.sMaxAge}`);
34
+ }
35
+ if (config.staleWhileRevalidate !== void 0) {
36
+ directives.push(`stale-while-revalidate=${config.staleWhileRevalidate}`);
37
+ }
38
+ if (config.staleIfError !== void 0) {
39
+ directives.push(`stale-if-error=${config.staleIfError}`);
40
+ }
41
+ if (config.immutable) {
42
+ directives.push("immutable");
43
+ }
44
+ return directives.join(", ");
45
+ }
46
+ var CDN_CACHE_PRESETS = {
47
+ // Static assets with hashed filenames (immutable)
48
+ immutable: {
49
+ maxAge: 31536e3,
50
+ // 1 year
51
+ sMaxAge: 31536e3,
52
+ public: true,
53
+ immutable: true
54
+ },
55
+ // Static assets (images, fonts)
56
+ static: {
57
+ maxAge: 2592e3,
58
+ // 30 days
59
+ sMaxAge: 31536e3,
60
+ // 1 year on CDN
61
+ staleWhileRevalidate: 86400,
62
+ // 1 day
63
+ public: true
64
+ },
65
+ // API responses (short-lived)
66
+ api: {
67
+ maxAge: 0,
68
+ sMaxAge: 60,
69
+ // 1 minute on CDN
70
+ staleWhileRevalidate: 30,
71
+ public: true
72
+ },
73
+ // HTML pages (dynamic)
74
+ page: {
75
+ maxAge: 0,
76
+ sMaxAge: 300,
77
+ // 5 minutes on CDN
78
+ staleWhileRevalidate: 60,
79
+ public: true
80
+ },
81
+ // User-specific data
82
+ private: {
83
+ maxAge: 300,
84
+ // 5 minutes
85
+ private: true,
86
+ staleWhileRevalidate: 60
87
+ },
88
+ // No caching
89
+ noCache: {
90
+ noStore: true
91
+ },
92
+ // Revalidate every request
93
+ revalidate: {
94
+ maxAge: 0,
95
+ sMaxAge: 0,
96
+ noCache: true
97
+ }
98
+ };
99
+ async function purgeCDNCache(urls, config) {
100
+ const { provider } = config;
101
+ switch (provider) {
102
+ case "cloudflare":
103
+ return purgeCloudflare(urls, config);
104
+ case "vercel":
105
+ return purgeVercel(urls, config);
106
+ case "fastly":
107
+ return purgeFastly(urls, config);
108
+ default:
109
+ throw new Error(`Unsupported CDN provider: ${provider}`);
110
+ }
111
+ }
112
+ async function purgeCloudflare(urls, config) {
113
+ const { apiKey, zoneId } = config;
114
+ if (!(apiKey && zoneId)) {
115
+ throw new Error("Cloudflare API key and zone ID required");
116
+ }
117
+ try {
118
+ const response = await fetch(
119
+ `https://api.cloudflare.com/client/v4/zones/${zoneId}/purge_cache`,
120
+ {
121
+ method: "POST",
122
+ headers: {
123
+ Authorization: `Bearer ${apiKey}`,
124
+ "Content-Type": "application/json"
125
+ },
126
+ body: JSON.stringify({ files: urls })
127
+ }
128
+ );
129
+ const data = await response.json();
130
+ return {
131
+ success: data.success,
132
+ purged: urls.length,
133
+ errors: data.errors
134
+ };
135
+ } catch (error) {
136
+ return {
137
+ success: false,
138
+ purged: 0,
139
+ errors: [error instanceof Error ? error.message : "Unknown error"]
140
+ };
141
+ }
142
+ }
143
+ async function purgeVercel(urls, config) {
144
+ const { apiKey } = config;
145
+ if (!apiKey) {
146
+ throw new Error("Vercel API token required");
147
+ }
148
+ try {
149
+ const response = await fetch("https://api.vercel.com/v1/purge", {
150
+ method: "POST",
151
+ headers: {
152
+ Authorization: `Bearer ${apiKey}`,
153
+ "Content-Type": "application/json"
154
+ },
155
+ body: JSON.stringify({ urls })
156
+ });
157
+ const data = await response.json();
158
+ return {
159
+ success: response.ok,
160
+ purged: urls.length,
161
+ errors: data.error ? [data.error.message] : void 0
162
+ };
163
+ } catch (error) {
164
+ return {
165
+ success: false,
166
+ purged: 0,
167
+ errors: [error instanceof Error ? error.message : "Unknown error"]
168
+ };
169
+ }
170
+ }
171
+ async function purgeFastly(urls, config) {
172
+ const { apiKey } = config;
173
+ if (!apiKey) {
174
+ throw new Error("Fastly API key required");
175
+ }
176
+ try {
177
+ const results = await Promise.all(
178
+ urls.map(async (url) => {
179
+ const response = await fetch(url, {
180
+ method: "PURGE",
181
+ headers: {
182
+ "Fastly-Key": apiKey
183
+ }
184
+ });
185
+ return response.ok;
186
+ })
187
+ );
188
+ const purged = results.filter(Boolean).length;
189
+ return {
190
+ success: purged === urls.length,
191
+ purged
192
+ };
193
+ } catch (error) {
194
+ return {
195
+ success: false,
196
+ purged: 0,
197
+ errors: [error instanceof Error ? error.message : "Unknown error"]
198
+ };
199
+ }
200
+ }
201
+ async function purgeCacheByTag(tags, config) {
202
+ const { provider, apiKey, zoneId } = config;
203
+ if (provider === "cloudflare") {
204
+ if (!(apiKey && zoneId)) {
205
+ throw new Error("Cloudflare API key and zone ID required");
206
+ }
207
+ try {
208
+ const response = await fetch(
209
+ `https://api.cloudflare.com/client/v4/zones/${zoneId}/purge_cache`,
210
+ {
211
+ method: "POST",
212
+ headers: {
213
+ Authorization: `Bearer ${apiKey}`,
214
+ "Content-Type": "application/json"
215
+ },
216
+ body: JSON.stringify({ tags })
217
+ }
218
+ );
219
+ const data = await response.json();
220
+ return {
221
+ success: data.success,
222
+ purged: tags.length,
223
+ errors: data.errors
224
+ };
225
+ } catch (error) {
226
+ return {
227
+ success: false,
228
+ purged: 0,
229
+ errors: [error instanceof Error ? error.message : "Unknown error"]
230
+ };
231
+ }
232
+ }
233
+ throw new Error(`Cache tag purging not supported for ${provider}`);
234
+ }
235
+ async function purgeAllCache(config) {
236
+ const { provider, apiKey, zoneId } = config;
237
+ if (provider === "cloudflare") {
238
+ if (!(apiKey && zoneId)) {
239
+ throw new Error("Cloudflare API key and zone ID required");
240
+ }
241
+ try {
242
+ const response = await fetch(
243
+ `https://api.cloudflare.com/client/v4/zones/${zoneId}/purge_cache`,
244
+ {
245
+ method: "POST",
246
+ headers: {
247
+ Authorization: `Bearer ${apiKey}`,
248
+ "Content-Type": "application/json"
249
+ },
250
+ body: JSON.stringify({ purge_everything: true })
251
+ }
252
+ );
253
+ const data = await response.json();
254
+ return {
255
+ success: data.success,
256
+ errors: data.errors
257
+ };
258
+ } catch (error) {
259
+ return {
260
+ success: false,
261
+ errors: [error instanceof Error ? error.message : "Unknown error"]
262
+ };
263
+ }
264
+ }
265
+ throw new Error(`Purge all not supported for ${provider}`);
266
+ }
267
+ async function warmCDNCache(urls, options = {}) {
268
+ const { concurrency = 5, headers = {} } = options;
269
+ const results = [];
270
+ const chunks = [];
271
+ for (let i = 0; i < urls.length; i += concurrency) {
272
+ chunks.push(urls.slice(i, i + concurrency));
273
+ }
274
+ for (const chunk of chunks) {
275
+ const chunkResults = await Promise.all(
276
+ chunk.map(async (url) => {
277
+ try {
278
+ const response = await fetch(url, { headers });
279
+ return {
280
+ success: response.ok,
281
+ error: response.ok ? void 0 : `${response.status} ${response.statusText}`
282
+ };
283
+ } catch (error) {
284
+ return {
285
+ success: false,
286
+ error: error instanceof Error ? error.message : "Unknown error"
287
+ };
288
+ }
289
+ })
290
+ );
291
+ results.push(...chunkResults);
292
+ }
293
+ const warmed = results.filter((r) => r.success).length;
294
+ const failed = results.filter((r) => !r.success).length;
295
+ const errors = results.flatMap((r) => r.error ? [r.error] : []);
296
+ return { warmed, failed, errors };
297
+ }
298
+ function generateCacheTags(resource) {
299
+ const tags = [];
300
+ tags.push(resource.type);
301
+ if (resource.id) {
302
+ tags.push(`${resource.type}:${resource.id}`);
303
+ }
304
+ if (resource.related) {
305
+ tags.push(...resource.related);
306
+ }
307
+ return tags;
308
+ }
309
+ function generateVercelCacheConfig(preset) {
310
+ const config = CDN_CACHE_PRESETS[preset];
311
+ const cacheControl = generateCacheControl(config);
312
+ return {
313
+ headers: {
314
+ "Cache-Control": cacheControl,
315
+ "CDN-Cache-Control": cacheControl,
316
+ "Vercel-CDN-Cache-Control": cacheControl
317
+ }
318
+ };
319
+ }
320
+ function generateCloudflareConfig(preset, options = {}) {
321
+ const config = CDN_CACHE_PRESETS[preset];
322
+ const cacheControl = generateCacheControl(config);
323
+ const headers = {
324
+ "Cache-Control": cacheControl
325
+ };
326
+ if (options.cacheTags && options.cacheTags.length > 0) {
327
+ headers["Cache-Tag"] = options.cacheTags.join(",");
328
+ }
329
+ if (options.bypassOnCookie) {
330
+ headers["Cache-Control"] = `${cacheControl}, bypass=${options.bypassOnCookie}`;
331
+ }
332
+ return { headers };
333
+ }
334
+ function shouldCacheResponse(status, headers) {
335
+ if (status >= 400) {
336
+ return false;
337
+ }
338
+ const cacheControl = headers.get("cache-control") || "";
339
+ if (cacheControl.includes("no-store") || cacheControl.includes("no-cache") || cacheControl.includes("private")) {
340
+ return false;
341
+ }
342
+ return true;
343
+ }
344
+ function getCacheTTL(headers) {
345
+ const cacheControl = headers.get("cache-control") || "";
346
+ const sMaxAgeMatch = cacheControl.match(/s-maxage=(\d+)/);
347
+ if (sMaxAgeMatch?.[1]) {
348
+ return parseInt(sMaxAgeMatch[1], 10);
349
+ }
350
+ const maxAgeMatch = cacheControl.match(/max-age=(\d+)/);
351
+ if (maxAgeMatch?.[1]) {
352
+ return parseInt(maxAgeMatch[1], 10);
353
+ }
354
+ const expires = headers.get("expires");
355
+ if (expires) {
356
+ const expiresDate = new Date(expires);
357
+ const now = /* @__PURE__ */ new Date();
358
+ return Math.max(0, Math.floor((expiresDate.getTime() - now.getTime()) / 1e3));
359
+ }
360
+ return 0;
361
+ }
362
+
363
+ // src/logger.ts
364
+ var cacheLogger = console;
365
+ function configureCacheLogger(logger) {
366
+ cacheLogger = logger;
367
+ }
368
+ function getCacheLogger() {
369
+ return cacheLogger;
370
+ }
371
+
372
+ // src/edge-cache.ts
373
+ var ISR_PRESETS = {
374
+ // Revalidate every request
375
+ always: {
376
+ revalidate: 0
377
+ },
378
+ // Revalidate every minute
379
+ minute: {
380
+ revalidate: 60
381
+ },
382
+ // Revalidate every 5 minutes
383
+ fiveMinutes: {
384
+ revalidate: 300
385
+ },
386
+ // Revalidate every hour
387
+ hourly: {
388
+ revalidate: 3600
389
+ },
390
+ // Revalidate daily
391
+ daily: {
392
+ revalidate: 86400
393
+ },
394
+ // Never revalidate (static)
395
+ never: {
396
+ revalidate: false
397
+ }
398
+ };
399
+ async function generateStaticParams(fetchFn, mapFn) {
400
+ try {
401
+ const items = await fetchFn();
402
+ return items.map(mapFn);
403
+ } catch (error) {
404
+ getCacheLogger().error(
405
+ "Failed to generate static params",
406
+ error instanceof Error ? error : new Error(String(error))
407
+ );
408
+ return [];
409
+ }
410
+ }
411
+ async function revalidateTag(tag, secret) {
412
+ const baseUrl = process.env.NEXT_PUBLIC_URL;
413
+ if (!baseUrl) {
414
+ getCacheLogger().warn("revalidateTag skipped: NEXT_PUBLIC_URL is not configured", { tag });
415
+ return { revalidated: false, error: "NEXT_PUBLIC_URL is not configured" };
416
+ }
417
+ try {
418
+ const url = new URL("/api/revalidate", baseUrl);
419
+ const headers = { "Content-Type": "application/json" };
420
+ if (secret) {
421
+ headers["x-revalidate-secret"] = secret;
422
+ }
423
+ const response = await fetch(url.toString(), {
424
+ method: "POST",
425
+ headers,
426
+ body: JSON.stringify({ tag })
427
+ });
428
+ const data = await response.json();
429
+ if (!response.ok) {
430
+ getCacheLogger().warn("revalidateTag failed", {
431
+ tag,
432
+ status: response.status,
433
+ error: data.error
434
+ });
435
+ }
436
+ return {
437
+ revalidated: response.ok,
438
+ error: data.error
439
+ };
440
+ } catch (error) {
441
+ const message = error instanceof Error ? error.message : "Unknown error";
442
+ getCacheLogger().warn("revalidateTag error", { tag, error: message });
443
+ return {
444
+ revalidated: false,
445
+ error: message
446
+ };
447
+ }
448
+ }
449
+ async function revalidatePath(path, secret) {
450
+ const baseUrl = process.env.NEXT_PUBLIC_URL;
451
+ if (!baseUrl) {
452
+ getCacheLogger().warn("revalidatePath skipped: NEXT_PUBLIC_URL is not configured", { path });
453
+ return { revalidated: false, error: "NEXT_PUBLIC_URL is not configured" };
454
+ }
455
+ try {
456
+ const url = new URL("/api/revalidate", baseUrl);
457
+ const headers = { "Content-Type": "application/json" };
458
+ if (secret) {
459
+ headers["x-revalidate-secret"] = secret;
460
+ }
461
+ const response = await fetch(url.toString(), {
462
+ method: "POST",
463
+ headers,
464
+ body: JSON.stringify({ path })
465
+ });
466
+ const data = await response.json();
467
+ return {
468
+ revalidated: response.ok,
469
+ error: data.error
470
+ };
471
+ } catch (error) {
472
+ return {
473
+ revalidated: false,
474
+ error: error instanceof Error ? error.message : "Unknown error"
475
+ };
476
+ }
477
+ }
478
+ async function revalidatePaths(paths, secret) {
479
+ const results = await Promise.allSettled(paths.map((path) => revalidatePath(path, secret)));
480
+ let revalidated = 0;
481
+ let failed = 0;
482
+ const errors = [];
483
+ for (let i = 0; i < results.length; i++) {
484
+ const result = results[i];
485
+ const path = paths[i];
486
+ if (!(result && path)) {
487
+ continue;
488
+ }
489
+ if (result.status === "fulfilled" && result.value.revalidated) {
490
+ revalidated++;
491
+ } else {
492
+ failed++;
493
+ const error = result.status === "fulfilled" ? result.value.error || "Unknown error" : String(result.reason) || "Unknown error";
494
+ errors.push({ path, error });
495
+ }
496
+ }
497
+ return { revalidated, failed, errors };
498
+ }
499
+ async function revalidateTags(tags, secret) {
500
+ const results = await Promise.allSettled(tags.map((tag) => revalidateTag(tag, secret)));
501
+ let revalidated = 0;
502
+ let failed = 0;
503
+ const errors = [];
504
+ for (let i = 0; i < results.length; i++) {
505
+ const result = results[i];
506
+ const tag = tags[i];
507
+ if (!(result && tag)) {
508
+ continue;
509
+ }
510
+ if (result.status === "fulfilled" && result.value.revalidated) {
511
+ revalidated++;
512
+ } else {
513
+ failed++;
514
+ const error = result.status === "fulfilled" ? result.value.error || "Unknown error" : String(result.reason) || "Unknown error";
515
+ errors.push({ tag, error });
516
+ }
517
+ }
518
+ return { revalidated, failed, errors };
519
+ }
520
+ function createEdgeCachedFetch(config = {}) {
521
+ return async (url, options) => {
522
+ const fetchOptions = {
523
+ ...options,
524
+ ...config,
525
+ next: {
526
+ ...options?.next,
527
+ ...config.next
528
+ }
529
+ };
530
+ const response = await fetch(url, fetchOptions);
531
+ if (!response.ok) {
532
+ throw new Error(`Fetch failed: ${response.statusText}`);
533
+ }
534
+ return response.json();
535
+ };
536
+ }
537
+ function createCachedFunction(fn, options = {}) {
538
+ if (options.revalidate === false) {
539
+ return fn;
540
+ }
541
+ const ttlMs = (options.revalidate ?? 60) * 1e3;
542
+ const cache = /* @__PURE__ */ new Map();
543
+ return async (...args) => {
544
+ const key = JSON.stringify(args);
545
+ const now = Date.now();
546
+ const cached = cache.get(key);
547
+ if (cached && now < cached.expiresAt) {
548
+ return cached.value;
549
+ }
550
+ const value = await fn(...args);
551
+ cache.set(key, { value, expiresAt: now + ttlMs });
552
+ return value;
553
+ };
554
+ }
555
+ var EdgeRateLimiter = class {
556
+ constructor(config) {
557
+ this.config = config;
558
+ }
559
+ cache = /* @__PURE__ */ new Map();
560
+ /**
561
+ * Check rate limit
562
+ */
563
+ check(request) {
564
+ const key = this.config.key ? this.config.key(request) : request.headers.get("x-forwarded-for") || "unknown";
565
+ const now = Date.now();
566
+ let entry = this.cache.get(key);
567
+ if (!entry || now > entry.resetTime) {
568
+ entry = {
569
+ count: 0,
570
+ resetTime: now + this.config.window
571
+ };
572
+ this.cache.set(key, entry);
573
+ }
574
+ entry.count++;
575
+ const allowed = entry.count <= this.config.limit;
576
+ const remaining = Math.max(0, this.config.limit - entry.count);
577
+ return {
578
+ allowed,
579
+ limit: this.config.limit,
580
+ remaining,
581
+ reset: entry.resetTime
582
+ };
583
+ }
584
+ /**
585
+ * Clean up expired entries
586
+ */
587
+ cleanup() {
588
+ const now = Date.now();
589
+ for (const [key, entry] of this.cache.entries()) {
590
+ if (now > entry.resetTime) {
591
+ this.cache.delete(key);
592
+ }
593
+ }
594
+ }
595
+ };
596
+ function getGeoLocation(request) {
597
+ const country = request.headers.get("x-vercel-ip-country");
598
+ const region = request.headers.get("x-vercel-ip-country-region");
599
+ const city = request.headers.get("x-vercel-ip-city");
600
+ const latitude = request.headers.get("x-vercel-ip-latitude");
601
+ const longitude = request.headers.get("x-vercel-ip-longitude");
602
+ if (!country) {
603
+ const cfCountry = request.headers.get("cf-ipcountry");
604
+ if (cfCountry) {
605
+ return {
606
+ country: cfCountry
607
+ };
608
+ }
609
+ return null;
610
+ }
611
+ return {
612
+ country: country || void 0,
613
+ region: region || void 0,
614
+ city: city ? decodeURIComponent(city) : void 0,
615
+ latitude: latitude ? parseFloat(latitude) : void 0,
616
+ longitude: longitude ? parseFloat(longitude) : void 0
617
+ };
618
+ }
619
+ function getABTestVariant(request, testName, variants) {
620
+ const cookieName = `ab-test-${testName}`;
621
+ const cookieVariant = request.cookies.get(cookieName)?.value;
622
+ if (cookieVariant && variants.includes(cookieVariant)) {
623
+ return cookieVariant;
624
+ }
625
+ const ip = request.headers.get("x-forwarded-for") || "unknown";
626
+ const hash = simpleHash(ip + testName);
627
+ const variantIndex = hash % variants.length;
628
+ const variant = variants[variantIndex];
629
+ if (!variant) {
630
+ throw new Error("No variant found for A/B test");
631
+ }
632
+ return variant;
633
+ }
634
+ function simpleHash(str) {
635
+ let hash = 0;
636
+ for (let i = 0; i < str.length; i++) {
637
+ const char = str.charCodeAt(i);
638
+ hash = (hash << 5) - hash + char;
639
+ hash = hash & hash;
640
+ }
641
+ return Math.abs(hash);
642
+ }
643
+ function getPersonalizationConfig(request) {
644
+ const userAgent = request.headers.get("user-agent") || "";
645
+ const device = getDeviceType(userAgent);
646
+ const location = getGeoLocation(request);
647
+ return {
648
+ userId: request.cookies.get("user-id")?.value,
649
+ location: location || void 0,
650
+ device
651
+ };
652
+ }
653
+ function getDeviceType(userAgent) {
654
+ if (/mobile/i.test(userAgent) && !/tablet|ipad/i.test(userAgent)) {
655
+ return "mobile";
656
+ }
657
+ if (/tablet|ipad/i.test(userAgent)) {
658
+ return "tablet";
659
+ }
660
+ return "desktop";
661
+ }
662
+ function setEdgeCacheHeaders(response, config) {
663
+ const cacheControl = [];
664
+ if (config.maxAge !== void 0) {
665
+ cacheControl.push(`max-age=${config.maxAge}`);
666
+ }
667
+ if (config.sMaxAge !== void 0) {
668
+ cacheControl.push(`s-maxage=${config.sMaxAge}`);
669
+ }
670
+ if (config.staleWhileRevalidate !== void 0) {
671
+ cacheControl.push(`stale-while-revalidate=${config.staleWhileRevalidate}`);
672
+ }
673
+ if (cacheControl.length > 0) {
674
+ response.headers.set("Cache-Control", cacheControl.join(", "));
675
+ }
676
+ if (config.tags && config.tags.length > 0) {
677
+ response.headers.set("Cache-Tag", config.tags.join(","));
678
+ }
679
+ return response;
680
+ }
681
+ function addPreloadLinks(response, resources) {
682
+ const links = resources.map((resource) => {
683
+ const attrs = [`<${resource.href}>`, `rel="preload"`, `as="${resource.as}"`];
684
+ if (resource.type) {
685
+ attrs.push(`type="${resource.type}"`);
686
+ }
687
+ if (resource.crossorigin) {
688
+ attrs.push("crossorigin");
689
+ }
690
+ return attrs.join("; ");
691
+ });
692
+ if (links.length > 0) {
693
+ response.headers.set("Link", links.join(", "));
694
+ }
695
+ return response;
696
+ }
697
+ async function warmISRCache(paths, baseURL = process.env.NEXT_PUBLIC_URL || "http://localhost:3000") {
698
+ const results = await Promise.allSettled(
699
+ paths.map(async (path) => {
700
+ const url = new URL(path, baseURL);
701
+ const response = await fetch(url.toString());
702
+ if (!response.ok) {
703
+ throw new Error(`${response.status} ${response.statusText}`);
704
+ }
705
+ return true;
706
+ })
707
+ );
708
+ let warmed = 0;
709
+ let failed = 0;
710
+ const errors = [];
711
+ for (let i = 0; i < results.length; i++) {
712
+ const result = results[i];
713
+ const path = paths[i];
714
+ if (!(result && path)) {
715
+ continue;
716
+ }
717
+ if (result.status === "fulfilled") {
718
+ warmed++;
719
+ } else {
720
+ failed++;
721
+ errors.push({
722
+ path,
723
+ error: result.reason instanceof Error ? result.reason.message : String(result.reason) || "Unknown error"
724
+ });
725
+ }
726
+ }
727
+ return { warmed, failed, errors };
728
+ }
729
+ export {
730
+ CDN_CACHE_PRESETS,
731
+ DEFAULT_CDN_CONFIG,
732
+ EdgeRateLimiter,
733
+ ISR_PRESETS,
734
+ addPreloadLinks,
735
+ configureCacheLogger,
736
+ createCachedFunction,
737
+ createEdgeCachedFetch,
738
+ generateCacheControl,
739
+ generateCacheTags,
740
+ generateCloudflareConfig,
741
+ generateStaticParams,
742
+ generateVercelCacheConfig,
743
+ getABTestVariant,
744
+ getCacheLogger,
745
+ getCacheTTL,
746
+ getGeoLocation,
747
+ getPersonalizationConfig,
748
+ purgeAllCache,
749
+ purgeCDNCache,
750
+ purgeCacheByTag,
751
+ revalidatePath,
752
+ revalidatePaths,
753
+ revalidateTag,
754
+ revalidateTags,
755
+ setEdgeCacheHeaders,
756
+ shouldCacheResponse,
757
+ warmCDNCache,
758
+ warmISRCache
759
+ };
760
+ //# sourceMappingURL=index.js.map