@rangojs/router 0.0.0-experimental.119 → 0.0.0-experimental.120

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.
@@ -2130,7 +2130,7 @@ import { resolve } from "node:path";
2130
2130
  // package.json
2131
2131
  var package_default = {
2132
2132
  name: "@rangojs/router",
2133
- version: "0.0.0-experimental.119",
2133
+ version: "0.0.0-experimental.120",
2134
2134
  description: "Django-inspired RSC router with composable URL patterns",
2135
2135
  keywords: [
2136
2136
  "react",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rangojs/router",
3
- "version": "0.0.0-experimental.119",
3
+ "version": "0.0.0-experimental.120",
4
4
  "description": "Django-inspired RSC router with composable URL patterns",
5
5
  "keywords": [
6
6
  "react",
@@ -72,6 +72,15 @@ const CACHE_ORIG_CC_HEADER = "x-edge-cache-orig-cc";
72
72
  */
73
73
  export const MAX_REVALIDATION_INTERVAL = 30;
74
74
 
75
+ /**
76
+ * Maximum time (ms) to wait for an L1 edge cache (CF Cache API) read before
77
+ * giving up and treating it as a miss. The Cache API is normally sub-millisecond
78
+ * per-colo, so a slow `match` signals a degraded colo; we don't want it adding
79
+ * latency to the request. On timeout the lookup is abandoned, a warning is
80
+ * logged, and the read falls through to its normal miss path (L2/KV or render).
81
+ */
82
+ export const EDGE_LOOKUP_TIMEOUT_MS = 10;
83
+
75
84
  // ============================================================================
76
85
  // Types
77
86
  // ============================================================================
@@ -341,6 +350,50 @@ export class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<TEnv> {
341
350
  return caches.default;
342
351
  }
343
352
 
353
+ /**
354
+ * Read from the L1 edge cache with a latency budget. A `match` that takes
355
+ * longer than EDGE_LOOKUP_TIMEOUT_MS is abandoned and reported as a miss
356
+ * (undefined) so a degraded colo cannot stall the request; callers then fall
357
+ * through to their normal miss path (L2/KV or render). The slow `match` is
358
+ * left to settle in the background (errors swallowed) rather than aborted,
359
+ * since the Cache API exposes no cancellation.
360
+ * @internal
361
+ */
362
+ private async matchWithTimeout(
363
+ cache: Cache,
364
+ request: Request,
365
+ ): Promise<Response | undefined> {
366
+ let timer: ReturnType<typeof setTimeout> | undefined;
367
+ const timeout = new Promise<{ timedOut: true }>((resolve) => {
368
+ timer = setTimeout(
369
+ () => resolve({ timedOut: true }),
370
+ EDGE_LOOKUP_TIMEOUT_MS,
371
+ );
372
+ });
373
+ try {
374
+ const matchPromise = cache.match(request);
375
+ // The losing branch keeps running; ensure a late rejection can't surface
376
+ // as an unhandled rejection once we've stopped awaiting it.
377
+ matchPromise.catch(() => {});
378
+ const result = await Promise.race([
379
+ matchPromise.then((response) => ({
380
+ timedOut: false as const,
381
+ response,
382
+ })),
383
+ timeout,
384
+ ]);
385
+ if (result.timedOut) {
386
+ console.warn(
387
+ `[CFCacheStore] edge cache lookup exceeded ${EDGE_LOOKUP_TIMEOUT_MS}ms; treating as miss`,
388
+ );
389
+ return undefined;
390
+ }
391
+ return result.response;
392
+ } finally {
393
+ if (timer) clearTimeout(timer);
394
+ }
395
+ }
396
+
344
397
  // ============================================================================
345
398
  // Segment Cache Methods
346
399
  // ============================================================================
@@ -360,7 +413,7 @@ export class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<TEnv> {
360
413
  try {
361
414
  const cache = await this.getCache();
362
415
  const request = this.keyToRequest(key);
363
- const response = await cache.match(request);
416
+ const response = await this.matchWithTimeout(cache, request);
364
417
 
365
418
  if (!response) {
366
419
  return this.kvGetSegment(key);
@@ -494,7 +547,7 @@ export class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<TEnv> {
494
547
  try {
495
548
  const cache = await this.getCache();
496
549
  const request = this.keyToRequest(`doc:${key}`);
497
- const response = await cache.match(request);
550
+ const response = await this.matchWithTimeout(cache, request);
498
551
 
499
552
  if (!response || response.status !== 200) {
500
553
  return this.kvGetResponse(key);
@@ -640,7 +693,7 @@ export class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<TEnv> {
640
693
  try {
641
694
  const cache = await this.getCache();
642
695
  const request = this.keyToRequest(`fn:${key}`);
643
- const response = await cache.match(request);
696
+ const response = await this.matchWithTimeout(cache, request);
644
697
 
645
698
  if (!response) return this.kvGetItem(key);
646
699