@uploadista/kv-store-memory 0.0.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.
@@ -0,0 +1,5 @@
1
+
2
+ 
3
+ > @uploadista/kv-store-memory@0.0.2 build /Users/denislaboureyras/Documents/uploadista/dev/uploadista-workspace/uploadista-sdk/packages/kv-stores/memory
4
+ > tsc -b
5
+
@@ -0,0 +1,5 @@
1
+
2
+ > @uploadista/kv-store-memory@ check /Users/denislaboureyras/Documents/uploadista/dev/uploadista/packages/uploadista/kv-stores/memory
3
+ > biome check --write ./src
4
+
5
+ Checked 2 files in 26ms. No fixes applied.
File without changes
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 uploadista
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,332 @@
1
+ # @uploadista/kv-store-memory
2
+
3
+ In-memory key-value store for Uploadista. Perfect for development, testing, and single-process deployments.
4
+
5
+ ## Overview
6
+
7
+ The memory KV store provides a simple, synchronous in-memory storage backend using JavaScript Maps. It's designed for:
8
+
9
+ - **Development**: Instant setup, no external dependencies
10
+ - **Testing**: Predictable behavior, no network latency
11
+ - **Single-Process Servers**: Single-machine deployments without state sharing
12
+ - **Prototyping**: Quick proof-of-concepts
13
+
14
+ All data is stored in RAM and will be lost when the process exits. For persistent or distributed storage, use [Redis](#see-also), [Cloudflare KV](#see-also), or [Filesystem](#see-also) stores.
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @uploadista/kv-store-memory
20
+ # or
21
+ pnpm add @uploadista/kv-store-memory
22
+ ```
23
+
24
+ ### Prerequisites
25
+
26
+ - Node.js 18+ (JavaScript runtime)
27
+ - No external services required
28
+
29
+ ## Quick Start
30
+
31
+ ```typescript
32
+ import { memoryKvStore } from "@uploadista/kv-store-memory";
33
+ import { Effect } from "effect";
34
+
35
+ // Use the memory store layer directly
36
+ const program = Effect.gen(function* () {
37
+ // The memoryKvStore layer is already configured
38
+ // No additional setup needed
39
+ });
40
+
41
+ // Run with the memory store
42
+ Effect.runSync(program.pipe(Effect.provide(memoryKvStore)));
43
+ ```
44
+
45
+ ## Features
46
+
47
+ - ✅ **Zero Setup**: Works out of the box with no configuration
48
+ - ✅ **Synchronous Operations**: Fast in-memory access (~1μs per operation)
49
+ - ✅ **Pattern Matching**: Prefix-based key listing for batch operations
50
+ - ✅ **Effect-TS Integration**: Full async/error handling with Effect
51
+ - ✅ **Type Safe**: Full TypeScript support with strict typing
52
+
53
+ ## API Reference
54
+
55
+ ### Main Exports
56
+
57
+ #### `memoryKvStore: Layer<BaseKvStoreService>`
58
+
59
+ Pre-configured Effect layer providing the `BaseKvStoreService` with in-memory storage.
60
+
61
+ ```typescript
62
+ import { memoryKvStore } from "@uploadista/kv-store-memory";
63
+ import { Effect, Layer } from "effect";
64
+
65
+ const layer = memoryKvStore;
66
+ // Type: Layer<never, never, BaseKvStoreService>
67
+ ```
68
+
69
+ #### `makeMemoryBaseKvStore(): BaseKvStore`
70
+
71
+ Factory function to create a new memory KV store instance. Useful for creating multiple isolated stores.
72
+
73
+ ```typescript
74
+ import { makeMemoryBaseKvStore } from "@uploadista/kv-store-memory";
75
+
76
+ const store = makeMemoryBaseKvStore();
77
+ const value = store.get("key"); // Effect<string | null>
78
+ ```
79
+
80
+ ### Available Operations
81
+
82
+ The memory store implements the `BaseKvStore` interface:
83
+
84
+ #### `get(key: string): Effect<string | null>`
85
+
86
+ Retrieve a value by key. Returns `null` if key doesn't exist.
87
+
88
+ ```typescript
89
+ const program = Effect.gen(function* () {
90
+ const value = yield* store.get("user:123");
91
+ // value is either a string or null
92
+ });
93
+ ```
94
+
95
+ #### `set(key: string, value: string): Effect<void>`
96
+
97
+ Store a string value. Overwrites existing value if key exists.
98
+
99
+ ```typescript
100
+ const program = Effect.gen(function* () {
101
+ yield* store.set("user:123", JSON.stringify({ name: "Alice" }));
102
+ });
103
+ ```
104
+
105
+ #### `delete(key: string): Effect<void>`
106
+
107
+ Remove a key. Safe to call on non-existent keys (no-op).
108
+
109
+ ```typescript
110
+ const program = Effect.gen(function* () {
111
+ yield* store.delete("user:123");
112
+ });
113
+ ```
114
+
115
+ #### `list(keyPrefix: string): Effect<string[]>`
116
+
117
+ List all keys matching a prefix. Returns array of key names (without prefix).
118
+
119
+ ```typescript
120
+ const program = Effect.gen(function* () {
121
+ const keys = yield* store.list("user:");
122
+ // Returns: ["123", "456", "789"] for keys ["user:123", "user:456", "user:789"]
123
+ });
124
+ ```
125
+
126
+ ## Configuration
127
+
128
+ The memory store requires no configuration. Simply import and use:
129
+
130
+ ```typescript
131
+ import { memoryKvStore } from "@uploadista/kv-store-memory";
132
+ import { uploadServer } from "@uploadista/server";
133
+ import { Effect } from "effect";
134
+
135
+ const program = Effect.gen(function* () {
136
+ const server = yield* uploadServer;
137
+ // Store is automatically available
138
+ });
139
+
140
+ Effect.runSync(
141
+ program.pipe(
142
+ Effect.provide(memoryKvStore),
143
+ // ... other layers
144
+ )
145
+ );
146
+ ```
147
+
148
+ ## Examples
149
+
150
+ ### Example 1: Upload Session Storage
151
+
152
+ Store and retrieve upload file metadata:
153
+
154
+ ```typescript
155
+ import { makeMemoryBaseKvStore } from "@uploadista/kv-store-memory";
156
+ import { Effect } from "effect";
157
+
158
+ const store = makeMemoryBaseKvStore();
159
+
160
+ interface UploadMetadata {
161
+ filename: string;
162
+ size: number;
163
+ uploadedAt: string;
164
+ }
165
+
166
+ const program = Effect.gen(function* () {
167
+ // Store metadata
168
+ const metadata: UploadMetadata = {
169
+ filename: "document.pdf",
170
+ size: 2097152,
171
+ uploadedAt: new Date().toISOString(),
172
+ };
173
+
174
+ yield* store.set("upload:abc123", JSON.stringify(metadata));
175
+
176
+ // Retrieve metadata
177
+ const stored = yield* store.get("upload:abc123");
178
+ const parsed = stored ? JSON.parse(stored) : null;
179
+ console.log(parsed);
180
+ // { filename: "document.pdf", size: 2097152, uploadedAt: "2025-10-21T..." }
181
+ });
182
+
183
+ Effect.runSync(program);
184
+ ```
185
+
186
+ ### Example 2: Batch Operations
187
+
188
+ List and process multiple keys:
189
+
190
+ ```typescript
191
+ import { makeMemoryBaseKvStore } from "@uploadista/kv-store-memory";
192
+ import { Effect } from "effect";
193
+
194
+ const store = makeMemoryBaseKvStore();
195
+
196
+ const program = Effect.gen(function* () {
197
+ // Store multiple items
198
+ yield* store.set("session:user1", JSON.stringify({ token: "abc" }));
199
+ yield* store.set("session:user2", JSON.stringify({ token: "def" }));
200
+ yield* store.set("session:user3", JSON.stringify({ token: "ghi" }));
201
+
202
+ // List all sessions
203
+ const sessionKeys = yield* store.list("session:");
204
+ console.log(sessionKeys); // ["user1", "user2", "user3"]
205
+
206
+ // Process each session
207
+ for (const key of sessionKeys) {
208
+ const fullKey = `session:${key}`;
209
+ const data = yield* store.get(fullKey);
210
+ console.log(`${fullKey}: ${data}`);
211
+ }
212
+ });
213
+
214
+ Effect.runSync(program);
215
+ ```
216
+
217
+ ### Example 3: Error Handling
218
+
219
+ Memory store operations rarely fail, but always handle effects properly:
220
+
221
+ ```typescript
222
+ import { makeMemoryBaseKvStore } from "@uploadista/kv-store-memory";
223
+ import { Effect } from "effect";
224
+
225
+ const store = makeMemoryBaseKvStore();
226
+
227
+ const program = Effect.gen(function* () {
228
+ const value = yield* store.get("key");
229
+
230
+ if (value === null) {
231
+ console.log("Key not found, using default");
232
+ yield* store.set("key", "default-value");
233
+ } else {
234
+ console.log("Value:", value);
235
+ }
236
+ });
237
+
238
+ Effect.runSync(program);
239
+ ```
240
+
241
+ ## Limitations
242
+
243
+ - **No Persistence**: Data is lost when the process exits
244
+ - **Single-Process Only**: Not suitable for distributed systems
245
+ - **No TTL/Expiration**: Values persist until explicitly deleted
246
+ - **Memory Growth**: No automatic cleanup; responsibility falls to application
247
+ - **No Transactions**: Individual operations are atomic, but multi-step operations are not
248
+
249
+ ## Use Cases
250
+
251
+ ✅ **Perfect For**:
252
+ - Local development and testing
253
+ - Prototype and MVP applications
254
+ - Single-server deployments (same machine)
255
+ - Unit/integration tests with fast execution
256
+
257
+ ❌ **Not Recommended For**:
258
+ - Distributed/clustered systems (use [Redis](#see-also) instead)
259
+ - Applications requiring data persistence (use [Filesystem](#see-also) or [Azure](#see-also))
260
+ - High-memory applications with millions of keys
261
+ - Serverless/edge deployments (use [Cloudflare KV](#see-also))
262
+
263
+ ## Performance Characteristics
264
+
265
+ | Operation | Latency | Scaling |
266
+ |-----------|---------|---------|
267
+ | get() | ~1μs | O(1) |
268
+ | set() | ~1μs | O(1) |
269
+ | delete() | ~1μs | O(1) |
270
+ | list() | ~100μs | O(n) where n = matching keys |
271
+
272
+ Memory usage is proportional to total data stored. 1MB of data ≈ 1MB RAM.
273
+
274
+ ## Related Packages
275
+
276
+ - [@uploadista/core](../../core) - Core types and interfaces
277
+ - [@uploadista/kv-store-redis](../redis) - Distributed Redis store
278
+ - [@uploadista/kv-store-ioredis](../ioredis) - IORedis with clustering
279
+ - [@uploadista/kv-store-cloudflare-kv](../cloudflare-kv) - Edge-deployed KV
280
+ - [@uploadista/kv-store-filesystem](../filesystem) - Persistent file-based store
281
+ - [@uploadista/server](../../servers/server) - Upload server using KV stores
282
+
283
+ ## Troubleshooting
284
+
285
+ ### Data Lost After Process Restart
286
+
287
+ This is expected behavior. Memory stores are ephemeral by design. For persistent storage:
288
+
289
+ ```typescript
290
+ // Use filesystem store instead
291
+ import { fileKvStore } from "@uploadista/kv-store-filesystem";
292
+
293
+ const layer = fileKvStore({ directory: "./data" });
294
+ ```
295
+
296
+ ### Out of Memory Errors
297
+
298
+ If handling massive files or many concurrent uploads, memory may be exhausted. Solutions:
299
+
300
+ 1. **Reduce In-Flight Uploads**: Implement rate limiting at the upload endpoint
301
+ 2. **Use Streaming**: Implement chunked uploads to avoid buffering entire files
302
+ 3. **Switch to Persistent Store**: Use Redis or Filesystem for external state management
303
+
304
+ ```typescript
305
+ // Monitor memory usage
306
+ console.log(process.memoryUsage());
307
+ // { rss: 45MB, heapTotal: 30MB, heapUsed: 20MB, external: 5MB }
308
+ ```
309
+
310
+ ### Multiple Instances Share Data?
311
+
312
+ Each `makeMemoryBaseKvStore()` call creates an isolated store. To share state:
313
+
314
+ ```typescript
315
+ // These are separate stores - data doesn't cross
316
+ const store1 = makeMemoryBaseKvStore();
317
+ const store2 = makeMemoryBaseKvStore();
318
+
319
+ // Use a single instance across your app
320
+ const sharedStore = makeMemoryBaseKvStore();
321
+ export { sharedStore };
322
+ ```
323
+
324
+ ## License
325
+
326
+ See [LICENSE](../../../LICENSE) in the main repository.
327
+
328
+ ## See Also
329
+
330
+ - [KV Stores Comparison Guide](../KV_STORES_COMPARISON.md) - Compare all KV store options
331
+ - [Server Setup Guide](../../../SERVER_SETUP.md) - Using KV stores in production servers
332
+ - [Effect-TS Documentation](https://effect.website/) - Learn Effect patterns used throughout
@@ -0,0 +1,2 @@
1
+ export * from "./memory-kv-store";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export * from "./memory-kv-store";
@@ -0,0 +1,5 @@
1
+ import { type BaseKvStore, BaseKvStoreService } from "@uploadista/core/types";
2
+ import { Layer } from "effect";
3
+ export declare function makeMemoryBaseKvStore(): BaseKvStore;
4
+ export declare const memoryKvStore: Layer.Layer<BaseKvStoreService, never, never>;
5
+ //# sourceMappingURL=memory-kv-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-kv-store.d.ts","sourceRoot":"","sources":["../src/memory-kv-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC9E,OAAO,EAAU,KAAK,EAAE,MAAM,QAAQ,CAAC;AAGvC,wBAAgB,qBAAqB,IAAI,WAAW,CAqBnD;AAGD,eAAO,MAAM,aAAa,+CAGzB,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { BaseKvStoreService } from "@uploadista/core/types";
2
+ import { Effect, Layer } from "effect";
3
+ // Base memory store that stores raw strings
4
+ export function makeMemoryBaseKvStore() {
5
+ const data = new Map();
6
+ return {
7
+ get: (key) => {
8
+ const value = data.get(key);
9
+ return Effect.succeed(value ?? null);
10
+ },
11
+ set: (key, value) => {
12
+ data.set(key, value);
13
+ return Effect.succeed(void 0);
14
+ },
15
+ delete: (key) => {
16
+ data.delete(key);
17
+ return Effect.succeed(void 0);
18
+ },
19
+ list: (keyPrefix) => {
20
+ return Effect.succeed(Array.from(data.keys()).filter((key) => key.startsWith(keyPrefix)));
21
+ },
22
+ };
23
+ }
24
+ // Base store layer
25
+ export const memoryKvStore = Layer.succeed(BaseKvStoreService, makeMemoryBaseKvStore());
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@uploadista/kv-store-memory",
3
+ "type": "module",
4
+ "version": "0.0.3",
5
+ "description": "Memory KV store for Uploadista",
6
+ "license": "MIT",
7
+ "author": "Uploadista",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "dependencies": {
16
+ "effect": "3.18.4",
17
+ "@uploadista/core": "0.0.3"
18
+ },
19
+ "devDependencies": {
20
+ "@uploadista/typescript-config": "0.0.3"
21
+ },
22
+ "scripts": {
23
+ "build": "tsc -b",
24
+ "format": "biome format --write ./src",
25
+ "lint": "biome lint --write ./src",
26
+ "check": "biome check --write ./src"
27
+ }
28
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./memory-kv-store";
@@ -0,0 +1,32 @@
1
+ import { type BaseKvStore, BaseKvStoreService } from "@uploadista/core/types";
2
+ import { Effect, Layer } from "effect";
3
+
4
+ // Base memory store that stores raw strings
5
+ export function makeMemoryBaseKvStore(): BaseKvStore {
6
+ const data: Map<string, string> = new Map();
7
+ return {
8
+ get: (key: string) => {
9
+ const value = data.get(key);
10
+ return Effect.succeed(value ?? null);
11
+ },
12
+ set: (key: string, value: string) => {
13
+ data.set(key, value);
14
+ return Effect.succeed(void 0);
15
+ },
16
+ delete: (key: string) => {
17
+ data.delete(key);
18
+ return Effect.succeed(void 0);
19
+ },
20
+ list: (keyPrefix: string) => {
21
+ return Effect.succeed(
22
+ Array.from(data.keys()).filter((key) => key.startsWith(keyPrefix)),
23
+ );
24
+ },
25
+ };
26
+ }
27
+
28
+ // Base store layer
29
+ export const memoryKvStore = Layer.succeed(
30
+ BaseKvStoreService,
31
+ makeMemoryBaseKvStore(),
32
+ );
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": "@uploadista/typescript-config/server.json",
3
+ "compilerOptions": {
4
+ "baseUrl": "./",
5
+ "paths": {
6
+ "@/*": ["./src/*"]
7
+ },
8
+ "outDir": "./dist",
9
+ "rootDir": "./src",
10
+ "typeRoots": ["../../../../node_modules/@types"]
11
+ },
12
+ "include": ["src"]
13
+ }
@@ -0,0 +1 @@
1
+ {"root":["./src/index.ts","./src/memory-kv-store.ts"],"version":"5.9.3"}