@vercel/kv2 0.0.1

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.
Files changed (166) hide show
  1. package/README.md +87 -0
  2. package/SKILL.md +65 -0
  3. package/dist/blob-format.d.ts +35 -0
  4. package/dist/blob-format.d.ts.map +1 -0
  5. package/dist/blob-format.js +91 -0
  6. package/dist/blob-format.js.map +1 -0
  7. package/dist/blob-store.d.ts +11 -0
  8. package/dist/blob-store.d.ts.map +1 -0
  9. package/dist/blob-store.js +32 -0
  10. package/dist/blob-store.js.map +1 -0
  11. package/dist/cache.d.ts +33 -0
  12. package/dist/cache.d.ts.map +1 -0
  13. package/dist/cache.js +146 -0
  14. package/dist/cache.js.map +1 -0
  15. package/dist/cached-kv.d.ts +63 -0
  16. package/dist/cached-kv.d.ts.map +1 -0
  17. package/dist/cached-kv.js +891 -0
  18. package/dist/cached-kv.js.map +1 -0
  19. package/dist/cli.d.ts +3 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +342 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/create-kv.d.ts +86 -0
  24. package/dist/create-kv.d.ts.map +1 -0
  25. package/dist/create-kv.js +125 -0
  26. package/dist/create-kv.js.map +1 -0
  27. package/dist/disk-cache.d.ts.map +1 -0
  28. package/dist/disk-cache.js.map +1 -0
  29. package/dist/index.d.ts +16 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +13 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/indexed-kv.d.ts +44 -0
  34. package/dist/indexed-kv.d.ts.map +1 -0
  35. package/dist/indexed-kv.js +373 -0
  36. package/dist/indexed-kv.js.map +1 -0
  37. package/dist/manifest-log.d.ts +57 -0
  38. package/dist/manifest-log.d.ts.map +1 -0
  39. package/dist/manifest-log.js +128 -0
  40. package/dist/manifest-log.js.map +1 -0
  41. package/dist/memory-cache.d.ts +22 -0
  42. package/dist/memory-cache.d.ts.map +1 -0
  43. package/dist/memory-cache.js +90 -0
  44. package/dist/memory-cache.js.map +1 -0
  45. package/dist/proxy-cache.d.ts +40 -0
  46. package/dist/proxy-cache.d.ts.map +1 -0
  47. package/dist/proxy-cache.js +124 -0
  48. package/dist/proxy-cache.js.map +1 -0
  49. package/dist/readme.test.d.ts +9 -0
  50. package/dist/readme.test.d.ts.map +1 -0
  51. package/dist/readme.test.js +285 -0
  52. package/dist/readme.test.js.map +1 -0
  53. package/dist/schema/define-schema.d.ts +35 -0
  54. package/dist/schema/define-schema.d.ts.map +1 -0
  55. package/dist/schema/define-schema.js +70 -0
  56. package/dist/schema/define-schema.js.map +1 -0
  57. package/dist/schema/index.d.ts +4 -0
  58. package/dist/schema/index.d.ts.map +1 -0
  59. package/dist/schema/index.js +5 -0
  60. package/dist/schema/index.js.map +1 -0
  61. package/dist/schema/key-builders.d.ts +40 -0
  62. package/dist/schema/key-builders.d.ts.map +1 -0
  63. package/dist/schema/key-builders.js +124 -0
  64. package/dist/schema/key-builders.js.map +1 -0
  65. package/dist/schema/schema-kv.d.ts +48 -0
  66. package/dist/schema/schema-kv.d.ts.map +1 -0
  67. package/dist/schema/schema-kv.js +96 -0
  68. package/dist/schema/schema-kv.js.map +1 -0
  69. package/dist/schema/tree.d.ts +14 -0
  70. package/dist/schema/tree.d.ts.map +1 -0
  71. package/dist/schema/tree.js +135 -0
  72. package/dist/schema/tree.js.map +1 -0
  73. package/dist/schema/types.d.ts +135 -0
  74. package/dist/schema/types.d.ts.map +1 -0
  75. package/dist/schema/types.js +2 -0
  76. package/dist/schema/types.js.map +1 -0
  77. package/dist/testing/core-tests.d.ts +30 -0
  78. package/dist/testing/core-tests.d.ts.map +1 -0
  79. package/dist/testing/core-tests.js +383 -0
  80. package/dist/testing/core-tests.js.map +1 -0
  81. package/dist/testing/create-kv-test-setup.d.ts +21 -0
  82. package/dist/testing/create-kv-test-setup.d.ts.map +1 -0
  83. package/dist/testing/create-kv-test-setup.js +25 -0
  84. package/dist/testing/create-kv-test-setup.js.map +1 -0
  85. package/dist/testing/debug-manifest.d.ts +2 -0
  86. package/dist/testing/debug-manifest.d.ts.map +1 -0
  87. package/dist/testing/debug-manifest.js +14 -0
  88. package/dist/testing/debug-manifest.js.map +1 -0
  89. package/dist/testing/fake-blob-store.d.ts +23 -0
  90. package/dist/testing/fake-blob-store.d.ts.map +1 -0
  91. package/dist/testing/fake-blob-store.js +158 -0
  92. package/dist/testing/fake-blob-store.js.map +1 -0
  93. package/dist/testing/fake-cache.d.ts +54 -0
  94. package/dist/testing/fake-cache.d.ts.map +1 -0
  95. package/dist/testing/fake-cache.js +137 -0
  96. package/dist/testing/fake-cache.js.map +1 -0
  97. package/dist/testing/index.d.ts +34 -0
  98. package/dist/testing/index.d.ts.map +1 -0
  99. package/dist/testing/index.js +101 -0
  100. package/dist/testing/index.js.map +1 -0
  101. package/dist/testing/manifest-test-setup.d.ts +22 -0
  102. package/dist/testing/manifest-test-setup.d.ts.map +1 -0
  103. package/dist/testing/manifest-test-setup.js +43 -0
  104. package/dist/testing/manifest-test-setup.js.map +1 -0
  105. package/dist/testing/perf-test.d.ts +13 -0
  106. package/dist/testing/perf-test.d.ts.map +1 -0
  107. package/dist/testing/perf-test.js +101 -0
  108. package/dist/testing/perf-test.js.map +1 -0
  109. package/dist/testing/run-tests.d.ts +2 -0
  110. package/dist/testing/run-tests.d.ts.map +1 -0
  111. package/dist/testing/run-tests.js +141 -0
  112. package/dist/testing/run-tests.js.map +1 -0
  113. package/dist/testing/setup.d.ts +2 -0
  114. package/dist/testing/setup.d.ts.map +1 -0
  115. package/dist/testing/setup.js +3 -0
  116. package/dist/testing/setup.js.map +1 -0
  117. package/dist/testing/test-index.d.ts +28 -0
  118. package/dist/testing/test-index.d.ts.map +1 -0
  119. package/dist/testing/test-index.js +35 -0
  120. package/dist/testing/test-index.js.map +1 -0
  121. package/dist/testing/test-setup.d.ts +32 -0
  122. package/dist/testing/test-setup.d.ts.map +1 -0
  123. package/dist/testing/test-setup.js +72 -0
  124. package/dist/testing/test-setup.js.map +1 -0
  125. package/dist/testing/upstream-kv-test-setup.d.ts +30 -0
  126. package/dist/testing/upstream-kv-test-setup.d.ts.map +1 -0
  127. package/dist/testing/upstream-kv-test-setup.js +66 -0
  128. package/dist/testing/upstream-kv-test-setup.js.map +1 -0
  129. package/dist/testing/vitest-compat.d.ts +92 -0
  130. package/dist/testing/vitest-compat.d.ts.map +1 -0
  131. package/dist/testing/vitest-compat.js +601 -0
  132. package/dist/testing/vitest-compat.js.map +1 -0
  133. package/dist/tracing.d.ts +71 -0
  134. package/dist/tracing.d.ts.map +1 -0
  135. package/dist/tracing.js +232 -0
  136. package/dist/tracing.js.map +1 -0
  137. package/dist/typed-kv.d.ts +120 -0
  138. package/dist/typed-kv.d.ts.map +1 -0
  139. package/dist/typed-kv.js +565 -0
  140. package/dist/typed-kv.js.map +1 -0
  141. package/dist/typed-upstream-kv.d.ts +17 -0
  142. package/dist/typed-upstream-kv.d.ts.map +1 -0
  143. package/dist/typed-upstream-kv.js +38 -0
  144. package/dist/typed-upstream-kv.js.map +1 -0
  145. package/dist/types.d.ts +199 -0
  146. package/dist/types.d.ts.map +1 -0
  147. package/dist/types.js +23 -0
  148. package/dist/types.js.map +1 -0
  149. package/dist/upstream-kv.d.ts +84 -0
  150. package/dist/upstream-kv.d.ts.map +1 -0
  151. package/dist/upstream-kv.js +375 -0
  152. package/dist/upstream-kv.js.map +1 -0
  153. package/docs/api-reference.md +222 -0
  154. package/docs/caching.md +60 -0
  155. package/docs/cli.md +123 -0
  156. package/docs/copy-on-write-branches.md +98 -0
  157. package/docs/getting-started.md +61 -0
  158. package/docs/indexes.md +122 -0
  159. package/docs/iterating-and-pagination.md +93 -0
  160. package/docs/metadata.md +82 -0
  161. package/docs/optimistic-locking.md +72 -0
  162. package/docs/schema-and-trees.md +222 -0
  163. package/docs/streaming.md +61 -0
  164. package/docs/testing-and-tracing.md +141 -0
  165. package/docs/typed-stores.md +68 -0
  166. package/package.json +63 -0
