@flareone/kv 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Flareone Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # @flareone/kv
2
+
3
+ Workers KV integration for Flareone framework.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @flareone/kv
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - **Type-safe Wrapper**: High-level API for `KVNamespace`
14
+ - **Caching**: Built-in TTL and caching strategies
15
+ - **Repository Pattern**: `KVRepository` base class for entity management
16
+ - **Batch Operations**: Efficient `setMany`, `deleteMany`, `list`
17
+ - **Metadata Support**: Simple API for storing/retrieving metadata
18
+
19
+ ## Usage
20
+
21
+ ```typescript
22
+ import { Module, Injectable, Inject } from '@flareone/core';
23
+ import { KVModule, KVService } from '@flareone/kv';
24
+
25
+ @Injectable()
26
+ class CacheService {
27
+ constructor(@Inject(KVService) private kv: KVService) {}
28
+
29
+ async saveUser(id: string, data: any) {
30
+ // Automatic JSON serialization + TTL
31
+ await this.kv.set(`user:${id}`, data, { expirationTtl: 3600 });
32
+ }
33
+ }
34
+
35
+ @Module({
36
+ imports: [
37
+ KVModule.forRoot({
38
+ binding: 'MY_KV', // Binding name in wrangler.toml
39
+ keyPrefix: 'app:'
40
+ })
41
+ ]
42
+ })
43
+ class AppModule {}
44
+ ```
45
+
46
+ See [main repository](https://github.com/flareonejs/flareone) for full documentation.
@@ -0,0 +1,241 @@
1
+ import { Type, DynamicModule, InjectionToken } from '@flareone/core';
2
+
3
+ /**
4
+ * @flareone/kv - Workers KV Integration
5
+ * High-level, type-safe wrapper for Cloudflare Workers KV
6
+ */
7
+
8
+ interface KVGetOptions {
9
+ type?: 'text' | 'json' | 'arrayBuffer' | 'stream';
10
+ cacheTtl?: number;
11
+ }
12
+ interface KVPutOptions {
13
+ expiration?: number;
14
+ expirationTtl?: number;
15
+ metadata?: Record<string, unknown>;
16
+ }
17
+ interface KVListOptions {
18
+ prefix?: string;
19
+ limit?: number;
20
+ cursor?: string;
21
+ }
22
+ interface KVListResult<T = unknown> {
23
+ keys: Array<{
24
+ name: string;
25
+ expiration?: number;
26
+ metadata?: T;
27
+ }>;
28
+ list_complete: boolean;
29
+ cursor?: string;
30
+ }
31
+ interface KVValueWithMetadata<T, M = unknown> {
32
+ value: T | null;
33
+ metadata: M | null;
34
+ }
35
+ interface KVModuleOptions {
36
+ binding: string;
37
+ defaultTtl?: number;
38
+ keyPrefix?: string;
39
+ enableCache?: boolean;
40
+ cacheTtl?: number;
41
+ }
42
+ interface KVModuleAsyncOptions {
43
+ imports?: Array<Type | DynamicModule>;
44
+ useFactory: (...args: unknown[]) => KVModuleOptions | Promise<KVModuleOptions>;
45
+ inject?: InjectionToken[];
46
+ }
47
+ declare const KV_OPTIONS: InjectionToken<KVModuleOptions>;
48
+ declare const KV_NAMESPACE: InjectionToken<KVNamespace<string>>;
49
+ /**
50
+ * High-level KV service with type-safe operations
51
+ */
52
+ declare class KVService {
53
+ private namespace;
54
+ private options;
55
+ /**
56
+ * Initialize with KV namespace and options
57
+ */
58
+ initialize(namespace: KVNamespace, options: KVModuleOptions): void;
59
+ /**
60
+ * Get the underlying KV namespace
61
+ */
62
+ getNamespace(): KVNamespace;
63
+ /**
64
+ * Build the full key with optional prefix
65
+ */
66
+ private buildKey;
67
+ /**
68
+ * Get a value by key
69
+ */
70
+ get<T = string>(key: string, options?: KVGetOptions): Promise<T | null>;
71
+ /**
72
+ * Get a value as text
73
+ */
74
+ getText(key: string, cacheTtl?: number): Promise<string | null>;
75
+ /**
76
+ * Get a value as JSON
77
+ */
78
+ getJson<T>(key: string, cacheTtl?: number): Promise<T | null>;
79
+ /**
80
+ * Get a value as ArrayBuffer
81
+ */
82
+ getArrayBuffer(key: string, cacheTtl?: number): Promise<ArrayBuffer | null>;
83
+ /**
84
+ * Get a value as ReadableStream
85
+ */
86
+ getStream(key: string, cacheTtl?: number): Promise<ReadableStream | null>;
87
+ /**
88
+ * Get a value with its metadata
89
+ */
90
+ getWithMetadata<T = unknown, M = unknown>(key: string, type?: 'text' | 'json' | 'arrayBuffer' | 'stream'): Promise<KVValueWithMetadata<T, M>>;
91
+ /**
92
+ * Set a value
93
+ */
94
+ set<T = unknown>(key: string, value: T, options?: KVPutOptions): Promise<void>;
95
+ /**
96
+ * Set multiple values at once
97
+ */
98
+ setMany<T = unknown>(entries: Array<{
99
+ key: string;
100
+ value: T;
101
+ options?: KVPutOptions;
102
+ }>): Promise<void>;
103
+ /**
104
+ * Set a value with automatic JSON serialization
105
+ */
106
+ setJson<T>(key: string, value: T, options?: KVPutOptions): Promise<void>;
107
+ /**
108
+ * Set a value as raw text
109
+ */
110
+ setText(key: string, value: string, options?: KVPutOptions): Promise<void>;
111
+ /**
112
+ * Set a value as ArrayBuffer
113
+ */
114
+ setArrayBuffer(key: string, value: ArrayBuffer, options?: KVPutOptions): Promise<void>;
115
+ /**
116
+ * Delete a key
117
+ */
118
+ delete(key: string): Promise<void>;
119
+ /**
120
+ * Delete multiple keys
121
+ */
122
+ deleteMany(keys: string[]): Promise<void>;
123
+ /**
124
+ * Delete all keys with a prefix
125
+ */
126
+ deleteByPrefix(prefix: string): Promise<number>;
127
+ /**
128
+ * List keys
129
+ */
130
+ list<M = unknown>(options?: KVListOptions): Promise<KVListResult<M>>;
131
+ /**
132
+ * Get all keys (handles pagination automatically)
133
+ */
134
+ keys<M = unknown>(prefix?: string): Promise<Array<{
135
+ name: string;
136
+ metadata?: M;
137
+ }>>;
138
+ /**
139
+ * Check if a key exists
140
+ */
141
+ exists(key: string): Promise<boolean>;
142
+ /**
143
+ * Get or set a value (cache pattern)
144
+ */
145
+ getOrSet<T>(key: string, factory: () => T | Promise<T>, options?: KVPutOptions): Promise<T>;
146
+ /**
147
+ * Increment a numeric value
148
+ */
149
+ increment(key: string, delta?: number): Promise<number>;
150
+ /**
151
+ * Decrement a numeric value
152
+ */
153
+ decrement(key: string, delta?: number): Promise<number>;
154
+ /**
155
+ * Append to an array stored in KV
156
+ */
157
+ append<T>(key: string, item: T, options?: KVPutOptions): Promise<T[]>;
158
+ /**
159
+ * Update a value with a transformer function
160
+ */
161
+ update<T>(key: string, updater: (current: T | null) => T, options?: KVPutOptions): Promise<T>;
162
+ }
163
+ /**
164
+ * Base class for creating typed KV repositories
165
+ */
166
+ declare abstract class KVRepository<T, M = unknown> {
167
+ protected readonly kv: KVService;
168
+ protected readonly prefix: string;
169
+ constructor(kv: KVService, prefix: string);
170
+ /**
171
+ * Build the full key for an entity
172
+ */
173
+ protected buildKey(id: string): string;
174
+ /**
175
+ * Find an entity by ID
176
+ */
177
+ findById(id: string): Promise<T | null>;
178
+ /**
179
+ * Find an entity by ID with metadata
180
+ */
181
+ findByIdWithMetadata(id: string): Promise<KVValueWithMetadata<T, M>>;
182
+ /**
183
+ * Save an entity
184
+ */
185
+ save(id: string, entity: T, options?: KVPutOptions): Promise<void>;
186
+ /**
187
+ * Delete an entity
188
+ */
189
+ delete(id: string): Promise<void>;
190
+ /**
191
+ * Check if an entity exists
192
+ */
193
+ exists(id: string): Promise<boolean>;
194
+ /**
195
+ * Get all entity IDs
196
+ */
197
+ getAllIds(): Promise<string[]>;
198
+ /**
199
+ * Get all entities
200
+ */
201
+ findAll(): Promise<T[]>;
202
+ /**
203
+ * Count entities
204
+ */
205
+ count(): Promise<number>;
206
+ /**
207
+ * Delete all entities
208
+ */
209
+ deleteAll(): Promise<number>;
210
+ }
211
+ /**
212
+ * Parameter decorator to inject KV namespace directly
213
+ */
214
+ declare function InjectKV(binding: string): ParameterDecorator;
215
+ /**
216
+ * KV Module for Flareone
217
+ */
218
+ declare class KVModule {
219
+ /**
220
+ * Configure KV module with static options
221
+ */
222
+ static forRoot(options: KVModuleOptions): DynamicModule;
223
+ /**
224
+ * Configure KV module with async options
225
+ */
226
+ static forRootAsync(options: KVModuleAsyncOptions): DynamicModule;
227
+ /**
228
+ * Configure KV for a specific feature/namespace
229
+ */
230
+ static forFeature(options: KVModuleOptions): DynamicModule;
231
+ }
232
+ /**
233
+ * Create a KV service for a specific namespace
234
+ */
235
+ declare function createKVService(namespace: KVNamespace, options?: Partial<KVModuleOptions>): KVService;
236
+ /**
237
+ * Helper to get KV namespace from environment
238
+ */
239
+ declare function getKVNamespace(env: Record<string, unknown>, binding: string): KVNamespace;
240
+
241
+ export { InjectKV, type KVGetOptions, type KVListOptions, type KVListResult, KVModule, type KVModuleAsyncOptions, type KVModuleOptions, type KVPutOptions, KVRepository, KVService, type KVValueWithMetadata, KV_NAMESPACE, KV_OPTIONS, createKVService, getKVNamespace };
package/dist/index.js ADDED
@@ -0,0 +1,409 @@
1
+ import { createToken, Injectable, Module } from '@flareone/core';
2
+
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __decorateClass = (decorators, target, key, kind) => {
5
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
6
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
7
+ if (decorator = decorators[i])
8
+ result = (decorator(result)) || result;
9
+ return result;
10
+ };
11
+ var KV_OPTIONS = createToken("KV_OPTIONS");
12
+ var KV_NAMESPACE = createToken("KV_NAMESPACE");
13
+ var KVService = class {
14
+ namespace = null;
15
+ options = null;
16
+ /**
17
+ * Initialize with KV namespace and options
18
+ */
19
+ initialize(namespace, options) {
20
+ this.namespace = namespace;
21
+ this.options = options;
22
+ }
23
+ /**
24
+ * Get the underlying KV namespace
25
+ */
26
+ getNamespace() {
27
+ if (!this.namespace) {
28
+ throw new Error("KV namespace not initialized. Make sure KVModule is properly configured.");
29
+ }
30
+ return this.namespace;
31
+ }
32
+ /**
33
+ * Build the full key with optional prefix
34
+ */
35
+ buildKey(key) {
36
+ return this.options?.keyPrefix ? `${this.options.keyPrefix}${key}` : key;
37
+ }
38
+ /**
39
+ * Get a value by key
40
+ */
41
+ async get(key, options) {
42
+ const ns = this.getNamespace();
43
+ const fullKey = this.buildKey(key);
44
+ const type = options?.type ?? "json";
45
+ const cacheTtl = options?.cacheTtl ?? this.options?.cacheTtl;
46
+ const kvOptions = { type };
47
+ if (cacheTtl) {
48
+ kvOptions.cacheTtl = cacheTtl;
49
+ }
50
+ return ns.get(fullKey, kvOptions);
51
+ }
52
+ /**
53
+ * Get a value as text
54
+ */
55
+ async getText(key, cacheTtl) {
56
+ return this.get(key, { type: "text", cacheTtl });
57
+ }
58
+ /**
59
+ * Get a value as JSON
60
+ */
61
+ async getJson(key, cacheTtl) {
62
+ return this.get(key, { type: "json", cacheTtl });
63
+ }
64
+ /**
65
+ * Get a value as ArrayBuffer
66
+ */
67
+ async getArrayBuffer(key, cacheTtl) {
68
+ return this.get(key, { type: "arrayBuffer", cacheTtl });
69
+ }
70
+ /**
71
+ * Get a value as ReadableStream
72
+ */
73
+ async getStream(key, cacheTtl) {
74
+ return this.get(key, { type: "stream", cacheTtl });
75
+ }
76
+ /**
77
+ * Get a value with its metadata
78
+ */
79
+ async getWithMetadata(key, type = "json") {
80
+ const ns = this.getNamespace();
81
+ const fullKey = this.buildKey(key);
82
+ const result = await ns.getWithMetadata(fullKey, { type });
83
+ return {
84
+ value: result.value,
85
+ metadata: result.metadata
86
+ };
87
+ }
88
+ /**
89
+ * Set a value
90
+ */
91
+ async set(key, value, options) {
92
+ const ns = this.getNamespace();
93
+ const fullKey = this.buildKey(key);
94
+ const serialized = typeof value === "string" ? value : JSON.stringify(value);
95
+ const kvOptions = {};
96
+ if (options?.expiration) {
97
+ kvOptions.expiration = options.expiration;
98
+ }
99
+ if (options?.expirationTtl ?? this.options?.defaultTtl) {
100
+ kvOptions.expirationTtl = options?.expirationTtl ?? this.options?.defaultTtl;
101
+ }
102
+ if (options?.metadata) {
103
+ kvOptions.metadata = options.metadata;
104
+ }
105
+ await ns.put(fullKey, serialized, kvOptions);
106
+ }
107
+ /**
108
+ * Set multiple values at once
109
+ */
110
+ async setMany(entries) {
111
+ await Promise.all(
112
+ entries.map(({ key, value, options }) => this.set(key, value, options))
113
+ );
114
+ }
115
+ /**
116
+ * Set a value with automatic JSON serialization
117
+ */
118
+ async setJson(key, value, options) {
119
+ return this.set(key, value, options);
120
+ }
121
+ /**
122
+ * Set a value as raw text
123
+ */
124
+ async setText(key, value, options) {
125
+ const ns = this.getNamespace();
126
+ const fullKey = this.buildKey(key);
127
+ const kvOptions = {};
128
+ if (options?.expiration) kvOptions.expiration = options.expiration;
129
+ if (options?.expirationTtl ?? this.options?.defaultTtl) {
130
+ kvOptions.expirationTtl = options?.expirationTtl ?? this.options?.defaultTtl;
131
+ }
132
+ if (options?.metadata) kvOptions.metadata = options.metadata;
133
+ await ns.put(fullKey, value, kvOptions);
134
+ }
135
+ /**
136
+ * Set a value as ArrayBuffer
137
+ */
138
+ async setArrayBuffer(key, value, options) {
139
+ const ns = this.getNamespace();
140
+ const fullKey = this.buildKey(key);
141
+ const kvOptions = {};
142
+ if (options?.expiration) kvOptions.expiration = options.expiration;
143
+ if (options?.expirationTtl ?? this.options?.defaultTtl) {
144
+ kvOptions.expirationTtl = options?.expirationTtl ?? this.options?.defaultTtl;
145
+ }
146
+ if (options?.metadata) kvOptions.metadata = options.metadata;
147
+ await ns.put(fullKey, value, kvOptions);
148
+ }
149
+ /**
150
+ * Delete a key
151
+ */
152
+ async delete(key) {
153
+ const ns = this.getNamespace();
154
+ const fullKey = this.buildKey(key);
155
+ await ns.delete(fullKey);
156
+ }
157
+ /**
158
+ * Delete multiple keys
159
+ */
160
+ async deleteMany(keys) {
161
+ await Promise.all(keys.map((key) => this.delete(key)));
162
+ }
163
+ /**
164
+ * Delete all keys with a prefix
165
+ */
166
+ async deleteByPrefix(prefix) {
167
+ const keys = await this.keys(prefix);
168
+ await this.deleteMany(keys.map((k) => k.name));
169
+ return keys.length;
170
+ }
171
+ /**
172
+ * List keys
173
+ */
174
+ async list(options) {
175
+ const ns = this.getNamespace();
176
+ const kvOptions = {};
177
+ if (options?.prefix) {
178
+ kvOptions.prefix = this.buildKey(options.prefix);
179
+ }
180
+ if (options?.limit) {
181
+ kvOptions.limit = options.limit;
182
+ }
183
+ if (options?.cursor) {
184
+ kvOptions.cursor = options.cursor;
185
+ }
186
+ return ns.list(kvOptions);
187
+ }
188
+ /**
189
+ * Get all keys (handles pagination automatically)
190
+ */
191
+ async keys(prefix) {
192
+ const allKeys = [];
193
+ let cursor;
194
+ let complete = false;
195
+ while (!complete) {
196
+ const result = await this.list({
197
+ prefix,
198
+ cursor,
199
+ limit: 1e3
200
+ });
201
+ allKeys.push(...result.keys);
202
+ complete = result.list_complete;
203
+ cursor = result.cursor;
204
+ }
205
+ return allKeys;
206
+ }
207
+ /**
208
+ * Check if a key exists
209
+ */
210
+ async exists(key) {
211
+ const value = await this.get(key, { type: "text" });
212
+ return value !== null;
213
+ }
214
+ /**
215
+ * Get or set a value (cache pattern)
216
+ */
217
+ async getOrSet(key, factory, options) {
218
+ const existing = await this.get(key);
219
+ if (existing !== null) {
220
+ return existing;
221
+ }
222
+ const value = await factory();
223
+ await this.set(key, value, options);
224
+ return value;
225
+ }
226
+ /**
227
+ * Increment a numeric value
228
+ */
229
+ async increment(key, delta = 1) {
230
+ const current = await this.get(key);
231
+ const newValue = (current ?? 0) + delta;
232
+ await this.set(key, newValue);
233
+ return newValue;
234
+ }
235
+ /**
236
+ * Decrement a numeric value
237
+ */
238
+ async decrement(key, delta = 1) {
239
+ return this.increment(key, -delta);
240
+ }
241
+ /**
242
+ * Append to an array stored in KV
243
+ */
244
+ async append(key, item, options) {
245
+ const existing = await this.get(key) ?? [];
246
+ existing.push(item);
247
+ await this.set(key, existing, options);
248
+ return existing;
249
+ }
250
+ /**
251
+ * Update a value with a transformer function
252
+ */
253
+ async update(key, updater, options) {
254
+ const current = await this.get(key);
255
+ const updated = updater(current);
256
+ await this.set(key, updated, options);
257
+ return updated;
258
+ }
259
+ };
260
+ KVService = __decorateClass([
261
+ Injectable()
262
+ ], KVService);
263
+ var KVRepository = class {
264
+ constructor(kv, prefix) {
265
+ this.kv = kv;
266
+ this.prefix = prefix;
267
+ }
268
+ /**
269
+ * Build the full key for an entity
270
+ */
271
+ buildKey(id) {
272
+ return `${this.prefix}:${id}`;
273
+ }
274
+ /**
275
+ * Find an entity by ID
276
+ */
277
+ async findById(id) {
278
+ return this.kv.get(this.buildKey(id));
279
+ }
280
+ /**
281
+ * Find an entity by ID with metadata
282
+ */
283
+ async findByIdWithMetadata(id) {
284
+ return this.kv.getWithMetadata(this.buildKey(id));
285
+ }
286
+ /**
287
+ * Save an entity
288
+ */
289
+ async save(id, entity, options) {
290
+ await this.kv.set(this.buildKey(id), entity, options);
291
+ }
292
+ /**
293
+ * Delete an entity
294
+ */
295
+ async delete(id) {
296
+ await this.kv.delete(this.buildKey(id));
297
+ }
298
+ /**
299
+ * Check if an entity exists
300
+ */
301
+ async exists(id) {
302
+ return this.kv.exists(this.buildKey(id));
303
+ }
304
+ /**
305
+ * Get all entity IDs
306
+ */
307
+ async getAllIds() {
308
+ const keys = await this.kv.keys(`${this.prefix}:`);
309
+ return keys.map((k) => k.name.replace(`${this.prefix}:`, ""));
310
+ }
311
+ /**
312
+ * Get all entities
313
+ */
314
+ async findAll() {
315
+ const ids = await this.getAllIds();
316
+ const entities = await Promise.all(ids.map((id) => this.findById(id)));
317
+ return entities.filter((e) => e !== null);
318
+ }
319
+ /**
320
+ * Count entities
321
+ */
322
+ async count() {
323
+ const keys = await this.kv.keys(`${this.prefix}:`);
324
+ return keys.length;
325
+ }
326
+ /**
327
+ * Delete all entities
328
+ */
329
+ async deleteAll() {
330
+ return this.kv.deleteByPrefix(`${this.prefix}:`);
331
+ }
332
+ };
333
+ function InjectKV(binding) {
334
+ return (target, propertyKey, parameterIndex) => {
335
+ const metaKey = `__kv_bindings_${String(propertyKey)}`;
336
+ const existingParams = target[metaKey] ?? [];
337
+ existingParams.push({ index: parameterIndex, binding });
338
+ target[metaKey] = existingParams;
339
+ };
340
+ }
341
+ var KVModule = class {
342
+ /**
343
+ * Configure KV module with static options
344
+ */
345
+ static forRoot(options) {
346
+ return {
347
+ module: KVModule,
348
+ providers: [
349
+ { provide: KV_OPTIONS, useValue: options },
350
+ KVService
351
+ ],
352
+ exports: [KVService, KV_OPTIONS]
353
+ };
354
+ }
355
+ /**
356
+ * Configure KV module with async options
357
+ */
358
+ static forRootAsync(options) {
359
+ return {
360
+ module: KVModule,
361
+ imports: options.imports ?? [],
362
+ providers: [
363
+ {
364
+ provide: KV_OPTIONS,
365
+ useFactory: options.useFactory,
366
+ inject: options.inject
367
+ },
368
+ KVService
369
+ ],
370
+ exports: [KVService, KV_OPTIONS]
371
+ };
372
+ }
373
+ /**
374
+ * Configure KV for a specific feature/namespace
375
+ */
376
+ static forFeature(options) {
377
+ const featureToken = createToken(`KV_${options.binding}`);
378
+ return {
379
+ module: KVModule,
380
+ providers: [
381
+ { provide: featureToken, useClass: KVService },
382
+ { provide: `KV_OPTIONS_${options.binding}`, useValue: options }
383
+ ],
384
+ exports: [featureToken]
385
+ };
386
+ }
387
+ };
388
+ KVModule = __decorateClass([
389
+ Module({})
390
+ ], KVModule);
391
+ function createKVService(namespace, options = {}) {
392
+ const service = new KVService();
393
+ service.initialize(namespace, {
394
+ binding: "custom",
395
+ ...options
396
+ });
397
+ return service;
398
+ }
399
+ function getKVNamespace(env, binding) {
400
+ const namespace = env[binding];
401
+ if (!namespace) {
402
+ throw new Error(`KV namespace '${binding}' not found in environment`);
403
+ }
404
+ return namespace;
405
+ }
406
+
407
+ export { InjectKV, KVModule, KVRepository, KVService, KV_NAMESPACE, KV_OPTIONS, createKVService, getKVNamespace };
408
+ //# sourceMappingURL=index.js.map
409
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * @flareone/kv - Workers KV Integration\r\n * High-level, type-safe wrapper for Cloudflare Workers KV\r\n */\r\n\r\nimport {\r\n Injectable,\r\n Module,\r\n createToken,\r\n type Type,\r\n type DynamicModule,\r\n type InjectionToken,\r\n} from '@flareone/core';\r\n\r\nexport interface KVGetOptions {\r\n type?: 'text' | 'json' | 'arrayBuffer' | 'stream';\r\n cacheTtl?: number;\r\n}\r\n\r\nexport interface KVPutOptions {\r\n expiration?: number;\r\n expirationTtl?: number;\r\n metadata?: Record<string, unknown>;\r\n}\r\n\r\nexport interface KVListOptions {\r\n prefix?: string;\r\n limit?: number;\r\n cursor?: string;\r\n}\r\nexport interface KVListResult<T = unknown> {\r\n keys: Array<{\r\n name: string;\r\n expiration?: number;\r\n metadata?: T;\r\n }>;\r\n list_complete: boolean;\r\n cursor?: string;\r\n}\r\n\r\nexport interface KVValueWithMetadata<T, M = unknown> {\r\n value: T | null;\r\n metadata: M | null;\r\n}\r\n\r\nexport interface KVModuleOptions {\r\n binding: string;\r\n defaultTtl?: number;\r\n keyPrefix?: string;\r\n enableCache?: boolean;\r\n cacheTtl?: number;\r\n}\r\n\r\nexport interface KVModuleAsyncOptions {\r\n imports?: Array<Type | DynamicModule>;\r\n useFactory: (...args: unknown[]) => KVModuleOptions | Promise<KVModuleOptions>;\r\n inject?: InjectionToken[];\r\n}\r\n\r\nexport const KV_OPTIONS = createToken<KVModuleOptions>('KV_OPTIONS');\r\nexport const KV_NAMESPACE = createToken<KVNamespace>('KV_NAMESPACE');\r\n\r\n/**\r\n * High-level KV service with type-safe operations\r\n */\r\n@Injectable()\r\nexport class KVService {\r\n private namespace: KVNamespace | null = null;\r\n private options: KVModuleOptions | null = null;\r\n\r\n /**\r\n * Initialize with KV namespace and options\r\n */\r\n initialize(namespace: KVNamespace, options: KVModuleOptions): void {\r\n this.namespace = namespace;\r\n this.options = options;\r\n }\r\n\r\n /**\r\n * Get the underlying KV namespace\r\n */\r\n getNamespace(): KVNamespace {\r\n if (!this.namespace) {\r\n throw new Error('KV namespace not initialized. Make sure KVModule is properly configured.');\r\n }\r\n return this.namespace;\r\n }\r\n\r\n /**\r\n * Build the full key with optional prefix\r\n */\r\n private buildKey(key: string): string {\r\n return this.options?.keyPrefix ? `${this.options.keyPrefix}${key}` : key;\r\n }\r\n\r\n /**\r\n * Get a value by key\r\n */\r\n async get<T = string>(key: string, options?: KVGetOptions): Promise<T | null> {\r\n const ns = this.getNamespace();\r\n const fullKey = this.buildKey(key);\r\n const type = options?.type ?? 'json';\r\n const cacheTtl = options?.cacheTtl ?? this.options?.cacheTtl;\r\n\r\n const kvOptions: KVNamespaceGetOptions<any> = { type };\r\n if (cacheTtl) {\r\n kvOptions.cacheTtl = cacheTtl;\r\n }\r\n\r\n return ns.get(fullKey, kvOptions) as Promise<T | null>;\r\n }\r\n\r\n /**\r\n * Get a value as text\r\n */\r\n async getText(key: string, cacheTtl?: number): Promise<string | null> {\r\n return this.get<string>(key, { type: 'text', cacheTtl });\r\n }\r\n\r\n /**\r\n * Get a value as JSON\r\n */\r\n async getJson<T>(key: string, cacheTtl?: number): Promise<T | null> {\r\n return this.get<T>(key, { type: 'json', cacheTtl });\r\n }\r\n\r\n /**\r\n * Get a value as ArrayBuffer\r\n */\r\n async getArrayBuffer(key: string, cacheTtl?: number): Promise<ArrayBuffer | null> {\r\n return this.get<ArrayBuffer>(key, { type: 'arrayBuffer', cacheTtl });\r\n }\r\n\r\n /**\r\n * Get a value as ReadableStream\r\n */\r\n async getStream(key: string, cacheTtl?: number): Promise<ReadableStream | null> {\r\n return this.get<ReadableStream>(key, { type: 'stream', cacheTtl });\r\n }\r\n\r\n /**\r\n * Get a value with its metadata\r\n */\r\n async getWithMetadata<T = unknown, M = unknown>(\r\n key: string,\r\n type: 'text' | 'json' | 'arrayBuffer' | 'stream' = 'json'\r\n ): Promise<KVValueWithMetadata<T, M>> {\r\n const ns = this.getNamespace();\r\n const fullKey = this.buildKey(key);\r\n const result = await (ns.getWithMetadata as (key: string, options: { type: string }) => Promise<{ value: unknown; metadata: unknown }>)(fullKey, { type });\r\n return {\r\n value: result.value as T | null,\r\n metadata: result.metadata as M | null,\r\n };\r\n }\r\n\r\n /**\r\n * Set a value\r\n */\r\n async set<T = unknown>(\r\n key: string,\r\n value: T,\r\n options?: KVPutOptions\r\n ): Promise<void> {\r\n const ns = this.getNamespace();\r\n const fullKey = this.buildKey(key);\r\n\r\n const serialized = typeof value === 'string' ? value : JSON.stringify(value);\r\n\r\n const kvOptions: KVNamespacePutOptions = {};\r\n if (options?.expiration) {\r\n kvOptions.expiration = options.expiration;\r\n }\r\n if (options?.expirationTtl ?? this.options?.defaultTtl) {\r\n kvOptions.expirationTtl = options?.expirationTtl ?? this.options?.defaultTtl;\r\n }\r\n if (options?.metadata) {\r\n kvOptions.metadata = options.metadata;\r\n }\r\n\r\n await ns.put(fullKey, serialized, kvOptions);\r\n }\r\n\r\n /**\r\n * Set multiple values at once\r\n */\r\n async setMany<T = unknown>(\r\n entries: Array<{ key: string; value: T; options?: KVPutOptions }>\r\n ): Promise<void> {\r\n await Promise.all(\r\n entries.map(({ key, value, options }) => this.set(key, value, options))\r\n );\r\n }\r\n\r\n /**\r\n * Set a value with automatic JSON serialization\r\n */\r\n async setJson<T>(key: string, value: T, options?: KVPutOptions): Promise<void> {\r\n return this.set(key, value, options);\r\n }\r\n\r\n /**\r\n * Set a value as raw text\r\n */\r\n async setText(key: string, value: string, options?: KVPutOptions): Promise<void> {\r\n const ns = this.getNamespace();\r\n const fullKey = this.buildKey(key);\r\n\r\n const kvOptions: KVNamespacePutOptions = {};\r\n if (options?.expiration) kvOptions.expiration = options.expiration;\r\n if (options?.expirationTtl ?? this.options?.defaultTtl) {\r\n kvOptions.expirationTtl = options?.expirationTtl ?? this.options?.defaultTtl;\r\n }\r\n if (options?.metadata) kvOptions.metadata = options.metadata;\r\n\r\n await ns.put(fullKey, value, kvOptions);\r\n }\r\n\r\n /**\r\n * Set a value as ArrayBuffer\r\n */\r\n async setArrayBuffer(\r\n key: string,\r\n value: ArrayBuffer,\r\n options?: KVPutOptions\r\n ): Promise<void> {\r\n const ns = this.getNamespace();\r\n const fullKey = this.buildKey(key);\r\n\r\n const kvOptions: KVNamespacePutOptions = {};\r\n if (options?.expiration) kvOptions.expiration = options.expiration;\r\n if (options?.expirationTtl ?? this.options?.defaultTtl) {\r\n kvOptions.expirationTtl = options?.expirationTtl ?? this.options?.defaultTtl;\r\n }\r\n if (options?.metadata) kvOptions.metadata = options.metadata;\r\n\r\n await ns.put(fullKey, value, kvOptions);\r\n }\r\n\r\n /**\r\n * Delete a key\r\n */\r\n async delete(key: string): Promise<void> {\r\n const ns = this.getNamespace();\r\n const fullKey = this.buildKey(key);\r\n await ns.delete(fullKey);\r\n }\r\n\r\n /**\r\n * Delete multiple keys\r\n */\r\n async deleteMany(keys: string[]): Promise<void> {\r\n await Promise.all(keys.map((key) => this.delete(key)));\r\n }\r\n\r\n /**\r\n * Delete all keys with a prefix\r\n */\r\n async deleteByPrefix(prefix: string): Promise<number> {\r\n const keys = await this.keys(prefix);\r\n await this.deleteMany(keys.map((k) => k.name));\r\n return keys.length;\r\n }\r\n\r\n /**\r\n * List keys\r\n */\r\n async list<M = unknown>(options?: KVListOptions): Promise<KVListResult<M>> {\r\n const ns = this.getNamespace();\r\n\r\n const kvOptions: KVNamespaceListOptions = {};\r\n if (options?.prefix) {\r\n kvOptions.prefix = this.buildKey(options.prefix);\r\n }\r\n if (options?.limit) {\r\n kvOptions.limit = options.limit;\r\n }\r\n if (options?.cursor) {\r\n kvOptions.cursor = options.cursor;\r\n }\r\n\r\n return ns.list(kvOptions) as Promise<KVListResult<M>>;\r\n }\r\n\r\n /**\r\n * Get all keys (handles pagination automatically)\r\n */\r\n async keys<M = unknown>(prefix?: string): Promise<Array<{ name: string; metadata?: M }>> {\r\n const allKeys: Array<{ name: string; metadata?: M }> = [];\r\n let cursor: string | undefined;\r\n let complete = false;\r\n\r\n while (!complete) {\r\n const result = await this.list<M>({\r\n prefix,\r\n cursor,\r\n limit: 1000,\r\n });\r\n\r\n allKeys.push(...result.keys);\r\n complete = result.list_complete;\r\n cursor = result.cursor;\r\n }\r\n\r\n return allKeys;\r\n }\r\n\r\n /**\r\n * Check if a key exists\r\n */\r\n async exists(key: string): Promise<boolean> {\r\n const value = await this.get(key, { type: 'text' });\r\n return value !== null;\r\n }\r\n\r\n /**\r\n * Get or set a value (cache pattern)\r\n */\r\n async getOrSet<T>(\r\n key: string,\r\n factory: () => T | Promise<T>,\r\n options?: KVPutOptions\r\n ): Promise<T> {\r\n const existing = await this.get<T>(key);\r\n if (existing !== null) {\r\n return existing;\r\n }\r\n\r\n const value = await factory();\r\n await this.set(key, value, options);\r\n return value;\r\n }\r\n\r\n /**\r\n * Increment a numeric value\r\n */\r\n async increment(key: string, delta: number = 1): Promise<number> {\r\n const current = await this.get<number>(key);\r\n const newValue = (current ?? 0) + delta;\r\n await this.set(key, newValue);\r\n return newValue;\r\n }\r\n\r\n /**\r\n * Decrement a numeric value\r\n */\r\n async decrement(key: string, delta: number = 1): Promise<number> {\r\n return this.increment(key, -delta);\r\n }\r\n\r\n /**\r\n * Append to an array stored in KV\r\n */\r\n async append<T>(key: string, item: T, options?: KVPutOptions): Promise<T[]> {\r\n const existing = await this.get<T[]>(key) ?? [];\r\n existing.push(item);\r\n await this.set(key, existing, options);\r\n return existing;\r\n }\r\n\r\n /**\r\n * Update a value with a transformer function\r\n */\r\n async update<T>(\r\n key: string,\r\n updater: (current: T | null) => T,\r\n options?: KVPutOptions\r\n ): Promise<T> {\r\n const current = await this.get<T>(key);\r\n const updated = updater(current);\r\n await this.set(key, updated, options);\r\n return updated;\r\n }\r\n}\r\n\r\n/**\r\n * Base class for creating typed KV repositories\r\n */\r\nexport abstract class KVRepository<T, M = unknown> {\r\n constructor(\r\n protected readonly kv: KVService,\r\n protected readonly prefix: string\r\n ) { }\r\n\r\n /**\r\n * Build the full key for an entity\r\n */\r\n protected buildKey(id: string): string {\r\n return `${this.prefix}:${id}`;\r\n }\r\n\r\n /**\r\n * Find an entity by ID\r\n */\r\n async findById(id: string): Promise<T | null> {\r\n return this.kv.get<T>(this.buildKey(id));\r\n }\r\n\r\n /**\r\n * Find an entity by ID with metadata\r\n */\r\n async findByIdWithMetadata(id: string): Promise<KVValueWithMetadata<T, M>> {\r\n return this.kv.getWithMetadata<T, M>(this.buildKey(id));\r\n }\r\n\r\n /**\r\n * Save an entity\r\n */\r\n async save(id: string, entity: T, options?: KVPutOptions): Promise<void> {\r\n await this.kv.set(this.buildKey(id), entity, options);\r\n }\r\n\r\n /**\r\n * Delete an entity\r\n */\r\n async delete(id: string): Promise<void> {\r\n await this.kv.delete(this.buildKey(id));\r\n }\r\n\r\n /**\r\n * Check if an entity exists\r\n */\r\n async exists(id: string): Promise<boolean> {\r\n return this.kv.exists(this.buildKey(id));\r\n }\r\n\r\n /**\r\n * Get all entity IDs\r\n */\r\n async getAllIds(): Promise<string[]> {\r\n const keys = await this.kv.keys(`${this.prefix}:`);\r\n return keys.map((k) => k.name.replace(`${this.prefix}:`, ''));\r\n }\r\n\r\n /**\r\n * Get all entities\r\n */\r\n async findAll(): Promise<T[]> {\r\n const ids = await this.getAllIds();\r\n const entities = await Promise.all(ids.map((id) => this.findById(id)));\r\n return entities.filter((e): e is NonNullable<typeof e> => e !== null) as T[];\r\n }\r\n\r\n /**\r\n * Count entities\r\n */\r\n async count(): Promise<number> {\r\n const keys = await this.kv.keys(`${this.prefix}:`);\r\n return keys.length;\r\n }\r\n\r\n /**\r\n * Delete all entities\r\n */\r\n async deleteAll(): Promise<number> {\r\n return this.kv.deleteByPrefix(`${this.prefix}:`);\r\n }\r\n}\r\n\r\n/**\r\n * Parameter decorator to inject KV namespace directly\r\n */\r\nexport function InjectKV(binding: string): ParameterDecorator {\r\n return (target, propertyKey, parameterIndex) => {\r\n const metaKey = `__kv_bindings_${String(propertyKey)}`;\r\n const existingParams = (target as Record<string, unknown>)[metaKey] as Array<{ index: number; binding: string }> ?? [];\r\n existingParams.push({ index: parameterIndex, binding });\r\n (target as Record<string, unknown>)[metaKey] = existingParams;\r\n };\r\n}\r\n\r\n/**\r\n * KV Module for Flareone\r\n */\r\n@Module({})\r\nexport class KVModule {\r\n /**\r\n * Configure KV module with static options\r\n */\r\n static forRoot(options: KVModuleOptions): DynamicModule {\r\n return {\r\n module: KVModule,\r\n providers: [\r\n { provide: KV_OPTIONS, useValue: options },\r\n KVService,\r\n ],\r\n exports: [KVService, KV_OPTIONS],\r\n };\r\n }\r\n\r\n /**\r\n * Configure KV module with async options\r\n */\r\n static forRootAsync(options: KVModuleAsyncOptions): DynamicModule {\r\n return {\r\n module: KVModule,\r\n imports: options.imports ?? [],\r\n providers: [\r\n {\r\n provide: KV_OPTIONS,\r\n useFactory: options.useFactory,\r\n inject: options.inject,\r\n },\r\n KVService,\r\n ],\r\n exports: [KVService, KV_OPTIONS],\r\n };\r\n }\r\n\r\n /**\r\n * Configure KV for a specific feature/namespace\r\n */\r\n static forFeature(options: KVModuleOptions): DynamicModule {\r\n const featureToken = createToken<KVService>(`KV_${options.binding}`);\r\n\r\n return {\r\n module: KVModule,\r\n providers: [\r\n { provide: featureToken, useClass: KVService },\r\n { provide: `KV_OPTIONS_${options.binding}`, useValue: options },\r\n ],\r\n exports: [featureToken],\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Create a KV service for a specific namespace\r\n */\r\nexport function createKVService(\r\n namespace: KVNamespace,\r\n options: Partial<KVModuleOptions> = {}\r\n): KVService {\r\n const service = new KVService();\r\n service.initialize(namespace, {\r\n binding: 'custom',\r\n ...options,\r\n });\r\n return service;\r\n}\r\n\r\n/**\r\n * Helper to get KV namespace from environment\r\n */\r\nexport function getKVNamespace(env: Record<string, unknown>, binding: string): KVNamespace {\r\n const namespace = env[binding] as KVNamespace | undefined;\r\n if (!namespace) {\r\n throw new Error(`KV namespace '${binding}' not found in environment`);\r\n }\r\n return namespace;\r\n}\r\n"]}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@flareone/kv",
3
+ "version": "0.1.0",
4
+ "description": "Workers KV integration for Flareone framework",
5
+ "keywords": [
6
+ "cloudflare",
7
+ "workers",
8
+ "kv",
9
+ "flareon",
10
+ "key-value",
11
+ "storage"
12
+ ],
13
+ "homepage": "https://flareone.dev",
14
+ "license": "MIT",
15
+ "author": "Flareone Contributors",
16
+ "type": "module",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js"
21
+ }
22
+ },
23
+ "main": "./dist/index.js",
24
+ "types": "./dist/index.d.ts",
25
+ "files": [
26
+ "dist",
27
+ "README.md"
28
+ ],
29
+ "dependencies": {
30
+ "@flareone/core": "0.1.0"
31
+ },
32
+ "devDependencies": {
33
+ "@cloudflare/workers-types": "^4.20250109.0",
34
+ "rimraf": "^6.0.0",
35
+ "tsup": "^8.3.0",
36
+ "typescript": "^5.7.0"
37
+ },
38
+ "sideEffects": false,
39
+ "scripts": {
40
+ "build": "tsup",
41
+ "clean": "rimraf dist",
42
+ "dev": "tsup --watch",
43
+ "typecheck": "tsc --noEmit"
44
+ }
45
+ }