layercache 1.2.1 → 1.2.3

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/edge.cjs CHANGED
@@ -29,7 +29,30 @@ module.exports = __toCommonJS(edge_exports);
29
29
 
30
30
  // src/internal/StoredValue.ts
31
31
  function isStoredValueEnvelope(value) {
32
- return typeof value === "object" && value !== null && "__layercache" in value && value.__layercache === 1 && "kind" in value;
32
+ if (typeof value !== "object" || value === null) {
33
+ return false;
34
+ }
35
+ const v = value;
36
+ if (v.__layercache !== 1) {
37
+ return false;
38
+ }
39
+ if (v.kind !== "value" && v.kind !== "empty") {
40
+ return false;
41
+ }
42
+ if (v.freshUntil !== null && typeof v.freshUntil !== "number") {
43
+ return false;
44
+ }
45
+ if (v.staleUntil !== null && typeof v.staleUntil !== "number") {
46
+ return false;
47
+ }
48
+ if (v.errorUntil !== null && typeof v.errorUntil !== "number") {
49
+ return false;
50
+ }
51
+ const maxTimestamp = Date.now() + 10 * 365 * 24 * 60 * 60 * 1e3;
52
+ if (typeof v.freshUntil === "number" && v.freshUntil > maxTimestamp) {
53
+ return false;
54
+ }
55
+ return true;
33
56
  }