@@ -0,0 +1,128 @@
1
+ import { KV2 } from "./cached-kv.js";
2
+ const MANIFEST_CACHE_KEY = "__manifest__";
3
+ /**
4
+ * Manifest for tracking key sources (local vs upstream vs tombstone).
5
+ *
6
+ * Individual entries stored in blob for persistence.
7
+ * Aggregated manifest cached as single entry for fast cross-instance reads.
8
+ */
9
+ export class ManifestLog {
10
+ kv;
11
+ cache;
12
+ cacheKey;
13
+ constructor(blobStore, manifestPrefix, cache) {
14
+ this.kv = new KV2({
15
+ prefix: manifestPrefix,
16
+ blobStore,
17
+ // Pass same cache to inner KV for test isolation
18
+ // (avoids falling back to global Vercel runtime cache singleton)
19
+ cache,
20
+ });
21
+ this.cache = cache;
22
+ this.cacheKey = `manifest:${manifestPrefix}`;
23
+ }
24
+ /**
25
+ * Get the source for a specific key.
26
+ * Returns null if key is not in manifest (unknown).
27
+ */
28
+ async getKeySource(key) {
29
+ const manifest = await this.loadManifest();
30
+ return manifest.get(key) ?? null;
31
+ }
32
+ /**
33
+ * Record a key as local or upstream.
34
+ */
35
+ async recordAdd(key, source) {
36
+ await this.kv.set(key, { source });
37
+ await this.invalidateCache();
38
+ }
39
+ /**
40
+ * Record a key deletion (tombstone).
41
+ */
42
+ async recordDelete(key) {
43
+ await this.kv.set(key, { source: "tombstone" });
44
+ await this.invalidateCache();
45
+ }
46
+ /**
47
+ * Delete a manifest entry (for cleanup).
48
+ */
49
+ async remove(key) {
50
+ await this.kv.delete(key);
51
+ await this.invalidateCache();
52
+ }
53
+ /**
54
+ * Delete all manifest entries.
55
+ */
56
+ async destroy() {
57
+ for await (const key of this.kv.keys()) {
58
+ await this.kv.delete(key);
59
+ }
60
+ await this.invalidateCache();
61
+ }
62
+ /**
63
+ * Get all manifest entries.
64
+ */
65
+ async getAll() {
66
+ return this.loadManifest();
67
+ }
68
+ /**
69
+ * Get manifest state with keys map.
70
+ */
71
+ async getManifest() {
72
+ return { keys: await this.loadManifest() };
73
+ }
74
+ /**
75
+ * Load manifest from cache or blob.
76
+ * Caches aggregated result for fast repeated reads.
77
+ */
78
+ async loadManifest() {
79
+ // Try cache first
80
+ if (this.cache) {
81
+ try {
82
+ const cached = (await this.cache.get(this.cacheKey));
83
+ if (cached?.entries) {
84
+ return new Map(cached.entries);
85
+ }
86
+ }
87
+ catch {
88
+ // Cache miss or error, fall through to blob
89
+ }
90
+ }
91
+ // Load from blob
92
+ const entries = new Map();
93
+ for await (const key of this.kv.keys()) {
94
+ const result = await this.kv.get(key);
95
+ if (result.exists) {
96
+ entries.set(key, await result.value);
97
+ }
98
+ }
99
+ // Cache the aggregated result
100
+ if (this.cache) {
101
+ try {
102
+ const toCache = {
103
+ entries: Array.from(entries.entries()),
104
+ };
105
+ await this.cache.set(this.cacheKey, toCache, { ttl: 3600 });
106
+ }
107
+ catch {
108
+ // Cache write failed, continue without caching
109
+ }
110
+ }
111
+ return entries;
112
+ }
113
+ /**
114
+ * Invalidate the cached manifest.
115
+ */
116
+ async invalidateCache() {
117
+ if (this.cache) {
118
+ try {
119
+ // Use expireTag if available, otherwise set to empty
120
+ await this.cache.set(this.cacheKey, null, { ttl: 0 });
121
+ }
122
+ catch {
123
+ // Ignore cache invalidation errors
124
+ }
125
+ }
126
+ }
127
+ }
128
+ //# sourceMappingURL=manifest-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest-log.js","sourceRoot":"","sources":["../src/manifest-log.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * In-memory cache for local development.
3
+ * State is stored in globalThis to persist across HMR reloads.
4
+ */
5
+ import type { CacheLike } from "./types.js";
6
+ export declare class MemoryCache implements CacheLike {
7
+ private state;
8
+ constructor();
9
+ get(key: string): Promise<unknown>;
10
+ set(key: string, value: unknown, options?: {
11
+ tags?: string[];
12
+ ttl?: number;
13
+ }): Promise<void>;
14
+ expireTag(tag: string): Promise<void>;
15
+ }
16
+ export declare function getMemoryCache(): MemoryCache;
17
+ /**
18
+ * Check if memory cache should be used.
19
+ * Returns true when running locally (not on Vercel) and not in integration test mode.
20
+ */
21
+ export declare function shouldUseMemoryCache(): boolean;
22
+ //# sourceMappingURL=memory-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-cache.d.ts","sourceRoot":"","sources":["../src/memory-cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA4B5C,qBAAa,WAAY,YAAW,SAAS;IAC5C,OAAO,CAAC,KAAK,CAAmB;;IAU1B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAelC,GAAG,CACR,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GACzC,OAAO,CAAC,IAAI,CAAC;IAqBV,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAS3C;AAKD,wBAAgB,cAAc,IAAI,WAAW,CAM5C;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAW9C"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * In-memory cache for local development.
3
+ * State is stored in globalThis to persist across HMR reloads.
4
+ */
5
+ const globalKey = Symbol.for("kv-memory-cache");
6
+ function getState() {
7
+ const g = globalThis;
8
+ if (!g[globalKey]) {
9
+ g[globalKey] = {
10
+ data: new Map(),
11
+ tags: new Map(),
12
+ };
13
+ }
14
+ return g[globalKey];
15
+ }
16
+ let loggedUsage = false;
17
+ export class MemoryCache {
18
+ state;
19
+ constructor() {
20
+ this.state = getState();
21
+ if (!loggedUsage) {
22
+ console.log("[MemoryCache] Using in-memory cache for local development");
23
+ loggedUsage = true;
24
+ }
25
+ }
26
+ async get(key) {
27
+ const entry = this.state.data.get(key);
28
+ if (!entry) {
29
+ return null;
30
+ }
31
+ // Check expiration
32
+ if (Date.now() > entry.expiresAt) {
33
+ this.state.data.delete(key);
34
+ return null;
35
+ }
36
+ return entry.value;
37
+ }
38
+ async set(key, value, options) {
39
+ const tags = options?.tags ?? [];
40
+ const ttl = options?.ttl ?? 3600;
41
+ const entry = {
42
+ value,
43
+ tags,
44
+ expiresAt: Date.now() + ttl * 1000,
45
+ };
46
+ this.state.data.set(key, entry);
47
+ // Track tags
48
+ for (const tag of tags) {
49
+ if (!this.state.tags.has(tag)) {
50
+ this.state.tags.set(tag, new Set());
51
+ }
52
+ this.state.tags.get(tag).add(key);
53
+ }
54
+ }
55
+ async expireTag(tag) {
56
+ const keys = this.state.tags.get(tag);
57
+ if (keys) {
58
+ for (const key of keys) {
59
+ this.state.data.delete(key);
60
+ }
61
+ this.state.tags.delete(tag);
62
+ }
63
+ }
64
+ }
65
+ // Singleton instance (also stored in globalThis)
66
+ const instanceKey = Symbol.for("kv-memory-cache-instance");
67
+ export function getMemoryCache() {
68
+ const g = globalThis;
69
+ if (!g[instanceKey]) {
70
+ g[instanceKey] = new MemoryCache();
71
+ }
72
+ return g[instanceKey];
73
+ }
74
+ /**
75
+ * Check if memory cache should be used.
76
+ * Returns true when running locally (not on Vercel) and not in integration test mode.
77
+ */
78
+ export function shouldUseMemoryCache() {
79
+ // Don't use on Vercel
80
+ if (process.env.VERCEL) {
81
+ return false;
82
+ }
83
+ // Don't use during integration tests (they use proxy cache)
84
+ if (process.env.INTEGRATION_TEST === "1") {
85
+ return false;
86
+ }
87
+ // Use memory cache for local development
88
+ return true;
89
+ }
90
+ //# sourceMappingURL=memory-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-cache.js","sourceRoot":"","sources":["../src/memory-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * ProxyCache - A cache implementation that proxies to a deployed cache-proxy endpoint.
3
+ * This allows local development to use the real Vercel cache.
4
+ *
5
+ * Usage:
6
+ * // Set environment variables:
7
+ * // CACHE_PROXY_URL=https://cached-kv-poc.vercel.app/api/cache-proxy
8
+ * // PROTECTION_BYPASS=<your-bypass-token>
9
+ *
10
+ * import { getProxyCache } from "./proxy-cache.js";
11
+ * const cache = getProxyCache();
12
+ * await cache.set("key", { data: "value" }, { ttl: 3600 });
13
+ * const value = await cache.get("key");
14
+ */
15
+ interface CacheSetOptions {
16
+ tags?: string[];
17
+ ttl?: number;
18
+ }
19
+ export interface ProxyCache {
20
+ get(key: string): Promise<unknown>;
21
+ set(key: string, value: unknown, options?: CacheSetOptions): Promise<void>;
22
+ expireTag(tag: string): Promise<void>;
23
+ }
24
+ export interface ProxyCacheOptions {
25
+ /** Base URL of the cache-proxy endpoint */
26
+ proxyUrl?: string;
27
+ /** Protection bypass token for Vercel deployment protection */
28
+ protectionBypass?: string;
29
+ }
30
+ /**
31
+ * Get a proxy cache instance for local development.
32
+ * Uses CACHE_PROXY_URL and PROTECTION_BYPASS environment variables.
33
+ */
34
+ export declare function getProxyCache(options?: ProxyCacheOptions): ProxyCache;
35
+ /**
36
+ * Check if we should use the proxy cache (running locally with integration tests).
37
+ */
38
+ export declare function shouldUseProxyCache(): boolean;
39
+ export {};
40
+ //# sourceMappingURL=proxy-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-cache.d.ts","sourceRoot":"","sources":["../src/proxy-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,UAAU,eAAe;IACxB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IAC1B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,iBAAiB;IACjC,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AA6GD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,UAAU,CAKrE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAW7C"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * ProxyCache - A cache implementation that proxies to a deployed cache-proxy endpoint.
3
+ * This allows local development to use the real Vercel cache.
4
+ *
5
+ * Usage:
6
+ * // Set environment variables:
7
+ * // CACHE_PROXY_URL=https://cached-kv-poc.vercel.app/api/cache-proxy
8
+ * // PROTECTION_BYPASS=<your-bypass-token>
9
+ *
10
+ * import { getProxyCache } from "./proxy-cache.js";
11
+ * const cache = getProxyCache();
12
+ * await cache.set("key", { data: "value" }, { ttl: 3600 });
13
+ * const value = await cache.get("key");
14
+ */
15
+ const DEFAULT_CACHE_PROXY_URL = "https://cached-kv-poc.vercel.app/api/cache-proxy";
16
+ const REQUEST_TIMEOUT_MS = 10000; // 10 second timeout
17
+ class ProxyCacheImpl {
18
+ proxyUrl;
19
+ protectionBypass;
20
+ constructor(options) {
21
+ this.proxyUrl =
22
+ options?.proxyUrl ??
23
+ process.env.CACHE_PROXY_URL ??
24
+ DEFAULT_CACHE_PROXY_URL;
25
+ this.protectionBypass =
26
+ options?.protectionBypass ?? process.env.PROTECTION_BYPASS;
27
+ }
28
+ getHeaders(contentType) {
29
+ const headers = {};
30
+ if (contentType) {
31
+ headers["Content-Type"] = contentType;
32
+ }
33
+ if (this.protectionBypass) {
34
+ headers["x-vercel-protection-bypass"] = this.protectionBypass;
35
+ }
36
+ return headers;
37
+ }
38
+ async fetchWithTimeout(url, options = {}) {
39
+ const controller = new AbortController();
40
+ const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
41
+ try {
42
+ const response = await fetch(url, {
43
+ ...options,
44
+ signal: controller.signal,
45
+ });
46
+ return response;
47
+ }
48
+ finally {
49
+ clearTimeout(timeoutId);
50
+ }
51
+ }
52
+ async get(key) {
53
+ // Pass key in POST body to avoid URL encoding issues with unicode
54
+ const url = `${this.proxyUrl}?op=get`;
55
+ const response = await this.fetchWithTimeout(url, {
56
+ method: "POST",
57
+ headers: this.getHeaders("application/json"),
58
+ body: JSON.stringify({ key }),
59
+ });
60
+ const data = (await response.json());
61
+ if (data.error) {
62
+ throw new Error(data.error);
63
+ }
64
+ return data.value;
65
+ }
66
+ async set(key, value, options) {
67
+ // Pass key in POST body to avoid URL encoding issues with unicode
68
+ const url = `${this.proxyUrl}?op=set`;
69
+ const response = await this.fetchWithTimeout(url, {
70
+ method: "POST",
71
+ headers: this.getHeaders("application/json"),
72
+ body: JSON.stringify({
73
+ key,
74
+ value,
75
+ tags: options?.tags,
76
+ ttl: options?.ttl,
77
+ }),
78
+ });
79
+ const data = (await response.json());
80
+ if (data.error) {
81
+ throw new Error(data.error);
82
+ }
83
+ }
84
+ async expireTag(tag) {
85
+ // Pass tag in POST body to avoid URL encoding issues with unicode
86
+ const url = `${this.proxyUrl}?op=expireTag`;
87
+ const response = await this.fetchWithTimeout(url, {
88
+ method: "POST",
89
+ headers: this.getHeaders("application/json"),
90
+ body: JSON.stringify({ tag }),
91
+ });
92
+ const data = (await response.json());
93
+ if (data.error) {
94
+ throw new Error(data.error);
95
+ }
96
+ }
97
+ }
98
+ let proxyCacheInstance = null;
99
+ /**
100
+ * Get a proxy cache instance for local development.
101
+ * Uses CACHE_PROXY_URL and PROTECTION_BYPASS environment variables.
102
+ */
103
+ export function getProxyCache(options) {
104
+ if (!proxyCacheInstance) {
105
+ proxyCacheInstance = new ProxyCacheImpl(options);
106
+ }
107
+ return proxyCacheInstance;
108
+ }
109
+ /**
110
+ * Check if we should use the proxy cache (running locally with integration tests).
111
+ */
112
+ export function shouldUseProxyCache() {
113
+ // On Vercel, use the native cache
114
+ if (process.env.VERCEL) {
115
+ return false;
116
+ }
117
+ // Only use proxy for integration tests when PROTECTION_BYPASS is set
118
+ if (process.env.INTEGRATION_TEST !== "1") {
119
+ return false;
120
+ }
121
+ // Use proxy if CACHE_PROXY_URL or PROTECTION_BYPASS is set
122
+ return !!(process.env.CACHE_PROXY_URL || process.env.PROTECTION_BYPASS);
123
+ }
124
+ //# sourceMappingURL=proxy-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-cache.js","sourceRoot":"","sources":["../src/proxy-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * README and docs/ validation tests
3
+ *
4
+ * Ensures documentation stays in sync with the actual codebase:
5
+ * 1. TypeScript examples compile correctly
6
+ * 2. API documentation matches KVLike interface
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=readme.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readme.test.d.ts","sourceRoot":"","sources":["../src/readme.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}