@parsrun/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/README.md ADDED
@@ -0,0 +1,135 @@
1
+ # @parsrun/cache
2
+
3
+ Edge-compatible caching for Pars with multiple adapter support.
4
+
5
+ ## Features
6
+
7
+ - **Multi-Adapter**: Memory, Redis, Upstash, Cloudflare KV
8
+ - **Edge-Compatible**: Works on all runtimes
9
+ - **TTL Support**: Automatic expiration
10
+ - **Namespace**: Isolated cache spaces
11
+ - **Tags**: Cache invalidation by tags
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ pnpm add @parsrun/cache
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```typescript
22
+ import { createCache } from '@parsrun/cache';
23
+
24
+ const cache = createCache({
25
+ adapter: 'memory', // or 'redis', 'upstash', 'cloudflare-kv'
26
+ });
27
+
28
+ // Set value
29
+ await cache.set('key', { data: 'value' }, { ttl: 3600 });
30
+
31
+ // Get value
32
+ const value = await cache.get('key');
33
+
34
+ // Delete
35
+ await cache.delete('key');
36
+ ```
37
+
38
+ ## API Overview
39
+
40
+ ### Adapters
41
+
42
+ #### Memory (Development)
43
+
44
+ ```typescript
45
+ import { createMemoryCache } from '@parsrun/cache/adapters/memory';
46
+
47
+ const cache = createMemoryCache({
48
+ maxSize: 1000,
49
+ defaultTTL: 3600,
50
+ });
51
+ ```
52
+
53
+ #### Redis
54
+
55
+ ```typescript
56
+ import { createRedisCache } from '@parsrun/cache/adapters/redis';
57
+
58
+ const cache = createRedisCache({
59
+ url: 'redis://localhost:6379',
60
+ prefix: 'myapp:',
61
+ });
62
+ ```
63
+
64
+ #### Upstash (Serverless Redis)
65
+
66
+ ```typescript
67
+ import { createUpstashCache } from '@parsrun/cache/adapters/upstash';
68
+
69
+ const cache = createUpstashCache({
70
+ url: process.env.UPSTASH_REDIS_URL,
71
+ token: process.env.UPSTASH_REDIS_TOKEN,
72
+ });
73
+ ```
74
+
75
+ #### Cloudflare KV
76
+
77
+ ```typescript
78
+ import { createCloudflareKVCache } from '@parsrun/cache/adapters/cloudflare-kv';
79
+
80
+ // In Cloudflare Worker
81
+ const cache = createCloudflareKVCache({
82
+ namespace: env.CACHE_KV,
83
+ });
84
+ ```
85
+
86
+ ### Cache Operations
87
+
88
+ ```typescript
89
+ // Set with TTL (seconds)
90
+ await cache.set('user:1', userData, { ttl: 3600 });
91
+
92
+ // Set with tags
93
+ await cache.set('user:1', userData, {
94
+ ttl: 3600,
95
+ tags: ['users', 'user:1'],
96
+ });
97
+
98
+ // Get
99
+ const user = await cache.get<User>('user:1');
100
+
101
+ // Get or set
102
+ const user = await cache.getOrSet('user:1', async () => {
103
+ return await fetchUser(1);
104
+ }, { ttl: 3600 });
105
+
106
+ // Delete
107
+ await cache.delete('user:1');
108
+
109
+ // Delete by tag
110
+ await cache.deleteByTag('users');
111
+
112
+ // Clear all
113
+ await cache.clear();
114
+ ```
115
+
116
+ ### With Namespace
117
+
118
+ ```typescript
119
+ const userCache = cache.namespace('users');
120
+ await userCache.set('1', userData); // Key: users:1
121
+ ```
122
+
123
+ ## Exports
124
+
125
+ ```typescript
126
+ import { ... } from '@parsrun/cache'; // Main exports
127
+ import { ... } from '@parsrun/cache/adapters/memory'; // Memory adapter
128
+ import { ... } from '@parsrun/cache/adapters/redis'; // Redis adapter
129
+ import { ... } from '@parsrun/cache/adapters/upstash'; // Upstash adapter
130
+ import { ... } from '@parsrun/cache/adapters/cloudflare-kv'; // Cloudflare KV
131
+ ```
132
+
133
+ ## License
134
+
135
+ MIT
@@ -0,0 +1,51 @@
1
+ import { CacheAdapter, CloudflareKVCacheConfig, CacheGetOptions, CacheSetOptions } from '../types.js';
2
+ import '@parsrun/types';
3
+
4
+ /**
5
+ * @parsrun/cache - Cloudflare KV Adapter
6
+ * Cache adapter for Cloudflare Workers KV
7
+ */
8
+
9
+ /**
10
+ * Cloudflare KV Cache Adapter
11
+ * Uses Cloudflare Workers KV for edge caching
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * // In Cloudflare Workers
16
+ * export default {
17
+ * async fetch(request, env) {
18
+ * const cache = new CloudflareKVCacheAdapter({
19
+ * namespace: env.CACHE_KV,
20
+ * });
21
+ *
22
+ * await cache.set('user:123', { name: 'John' }, { ttl: 3600 });
23
+ * const user = await cache.get('user:123');
24
+ * }
25
+ * }
26
+ * ```
27
+ */
28
+ declare class CloudflareKVCacheAdapter implements CacheAdapter {
29
+ readonly type: "cloudflare-kv";
30
+ private kv;
31
+ private keyPrefix;
32
+ constructor(config: CloudflareKVCacheConfig);
33
+ private prefixKey;
34
+ get<T = unknown>(key: string, _options?: CacheGetOptions): Promise<T | null>;
35
+ set<T = unknown>(key: string, value: T, options?: CacheSetOptions): Promise<void>;
36
+ delete(key: string): Promise<void>;
37
+ has(key: string): Promise<boolean>;
38
+ clear(): Promise<void>;
39
+ getMany<T = unknown>(keys: string[]): Promise<Map<string, T | null>>;
40
+ setMany<T = unknown>(entries: Map<string, T>, options?: CacheSetOptions): Promise<void>;
41
+ deleteMany(keys: string[]): Promise<void>;
42
+ invalidateByTags(tags: string[]): Promise<void>;
43
+ ttl(_key: string): Promise<number>;
44
+ close(): Promise<void>;
45
+ }
46
+ /**
47
+ * Create a Cloudflare KV cache adapter
48
+ */
49
+ declare function createCloudflareKVCacheAdapter(config: CloudflareKVCacheConfig): CloudflareKVCacheAdapter;
50
+
51
+ export { CloudflareKVCacheAdapter, createCloudflareKVCacheAdapter };
@@ -0,0 +1,197 @@
1
+ // src/types.ts
2
+ import {
3
+ type,
4
+ cacheSetOptions,
5
+ cacheGetResult,
6
+ cacheStats,
7
+ memoryCacheConfig,
8
+ redisCacheConfig,
9
+ upstashCacheConfig,
10
+ cloudflareKvConfig,
11
+ multiTierCacheConfig,
12
+ cacheConfig
13
+ } from "@parsrun/types";
14
+ var CacheError = class extends Error {
15
+ constructor(message, code, cause) {
16
+ super(message);
17
+ this.code = code;
18
+ this.cause = cause;
19
+ this.name = "CacheError";
20
+ }
21
+ };
22
+ var CacheErrorCodes = {
23
+ CONNECTION_FAILED: "CONNECTION_FAILED",
24
+ OPERATION_FAILED: "OPERATION_FAILED",
25
+ SERIALIZATION_ERROR: "SERIALIZATION_ERROR",
26
+ INVALID_CONFIG: "INVALID_CONFIG",
27
+ NOT_IMPLEMENTED: "NOT_IMPLEMENTED"
28
+ };
29
+
30
+ // src/adapters/cloudflare-kv.ts
31
+ var CloudflareKVCacheAdapter = class {
32
+ type = "cloudflare-kv";
33
+ kv;
34
+ keyPrefix;
35
+ constructor(config) {
36
+ this.kv = config.namespace;
37
+ this.keyPrefix = config.keyPrefix ?? "";
38
+ }
39
+ prefixKey(key) {
40
+ return this.keyPrefix ? `${this.keyPrefix}:${key}` : key;
41
+ }
42
+ async get(key, _options) {
43
+ try {
44
+ const data = await this.kv.get(this.prefixKey(key), { type: "json" });
45
+ if (!data) {
46
+ return null;
47
+ }
48
+ return data.value;
49
+ } catch (err) {
50
+ throw new CacheError(
51
+ `Cloudflare KV get failed: ${err instanceof Error ? err.message : "Unknown error"}`,
52
+ CacheErrorCodes.OPERATION_FAILED,
53
+ err
54
+ );
55
+ }
56
+ }
57
+ async set(key, value, options) {
58
+ try {
59
+ const data = {
60
+ value,
61
+ tags: options?.tags,
62
+ metadata: options?.metadata
63
+ };
64
+ const putOptions = {};
65
+ if (options?.ttl) {
66
+ putOptions.expirationTtl = options.ttl;
67
+ }
68
+ if (options?.tags || options?.metadata) {
69
+ putOptions.metadata = {
70
+ tags: options.tags,
71
+ ...options.metadata
72
+ };
73
+ }
74
+ await this.kv.put(this.prefixKey(key), JSON.stringify(data), putOptions);
75
+ if (options?.tags && options.tags.length > 0) {
76
+ for (const tag of options.tags) {
77
+ const tagKey = this.prefixKey(`__tag:${tag}`);
78
+ const existing = await this.kv.get(tagKey, { type: "json" });
79
+ const keys = existing ? [.../* @__PURE__ */ new Set([...existing, key])] : [key];
80
+ await this.kv.put(tagKey, JSON.stringify(keys));
81
+ }
82
+ }
83
+ } catch (err) {
84
+ throw new CacheError(
85
+ `Cloudflare KV set failed: ${err instanceof Error ? err.message : "Unknown error"}`,
86
+ CacheErrorCodes.OPERATION_FAILED,
87
+ err
88
+ );
89
+ }
90
+ }
91
+ async delete(key) {
92
+ try {
93
+ await this.kv.delete(this.prefixKey(key));
94
+ } catch (err) {
95
+ throw new CacheError(
96
+ `Cloudflare KV delete failed: ${err instanceof Error ? err.message : "Unknown error"}`,
97
+ CacheErrorCodes.OPERATION_FAILED,
98
+ err
99
+ );
100
+ }
101
+ }
102
+ async has(key) {
103
+ try {
104
+ const value = await this.kv.get(this.prefixKey(key));
105
+ return value !== null;
106
+ } catch (err) {
107
+ throw new CacheError(
108
+ `Cloudflare KV has failed: ${err instanceof Error ? err.message : "Unknown error"}`,
109
+ CacheErrorCodes.OPERATION_FAILED,
110
+ err
111
+ );
112
+ }
113
+ }
114
+ async clear() {
115
+ try {
116
+ const prefix = this.keyPrefix ? `${this.keyPrefix}:` : "";
117
+ let cursor;
118
+ do {
119
+ const result = await this.kv.list({
120
+ prefix,
121
+ limit: 1e3,
122
+ cursor
123
+ });
124
+ for (const key of result.keys) {
125
+ await this.kv.delete(key.name);
126
+ }
127
+ cursor = result.list_complete ? void 0 : result.cursor;
128
+ } while (cursor);
129
+ } catch (err) {
130
+ throw new CacheError(
131
+ `Cloudflare KV clear failed: ${err instanceof Error ? err.message : "Unknown error"}`,
132
+ CacheErrorCodes.OPERATION_FAILED,
133
+ err
134
+ );
135
+ }
136
+ }
137
+ async getMany(keys) {
138
+ const map = /* @__PURE__ */ new Map();
139
+ const promises = keys.map(async (key) => {
140
+ const value = await this.get(key);
141
+ return { key, value };
142
+ });
143
+ const results = await Promise.all(promises);
144
+ for (const { key, value } of results) {
145
+ map.set(key, value);
146
+ }
147
+ return map;
148
+ }
149
+ async setMany(entries, options) {
150
+ const promises = [];
151
+ for (const [key, value] of entries) {
152
+ promises.push(this.set(key, value, options));
153
+ }
154
+ await Promise.all(promises);
155
+ }
156
+ async deleteMany(keys) {
157
+ const promises = keys.map((key) => this.delete(key));
158
+ await Promise.all(promises);
159
+ }
160
+ async invalidateByTags(tags) {
161
+ try {
162
+ const keysToDelete = /* @__PURE__ */ new Set();
163
+ for (const tag of tags) {
164
+ const tagKey = this.prefixKey(`__tag:${tag}`);
165
+ const keys = await this.kv.get(tagKey, { type: "json" });
166
+ if (keys) {
167
+ for (const key of keys) {
168
+ keysToDelete.add(key);
169
+ }
170
+ await this.kv.delete(tagKey);
171
+ }
172
+ }
173
+ if (keysToDelete.size > 0) {
174
+ await this.deleteMany([...keysToDelete]);
175
+ }
176
+ } catch (err) {
177
+ throw new CacheError(
178
+ `Cloudflare KV invalidate by tags failed: ${err instanceof Error ? err.message : "Unknown error"}`,
179
+ CacheErrorCodes.OPERATION_FAILED,
180
+ err
181
+ );
182
+ }
183
+ }
184
+ async ttl(_key) {
185
+ return -1;
186
+ }
187
+ async close() {
188
+ }
189
+ };
190
+ function createCloudflareKVCacheAdapter(config) {
191
+ return new CloudflareKVCacheAdapter(config);
192
+ }
193
+ export {
194
+ CloudflareKVCacheAdapter,
195
+ createCloudflareKVCacheAdapter
196
+ };
197
+ //# sourceMappingURL=cloudflare-kv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types.ts","../../src/adapters/cloudflare-kv.ts"],"sourcesContent":["/**\n * @parsrun/cache - Type Definitions\n * Cache types and interfaces\n */\n\n// Re-export types from @parsrun/types for convenience\nexport {\n type,\n cacheSetOptions as parsCacheSetOptions,\n cacheGetResult,\n cacheStats,\n memoryCacheConfig,\n redisCacheConfig,\n upstashCacheConfig,\n cloudflareKvConfig,\n multiTierCacheConfig,\n cacheConfig,\n type CacheSetOptions as ParsCacheSetOptions,\n type CacheGetResult,\n type CacheStats,\n type MemoryCacheConfig as ParsMemoryCacheConfig,\n type RedisCacheConfig as ParsRedisCacheConfig,\n type UpstashCacheConfig as ParsUpstashCacheConfig,\n type CloudflareKvConfig as ParsCloudflareKvConfig,\n type MultiTierCacheConfig,\n type CacheConfig,\n} from \"@parsrun/types\";\n\n/**\n * Cache adapter type\n */\nexport type CacheAdapterType = \"memory\" | \"redis\" | \"upstash\" | \"cloudflare-kv\";\n\n/**\n * Cache entry with metadata\n */\nexport interface CacheEntry<T = unknown> {\n /** Cached value */\n value: T;\n /** Expiration timestamp (ms) */\n expiresAt?: number | undefined;\n /** Original TTL in seconds (for refresh/sliding expiration) */\n ttlSeconds?: number | undefined;\n /** Cache entry tags for invalidation */\n tags?: string[] | undefined;\n /** Cache entry metadata */\n metadata?: Record<string, unknown> | undefined;\n}\n\n/**\n * Cache get options\n */\nexport interface CacheGetOptions {\n /** Whether to update TTL on access (sliding expiration) */\n refresh?: boolean | undefined;\n}\n\n/**\n * Cache set options\n */\nexport interface CacheSetOptions {\n /** Time to live in seconds */\n ttl?: number | undefined;\n /** Tags for cache invalidation */\n tags?: string[] | undefined;\n /** Additional metadata */\n metadata?: Record<string, unknown> | undefined;\n}\n\n/**\n * Cache delete options\n */\nexport interface CacheDeleteOptions {\n /** Delete all entries with matching tags */\n tags?: string[] | undefined;\n}\n\n/**\n * Cache adapter interface\n */\nexport interface CacheAdapter {\n /** Adapter type */\n readonly type: CacheAdapterType;\n\n /**\n * Get a value from cache\n * @param key Cache key\n * @param options Get options\n * @returns Cached value or null if not found/expired\n */\n get<T = unknown>(key: string, options?: CacheGetOptions): Promise<T | null>;\n\n /**\n * Set a value in cache\n * @param key Cache key\n * @param value Value to cache\n * @param options Set options\n */\n set<T = unknown>(key: string, value: T, options?: CacheSetOptions): Promise<void>;\n\n /**\n * Delete a value from cache\n * @param key Cache key\n */\n delete(key: string): Promise<void>;\n\n /**\n * Check if a key exists in cache\n * @param key Cache key\n */\n has(key: string): Promise<boolean>;\n\n /**\n * Clear all entries from cache\n */\n clear?(): Promise<void>;\n\n /**\n * Get multiple values at once\n * @param keys Cache keys\n */\n getMany?<T = unknown>(keys: string[]): Promise<Map<string, T | null>>;\n\n /**\n * Set multiple values at once\n * @param entries Key-value pairs\n * @param options Set options (applied to all)\n */\n setMany?<T = unknown>(entries: Map<string, T>, options?: CacheSetOptions): Promise<void>;\n\n /**\n * Delete multiple keys\n * @param keys Cache keys\n */\n deleteMany?(keys: string[]): Promise<void>;\n\n /**\n * Invalidate entries by tags\n * @param tags Tags to invalidate\n */\n invalidateByTags?(tags: string[]): Promise<void>;\n\n /**\n * Get TTL for a key (in seconds)\n * @param key Cache key\n * @returns TTL in seconds, -1 if no expiry, -2 if key doesn't exist\n */\n ttl?(key: string): Promise<number>;\n\n /**\n * Close/cleanup adapter resources\n */\n close?(): Promise<void>;\n}\n\n/**\n * Cache service configuration\n */\nexport interface CacheServiceConfig {\n /** Cache adapter to use */\n adapter: CacheAdapter;\n /** Default TTL in seconds */\n defaultTtl?: number | undefined;\n /** Key prefix for namespacing */\n keyPrefix?: string | undefined;\n /** Enable debug logging */\n debug?: boolean | undefined;\n}\n\n/**\n * Memory adapter configuration\n */\nexport interface MemoryCacheConfig {\n /** Maximum number of entries */\n maxEntries?: number | undefined;\n /** Cleanup interval in ms (default: 60000) */\n cleanupInterval?: number | undefined;\n}\n\n/**\n * Redis adapter configuration\n */\nexport interface RedisCacheConfig {\n /** Redis connection URL */\n url?: string | undefined;\n /** Redis host */\n host?: string | undefined;\n /** Redis port */\n port?: number | undefined;\n /** Redis password */\n password?: string | undefined;\n /** Redis database number */\n db?: number | undefined;\n /** Key prefix */\n keyPrefix?: string | undefined;\n /** Use TLS */\n tls?: boolean | undefined;\n}\n\n/**\n * Upstash adapter configuration\n */\nexport interface UpstashCacheConfig {\n /** Upstash Redis URL */\n url: string;\n /** Upstash Redis token */\n token: string;\n /** Key prefix */\n keyPrefix?: string | undefined;\n}\n\n/**\n * Cloudflare KV adapter configuration\n */\nexport interface CloudflareKVCacheConfig {\n /** KV namespace binding */\n namespace: KVNamespace;\n /** Key prefix */\n keyPrefix?: string | undefined;\n}\n\n/**\n * KVNamespace interface (Cloudflare Workers)\n */\nexport interface KVNamespace {\n get(key: string, options?: { type?: \"text\" | \"json\" | \"arrayBuffer\" | \"stream\" }): Promise<string | null>;\n get(key: string, options: { type: \"json\" }): Promise<unknown>;\n put(key: string, value: string | ArrayBuffer | ReadableStream, options?: { expiration?: number; expirationTtl?: number; metadata?: unknown }): Promise<void>;\n delete(key: string): Promise<void>;\n list(options?: { prefix?: string | undefined; limit?: number | undefined; cursor?: string | undefined }): Promise<{ keys: Array<{ name: string; expiration?: number; metadata?: unknown }>; list_complete: boolean; cursor?: string }>;\n getWithMetadata<T = unknown>(key: string, options?: { type?: \"text\" | \"json\" | \"arrayBuffer\" | \"stream\" }): Promise<{ value: string | null; metadata: T | null }>;\n}\n\n/**\n * Cache error\n */\nexport class CacheError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly cause?: unknown\n ) {\n super(message);\n this.name = \"CacheError\";\n }\n}\n\n/**\n * Common cache error codes\n */\nexport const CacheErrorCodes = {\n CONNECTION_FAILED: \"CONNECTION_FAILED\",\n OPERATION_FAILED: \"OPERATION_FAILED\",\n SERIALIZATION_ERROR: \"SERIALIZATION_ERROR\",\n INVALID_CONFIG: \"INVALID_CONFIG\",\n NOT_IMPLEMENTED: \"NOT_IMPLEMENTED\",\n} as const;\n","/**\n * @parsrun/cache - Cloudflare KV Adapter\n * Cache adapter for Cloudflare Workers KV\n */\n\nimport type {\n CacheAdapter,\n CacheGetOptions,\n CacheSetOptions,\n CloudflareKVCacheConfig,\n KVNamespace,\n} from \"../types.js\";\nimport { CacheError, CacheErrorCodes } from \"../types.js\";\n\n/**\n * Cloudflare KV Cache Adapter\n * Uses Cloudflare Workers KV for edge caching\n *\n * @example\n * ```typescript\n * // In Cloudflare Workers\n * export default {\n * async fetch(request, env) {\n * const cache = new CloudflareKVCacheAdapter({\n * namespace: env.CACHE_KV,\n * });\n *\n * await cache.set('user:123', { name: 'John' }, { ttl: 3600 });\n * const user = await cache.get('user:123');\n * }\n * }\n * ```\n */\nexport class CloudflareKVCacheAdapter implements CacheAdapter {\n readonly type = \"cloudflare-kv\" as const;\n\n private kv: KVNamespace;\n private keyPrefix: string;\n\n constructor(config: CloudflareKVCacheConfig) {\n this.kv = config.namespace;\n this.keyPrefix = config.keyPrefix ?? \"\";\n }\n\n private prefixKey(key: string): string {\n return this.keyPrefix ? `${this.keyPrefix}:${key}` : key;\n }\n\n async get<T = unknown>(key: string, _options?: CacheGetOptions): Promise<T | null> {\n try {\n const data = await this.kv.get(this.prefixKey(key), { type: \"json\" }) as { value: T; tags?: string[] } | null;\n\n if (!data) {\n return null;\n }\n\n return data.value;\n } catch (err) {\n throw new CacheError(\n `Cloudflare KV get failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n CacheErrorCodes.OPERATION_FAILED,\n err\n );\n }\n }\n\n async set<T = unknown>(key: string, value: T, options?: CacheSetOptions): Promise<void> {\n try {\n const data = {\n value,\n tags: options?.tags,\n metadata: options?.metadata,\n };\n\n const putOptions: { expirationTtl?: number; metadata?: unknown } = {};\n\n if (options?.ttl) {\n putOptions.expirationTtl = options.ttl;\n }\n\n // Store metadata in KV metadata field\n if (options?.tags || options?.metadata) {\n putOptions.metadata = {\n tags: options.tags,\n ...options.metadata,\n };\n }\n\n await this.kv.put(this.prefixKey(key), JSON.stringify(data), putOptions);\n\n // Store tag-to-key mappings\n if (options?.tags && options.tags.length > 0) {\n for (const tag of options.tags) {\n const tagKey = this.prefixKey(`__tag:${tag}`);\n const existing = await this.kv.get(tagKey, { type: \"json\" }) as string[] | null;\n const keys = existing ? [...new Set([...existing, key])] : [key];\n await this.kv.put(tagKey, JSON.stringify(keys));\n }\n }\n } catch (err) {\n throw new CacheError(\n `Cloudflare KV set failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n CacheErrorCodes.OPERATION_FAILED,\n err\n );\n }\n }\n\n async delete(key: string): Promise<void> {\n try {\n await this.kv.delete(this.prefixKey(key));\n } catch (err) {\n throw new CacheError(\n `Cloudflare KV delete failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n CacheErrorCodes.OPERATION_FAILED,\n err\n );\n }\n }\n\n async has(key: string): Promise<boolean> {\n try {\n const value = await this.kv.get(this.prefixKey(key));\n return value !== null;\n } catch (err) {\n throw new CacheError(\n `Cloudflare KV has failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n CacheErrorCodes.OPERATION_FAILED,\n err\n );\n }\n }\n\n async clear(): Promise<void> {\n try {\n const prefix = this.keyPrefix ? `${this.keyPrefix}:` : \"\";\n let cursor: string | undefined;\n\n do {\n const result = await this.kv.list({\n prefix,\n limit: 1000,\n cursor,\n });\n\n for (const key of result.keys) {\n await this.kv.delete(key.name);\n }\n\n cursor = result.list_complete ? undefined : result.cursor;\n } while (cursor);\n } catch (err) {\n throw new CacheError(\n `Cloudflare KV clear failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n CacheErrorCodes.OPERATION_FAILED,\n err\n );\n }\n }\n\n async getMany<T = unknown>(keys: string[]): Promise<Map<string, T | null>> {\n const map = new Map<string, T | null>();\n\n // KV doesn't support batch get, so we do parallel fetches\n const promises = keys.map(async (key) => {\n const value = await this.get<T>(key);\n return { key, value };\n });\n\n const results = await Promise.all(promises);\n\n for (const { key, value } of results) {\n map.set(key, value);\n }\n\n return map;\n }\n\n async setMany<T = unknown>(entries: Map<string, T>, options?: CacheSetOptions): Promise<void> {\n // KV doesn't support batch write, so we do parallel writes\n const promises: Promise<void>[] = [];\n\n for (const [key, value] of entries) {\n promises.push(this.set(key, value, options));\n }\n\n await Promise.all(promises);\n }\n\n async deleteMany(keys: string[]): Promise<void> {\n // KV doesn't support batch delete, so we do parallel deletes\n const promises = keys.map((key) => this.delete(key));\n await Promise.all(promises);\n }\n\n async invalidateByTags(tags: string[]): Promise<void> {\n try {\n const keysToDelete = new Set<string>();\n\n for (const tag of tags) {\n const tagKey = this.prefixKey(`__tag:${tag}`);\n const keys = await this.kv.get(tagKey, { type: \"json\" }) as string[] | null;\n\n if (keys) {\n for (const key of keys) {\n keysToDelete.add(key);\n }\n // Delete tag mapping\n await this.kv.delete(tagKey);\n }\n }\n\n if (keysToDelete.size > 0) {\n await this.deleteMany([...keysToDelete]);\n }\n } catch (err) {\n throw new CacheError(\n `Cloudflare KV invalidate by tags failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n CacheErrorCodes.OPERATION_FAILED,\n err\n );\n }\n }\n\n async ttl(_key: string): Promise<number> {\n // Cloudflare KV doesn't expose TTL, return -1 (unknown)\n return -1;\n }\n\n async close(): Promise<void> {\n // No-op for KV\n }\n}\n\n/**\n * Create a Cloudflare KV cache adapter\n */\nexport function createCloudflareKVCacheAdapter(config: CloudflareKVCacheConfig): CloudflareKVCacheAdapter {\n return new CloudflareKVCacheAdapter(config);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,6 @@
1
+ export { MemoryCacheAdapter, createMemoryCacheAdapter } from './memory.js';
2
+ export { RedisCacheAdapter, createRedisCacheAdapter } from './redis.js';
3
+ export { UpstashCacheAdapter, createUpstashCacheAdapter } from './upstash.js';
4
+ export { CloudflareKVCacheAdapter, createCloudflareKVCacheAdapter } from './cloudflare-kv.js';
5
+ import '../types.js';
6
+ import '@parsrun/types';