34
57
  function unwrapStoredValue(stored) {
35
58
  if (!isStoredValueEnvelope(stored)) {
@@ -87,16 +110,10 @@ var MemoryLayer = class {
87
110
  return entry.value;
88
111
  }
89
112
  async getMany(keys) {
90
- const values = [];
91
- for (const key of keys) {
92
- values.push(await this.getEntry(key));
93
- }
94
- return values;
113
+ return Promise.all(keys.map((key) => this.getEntry(key)));
95
114
  }
96
115
  async setMany(entries) {
97
- for (const entry of entries) {
98
- await this.set(entry.key, entry.value, entry.ttl);
99
- }
116
+ await Promise.all(entries.map((entry) => this.set(entry.key, entry.value, entry.ttl)));
100
117
  }
101
118
  async set(key, value, ttl = this.defaultTtl) {
102
119
  this.entries.delete(key);
@@ -283,15 +300,17 @@ var TagIndex = class {
283
300
  keyToTags = /* @__PURE__ */ new Map();
284
301
  knownKeys = /* @__PURE__ */ new Set();
285
302
  maxKnownKeys;
303
+ nextNodeId = 1;
304
+ root = this.createTrieNode();
286
305
  constructor(options = {}) {
287
- this.maxKnownKeys = options.maxKnownKeys;
306
+ this.maxKnownKeys = options.maxKnownKeys ?? 1e5;
288
307
  }
289
308
  async touch(key) {
290
- this.knownKeys.add(key);
309
+ this.insertKnownKey(key);
291
310
  this.pruneKnownKeysIfNeeded();
292
311
  }
293
312
  async track(key, tags) {
294
- this.knownKeys.add(key);
313
+ this.insertKnownKey(key);
295
314
  this.pruneKnownKeysIfNeeded();
296
315
  if (tags.length === 0) {
297
316
  return;
@@ -317,18 +336,104 @@ var TagIndex = class {
317
336
  return [...this.tagToKeys.get(tag) ?? /* @__PURE__ */ new Set()];
318
337
  }
319
338
  async keysForPrefix(prefix) {
320
- return [...this.knownKeys].filter((key) => key.startsWith(prefix));
339
+ const node = this.findNode(prefix);
340
+ if (!node) {
341
+ return [];
342
+ }
343
+ const matches = [];
344
+ this.collectFromNode(node, prefix, matches);
345
+ return matches;
321
346
  }
322
347
  async tagsForKey(key) {
323
348
  return [...this.keyToTags.get(key) ?? /* @__PURE__ */ new Set()];
324
349
  }
325
350
  async matchPattern(pattern) {
326
- return [...this.knownKeys].filter((key) => PatternMatcher.matches(pattern, key));
351
+ const matches = /* @__PURE__ */ new Set();
352
+ this.collectPatternMatches(this.root, "", pattern, 0, matches, /* @__PURE__ */ new Set());
353
+ return [...matches];
327
354
  }
328
355
  async clear() {
329
356
  this.tagToKeys.clear();
330
357
  this.keyToTags.clear();
331
358
  this.knownKeys.clear();
359
+ this.root.children.clear();
360
+ this.root.terminal = false;
361
+ this.nextNodeId = this.root.id + 1;
362
+ }
363
+ createTrieNode() {
364
+ return {
365
+ id: this.nextNodeId++,
366
+ terminal: false,
367
+ children: /* @__PURE__ */ new Map()
368
+ };
369
+ }
370
+ insertKnownKey(key) {
371
+ if (this.knownKeys.has(key)) {
372
+ return;
373
+ }
374
+ this.knownKeys.add(key);
375
+ let node = this.root;
376
+ for (const character of key) {
377
+ let child = node.children.get(character);
378
+ if (!child) {
379
+ child = this.createTrieNode();
380
+ node.children.set(character, child);
381
+ }
382
+ node = child;
383
+ }
384
+ node.terminal = true;
385
+ }
386
+ findNode(prefix) {
387
+ let node = this.root;
388
+ for (const character of prefix) {
389
+ node = node.children.get(character);
390
+ if (!node) {
391
+ return void 0;
392
+ }
393
+ }
394
+ return node;
395
+ }
396
+ collectFromNode(node, prefix, matches) {
397
+ if (node.terminal) {
398
+ matches.push(prefix);
399
+ }
400
+ for (const [character, child] of node.children) {
401
+ this.collectFromNode(child, `${prefix}${character}`, matches);
402
+ }
403
+ }
404
+ collectPatternMatches(node, prefix, pattern, patternIndex, matches, visited) {
405
+ const stateKey = `${node.id}:${patternIndex}`;
406
+ if (visited.has(stateKey)) {
407
+ return;
408
+ }
409
+ visited.add(stateKey);
410
+ if (patternIndex === pattern.length) {
411
+ if (node.terminal) {
412
+ matches.add(prefix);
413
+ }
414
+ return;
415
+ }
416
+ const patternChar = pattern[patternIndex];
417
+ if (patternChar === void 0) {
418
+ return;
419
+ }
420
+ if (patternChar === "*") {
421
+ this.collectPatternMatches(node, prefix, pattern, patternIndex + 1, matches, visited);
422
+ for (const [character, child2] of node.children) {
423
+ this.collectPatternMatches(child2, `${prefix}${character}`, pattern, patternIndex, matches, visited);
424
+ }
425
+ return;
426
+ }
427
+ if (patternChar === "?") {
428
+ for (const [character, child2] of node.children) {
429
+ this.collectPatternMatches(child2, `${prefix}${character}`, pattern, patternIndex + 1, matches, visited);
430
+ }
431
+ return;
432
+ }
433
+ const child = node.children.get(patternChar);
434
+ if (child) {
435
+ this.collectPatternMatches(child, `${prefix}${patternChar}`, pattern, patternIndex + 1, matches, visited);
436
+ }
332
437
  }
333
438
  pruneKnownKeysIfNeeded() {
334
439
  if (this.maxKnownKeys === void 0 || this.knownKeys.size <= this.maxKnownKeys) {
@@ -345,7 +450,7 @@ var TagIndex = class {
345
450
  }
346
451
  }
347
452
  removeKey(key) {
348
- this.knownKeys.delete(key);
453
+ this.removeKnownKey(key);
349
454
  const tags = this.keyToTags.get(key);
350
455
  if (!tags) {
351
456
  return;
@@ -362,6 +467,34 @@ var TagIndex = class {
362
467
  }
363
468
  this.keyToTags.delete(key);
364
469
  }
470
+ removeKnownKey(key) {
471
+ if (!this.knownKeys.delete(key)) {
472
+ return;
473
+ }
474
+ const path = [];
475
+ let node = this.root;
476
+ for (const character of key) {
477
+ const child = node.children.get(character);
478
+ if (!child) {
479
+ return;
480
+ }
481
+ path.push([node, character]);
482
+ node = child;
483
+ }
484
+ node.terminal = false;
485
+ for (let index = path.length - 1; index >= 0; index -= 1) {
486
+ const entry = path[index];
487
+ if (!entry) {
488
+ continue;
489
+ }
490
+ const [parent, character] = entry;
491
+ const child = parent.children.get(character);
492
+ if (!child || child.terminal || child.children.size > 0) {
493
+ break;
494
+ }
495
+ parent.children.delete(character);
496
+ }
497
+ }
365
498
  };
366
499
 
367
500
  // src/integrations/hono.ts
@@ -373,7 +506,8 @@ function createHonoCacheMiddleware(cache, options = {}) {
373
506
  await next();
374
507
  return;
375
508
  }
376
- const key = options.keyResolver ? options.keyResolver(context.req) : `${method}:${context.req.path ?? context.req.url ?? "/"}`;
509
+ const rawPath = context.req.path ?? context.req.url ?? "/";
510
+ const key = options.keyResolver ? options.keyResolver(context.req) : `${method}:${normalizeUrl(rawPath)}`;
377
511
  const cached = await cache.get(key, void 0, options);
378
512
  if (cached !== null) {
379
513
  context.header?.("x-cache", "HIT");
@@ -384,12 +518,26 @@ function createHonoCacheMiddleware(cache, options = {}) {
384
518
  const originalJson = context.json.bind(context);
385
519
  context.json = (body, status) => {
386
520
  context.header?.("x-cache", "MISS");
387
- void cache.set(key, body, options);
521
+ cache.set(key, body, options).catch((err) => {
522
+ cache.emit("error", {
523
+ operation: "set",
524
+ error: err instanceof Error ? err.message : String(err)
525
+ });
526
+ });
388
527
  return originalJson(body, status);
389
528
  };
390
529
  await next();
391
530
  };
392
531
  }
532
+ function normalizeUrl(url) {
533
+ try {
534
+ const parsed = new URL(url, "http://localhost");
535
+ parsed.searchParams.sort();
536
+ return decodeURIComponent(parsed.pathname) + parsed.search;
537
+ } catch {
538
+ return url;
539
+ }
540
+ }
393
541
  // Annotate the CommonJS export names for ESM import in node:
394
542
  0 && (module.exports = {
395
543
  MemoryLayer,
package/dist/edge.d.cts CHANGED
@@ -1,2 +1,2 @@
1
- export { e as CacheGetOptions, f as CacheLayer, h as CacheLayerSetManyEntry, t as CacheMetricsSnapshot, w as CacheRateLimitOptions, B as CacheTtlPolicy, D as CacheTtlPolicyContext, J as CacheWriteOptions, K as EvictionPolicy, M as MemoryLayer, N as MemoryLayerOptions, O as MemoryLayerSnapshotEntry, P as PatternMatcher, T as TagIndex, Q as createHonoCacheMiddleware } from './edge-C1sBhTfv.cjs';
1
+ export { e as CacheGetOptions, f as CacheLayer, h as CacheLayerSetManyEntry, t as CacheMetricsSnapshot, w as CacheRateLimitOptions, B as CacheTtlPolicy, D as CacheTtlPolicyContext, J as CacheWriteOptions, K as EvictionPolicy, M as MemoryLayer, N as MemoryLayerOptions, O as MemoryLayerSnapshotEntry, P as PatternMatcher, T as TagIndex, Q as createHonoCacheMiddleware } from './edge-B_rUqDy6.cjs';
2
2
  import 'node:events';
package/dist/edge.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { e as CacheGetOptions, f as CacheLayer, h as CacheLayerSetManyEntry, t as CacheMetricsSnapshot, w as CacheRateLimitOptions, B as CacheTtlPolicy, D as CacheTtlPolicyContext, J as CacheWriteOptions, K as EvictionPolicy, M as MemoryLayer, N as MemoryLayerOptions, O as MemoryLayerSnapshotEntry, P as PatternMatcher, T as TagIndex, Q as createHonoCacheMiddleware } from './edge-C1sBhTfv.js';
1
+ export { e as CacheGetOptions, f as CacheLayer, h as CacheLayerSetManyEntry, t as CacheMetricsSnapshot, w as CacheRateLimitOptions, B as CacheTtlPolicy, D as CacheTtlPolicyContext, J as CacheWriteOptions, K as EvictionPolicy, M as MemoryLayer, N as MemoryLayerOptions, O as MemoryLayerSnapshotEntry, P as PatternMatcher, T as TagIndex, Q as createHonoCacheMiddleware } from './edge-B_rUqDy6.js';
2
2
  import 'node:events';
package/dist/edge.js CHANGED
@@ -2,10 +2,10 @@ import {
2
2
  MemoryLayer,
3
3
  TagIndex,
4
4
  createHonoCacheMiddleware
5
- } from "./chunk-46UH7LNM.js";
5
+ } from "./chunk-KOYGHLVP.js";
6
6
  import {
7
7
  PatternMatcher
8
- } from "./chunk-ZMDB5KOK.js";
8
+ } from "./chunk-7V7XAB74.js";
9
9
  export {
10
10
  MemoryLayer,
11
11
  PatternMatcher,