@workglow/storage 0.0.85 → 0.0.87
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 +185 -53
- package/dist/browser.js +451 -188
- package/dist/browser.js.map +21 -18
- package/dist/bun.js +1069 -356
- package/dist/bun.js.map +29 -24
- package/dist/common-server.d.ts +17 -15
- package/dist/common-server.d.ts.map +1 -1
- package/dist/common.d.ts +13 -10
- package/dist/common.d.ts.map +1 -1
- package/dist/kv/{FsFolderJsonKvRepository.d.ts → FsFolderJsonKvStorage.d.ts} +8 -8
- package/dist/kv/FsFolderJsonKvStorage.d.ts.map +1 -0
- package/dist/kv/{FsFolderKvRepository.d.ts → FsFolderKvStorage.d.ts} +7 -7
- package/dist/kv/FsFolderKvStorage.d.ts.map +1 -0
- package/dist/kv/{IKvRepository.d.ts → IKvStorage.d.ts} +3 -3
- package/dist/kv/IKvStorage.d.ts.map +1 -0
- package/dist/kv/{InMemoryKvRepository.d.ts → InMemoryKvStorage.d.ts} +8 -8
- package/dist/kv/InMemoryKvStorage.d.ts.map +1 -0
- package/dist/kv/{IndexedDbKvRepository.d.ts → IndexedDbKvStorage.d.ts} +8 -8
- package/dist/kv/IndexedDbKvStorage.d.ts.map +1 -0
- package/dist/kv/{KvRepository.d.ts → KvStorage.d.ts} +7 -7
- package/dist/kv/KvStorage.d.ts.map +1 -0
- package/dist/kv/{KvViaTabularRepository.d.ts → KvViaTabularStorage.d.ts} +7 -7
- package/dist/kv/KvViaTabularStorage.d.ts.map +1 -0
- package/dist/kv/{PostgresKvRepository.d.ts → PostgresKvStorage.d.ts} +8 -8
- package/dist/kv/PostgresKvStorage.d.ts.map +1 -0
- package/dist/kv/{SqliteKvRepository.d.ts → SqliteKvStorage.d.ts} +8 -8
- package/dist/kv/SqliteKvStorage.d.ts.map +1 -0
- package/dist/kv/{SupabaseKvRepository.d.ts → SupabaseKvStorage.d.ts} +9 -9
- package/dist/kv/SupabaseKvStorage.d.ts.map +1 -0
- package/dist/node.js +1069 -356
- package/dist/node.js.map +29 -24
- package/dist/queue-limiter/IRateLimiterStorage.d.ts.map +1 -0
- package/dist/queue-limiter/InMemoryRateLimiterStorage.d.ts.map +1 -0
- package/dist/queue-limiter/IndexedDbRateLimiterStorage.d.ts.map +1 -0
- package/dist/queue-limiter/PostgresRateLimiterStorage.d.ts.map +1 -0
- package/dist/queue-limiter/SqliteRateLimiterStorage.d.ts.map +1 -0
- package/dist/queue-limiter/SupabaseRateLimiterStorage.d.ts.map +1 -0
- package/dist/tabular/{BaseSqlTabularRepository.d.ts → BaseSqlTabularStorage.d.ts} +8 -7
- package/dist/tabular/BaseSqlTabularStorage.d.ts.map +1 -0
- package/dist/tabular/{TabularRepository.d.ts → BaseTabularStorage.d.ts} +52 -10
- package/dist/tabular/BaseTabularStorage.d.ts.map +1 -0
- package/dist/tabular/{CachedTabularRepository.d.ts → CachedTabularStorage.d.ts} +15 -14
- package/dist/tabular/CachedTabularStorage.d.ts.map +1 -0
- package/dist/tabular/{FsFolderTabularRepository.d.ts → FsFolderTabularStorage.d.ts} +22 -12
- package/dist/tabular/FsFolderTabularStorage.d.ts.map +1 -0
- package/dist/tabular/{ITabularRepository.d.ts → ITabularStorage.d.ts} +29 -6
- package/dist/tabular/ITabularStorage.d.ts.map +1 -0
- package/dist/tabular/{InMemoryTabularRepository.d.ts → InMemoryTabularStorage.d.ts} +24 -14
- package/dist/tabular/InMemoryTabularStorage.d.ts.map +1 -0
- package/dist/tabular/{IndexedDbTabularRepository.d.ts → IndexedDbTabularStorage.d.ts} +20 -11
- package/dist/tabular/IndexedDbTabularStorage.d.ts.map +1 -0
- package/dist/tabular/{PostgresTabularRepository.d.ts → PostgresTabularStorage.d.ts} +37 -15
- package/dist/tabular/PostgresTabularStorage.d.ts.map +1 -0
- package/dist/tabular/{SharedInMemoryTabularRepository.d.ts → SharedInMemoryTabularStorage.d.ts} +14 -13
- package/dist/tabular/SharedInMemoryTabularStorage.d.ts.map +1 -0
- package/dist/tabular/{SqliteTabularRepository.d.ts → SqliteTabularStorage.d.ts} +25 -11
- package/dist/tabular/SqliteTabularStorage.d.ts.map +1 -0
- package/dist/tabular/{SupabaseTabularRepository.d.ts → SupabaseTabularStorage.d.ts} +17 -15
- package/dist/tabular/SupabaseTabularStorage.d.ts.map +1 -0
- package/dist/tabular/TabularStorageRegistry.d.ts +29 -0
- package/dist/tabular/TabularStorageRegistry.d.ts.map +1 -0
- package/dist/util/IndexedDbTable.d.ts +1 -1
- package/dist/util/IndexedDbTable.d.ts.map +1 -1
- package/dist/vector/IVectorStorage.d.ts +83 -0
- package/dist/vector/IVectorStorage.d.ts.map +1 -0
- package/dist/vector/InMemoryVectorStorage.d.ts +41 -0
- package/dist/vector/InMemoryVectorStorage.d.ts.map +1 -0
- package/dist/vector/PostgresVectorStorage.d.ts +57 -0
- package/dist/vector/PostgresVectorStorage.d.ts.map +1 -0
- package/dist/vector/SqliteVectorStorage.d.ts +45 -0
- package/dist/vector/SqliteVectorStorage.d.ts.map +1 -0
- package/package.json +7 -7
- package/src/kv/README.md +3 -3
- package/src/tabular/README.md +186 -23
- package/src/vector/README.md +393 -0
- package/dist/kv/FsFolderJsonKvRepository.d.ts.map +0 -1
- package/dist/kv/FsFolderKvRepository.d.ts.map +0 -1
- package/dist/kv/IKvRepository.d.ts.map +0 -1
- package/dist/kv/InMemoryKvRepository.d.ts.map +0 -1
- package/dist/kv/IndexedDbKvRepository.d.ts.map +0 -1
- package/dist/kv/KvRepository.d.ts.map +0 -1
- package/dist/kv/KvViaTabularRepository.d.ts.map +0 -1
- package/dist/kv/PostgresKvRepository.d.ts.map +0 -1
- package/dist/kv/SqliteKvRepository.d.ts.map +0 -1
- package/dist/kv/SupabaseKvRepository.d.ts.map +0 -1
- package/dist/limiter/IRateLimiterStorage.d.ts.map +0 -1
- package/dist/limiter/InMemoryRateLimiterStorage.d.ts.map +0 -1
- package/dist/limiter/IndexedDbRateLimiterStorage.d.ts.map +0 -1
- package/dist/limiter/PostgresRateLimiterStorage.d.ts.map +0 -1
- package/dist/limiter/SqliteRateLimiterStorage.d.ts.map +0 -1
- package/dist/limiter/SupabaseRateLimiterStorage.d.ts.map +0 -1
- package/dist/tabular/BaseSqlTabularRepository.d.ts.map +0 -1
- package/dist/tabular/CachedTabularRepository.d.ts.map +0 -1
- package/dist/tabular/FsFolderTabularRepository.d.ts.map +0 -1
- package/dist/tabular/ITabularRepository.d.ts.map +0 -1
- package/dist/tabular/InMemoryTabularRepository.d.ts.map +0 -1
- package/dist/tabular/IndexedDbTabularRepository.d.ts.map +0 -1
- package/dist/tabular/PostgresTabularRepository.d.ts.map +0 -1
- package/dist/tabular/SharedInMemoryTabularRepository.d.ts.map +0 -1
- package/dist/tabular/SqliteTabularRepository.d.ts.map +0 -1
- package/dist/tabular/SupabaseTabularRepository.d.ts.map +0 -1
- package/dist/tabular/TabularRepository.d.ts.map +0 -1
- /package/dist/{limiter → queue-limiter}/IRateLimiterStorage.d.ts +0 -0
- /package/dist/{limiter → queue-limiter}/InMemoryRateLimiterStorage.d.ts +0 -0
- /package/dist/{limiter → queue-limiter}/IndexedDbRateLimiterStorage.d.ts +0 -0
- /package/dist/{limiter → queue-limiter}/PostgresRateLimiterStorage.d.ts +0 -0
- /package/dist/{limiter → queue-limiter}/SqliteRateLimiterStorage.d.ts +0 -0
- /package/dist/{limiter → queue-limiter}/SupabaseRateLimiterStorage.d.ts +0 -0
package/README.md
CHANGED
|
@@ -28,12 +28,13 @@ Modular storage solutions for Workglow.AI platform with multiple backend impleme
|
|
|
28
28
|
- [Node.js Environment](#nodejs-environment)
|
|
29
29
|
- [Bun Environment](#bun-environment)
|
|
30
30
|
- [Advanced Features](#advanced-features)
|
|
31
|
+
- [Repository Registry](#repository-registry)
|
|
31
32
|
- [Event-Driven Architecture](#event-driven-architecture)
|
|
32
33
|
- [Compound Primary Keys](#compound-primary-keys)
|
|
33
34
|
- [Custom File Layout (KV on filesystem)](#custom-file-layout-kv-on-filesystem)
|
|
34
35
|
- [API Reference](#api-reference)
|
|
35
|
-
- [
|
|
36
|
-
- [
|
|
36
|
+
- [IKvStorage\<Key, Value\>](#ikvrepositorykey-value)
|
|
37
|
+
- [ITabularStorage\<Schema, PrimaryKeyNames\>](#itabularrepositoryschema-primarykeynames)
|
|
37
38
|
- [IQueueStorage\<Input, Output\>](#iqueuestorageinput-output)
|
|
38
39
|
- [Examples](#examples)
|
|
39
40
|
- [User Management System](#user-management-system)
|
|
@@ -46,16 +47,16 @@ Modular storage solutions for Workglow.AI platform with multiple backend impleme
|
|
|
46
47
|
|
|
47
48
|
```typescript
|
|
48
49
|
// Key-Value Storage (simple data)
|
|
49
|
-
import {
|
|
50
|
+
import { InMemoryKvStorage } from "@workglow/storage";
|
|
50
51
|
|
|
51
|
-
const kvStore = new
|
|
52
|
+
const kvStore = new InMemoryKvStorage<string, { name: string; age: number }>();
|
|
52
53
|
await kvStore.put("user:123", { name: "Alice", age: 30 });
|
|
53
54
|
const kvUser = await kvStore.get("user:123"); // { name: "Alice", age: 30 }
|
|
54
55
|
```
|
|
55
56
|
|
|
56
57
|
```typescript
|
|
57
58
|
// Tabular Storage (structured data with schemas)
|
|
58
|
-
import {
|
|
59
|
+
import { InMemoryTabularStorage } from "@workglow/storage";
|
|
59
60
|
import { JsonSchema } from "@workglow/util";
|
|
60
61
|
|
|
61
62
|
const userSchema = {
|
|
@@ -70,7 +71,7 @@ const userSchema = {
|
|
|
70
71
|
additionalProperties: false,
|
|
71
72
|
} as const satisfies JsonSchema;
|
|
72
73
|
|
|
73
|
-
const userRepo = new
|
|
74
|
+
const userRepo = new InMemoryTabularStorage<typeof userSchema, ["id"]>(
|
|
74
75
|
userSchema,
|
|
75
76
|
["id"], // primary key
|
|
76
77
|
["email"] // additional indexes
|
|
@@ -138,7 +139,7 @@ The package uses conditional exports, so importing from `@workglow/storage` auto
|
|
|
138
139
|
|
|
139
140
|
```typescript
|
|
140
141
|
// Import from the top-level package; it resolves to the correct target per environment
|
|
141
|
-
import {
|
|
142
|
+
import { InMemoryKvStorage, SqliteTabularStorage } from "@workglow/storage";
|
|
142
143
|
```
|
|
143
144
|
|
|
144
145
|
## Storage Types
|
|
@@ -150,10 +151,10 @@ Simple key-value storage for unstructured or semi-structured data.
|
|
|
150
151
|
#### Basic Usage
|
|
151
152
|
|
|
152
153
|
```typescript
|
|
153
|
-
import {
|
|
154
|
+
import { InMemoryKvStorage, FsFolderJsonKvRepository } from "@workglow/storage";
|
|
154
155
|
|
|
155
156
|
// In-memory (for testing/caching)
|
|
156
|
-
const cache = new
|
|
157
|
+
const cache = new InMemoryKvStorage<string, any>();
|
|
157
158
|
await cache.put("config", { theme: "dark", language: "en" });
|
|
158
159
|
|
|
159
160
|
// File-based JSON (persistent)
|
|
@@ -189,7 +190,7 @@ const supabaseStore = new SupabaseKvRepository(supabase, "settings");
|
|
|
189
190
|
#### Bulk Operations
|
|
190
191
|
|
|
191
192
|
```typescript
|
|
192
|
-
const store = new
|
|
193
|
+
const store = new InMemoryKvStorage<string, { name: string; score: number }>();
|
|
193
194
|
|
|
194
195
|
// Bulk insert
|
|
195
196
|
await store.putBulk([
|
|
@@ -208,7 +209,7 @@ const count = await store.size(); // 2
|
|
|
208
209
|
#### Event Handling
|
|
209
210
|
|
|
210
211
|
```typescript
|
|
211
|
-
const store = new
|
|
212
|
+
const store = new InMemoryKvStorage<string, any>();
|
|
212
213
|
|
|
213
214
|
// Listen to storage events
|
|
214
215
|
store.on("put", (key, value) => {
|
|
@@ -231,7 +232,7 @@ Structured storage with schemas, primary keys, and indexing for complex data rel
|
|
|
231
232
|
|
|
232
233
|
```typescript
|
|
233
234
|
import { JsonSchema } from "@workglow/util";
|
|
234
|
-
import {
|
|
235
|
+
import { InMemoryTabularStorage } from "@workglow/storage";
|
|
235
236
|
|
|
236
237
|
// Define your entity schema
|
|
237
238
|
const UserSchema = {
|
|
@@ -249,13 +250,59 @@ const UserSchema = {
|
|
|
249
250
|
} as const satisfies JsonSchema;
|
|
250
251
|
|
|
251
252
|
// Create repository with primary key and indexes
|
|
252
|
-
const userRepo = new
|
|
253
|
+
const userRepo = new InMemoryTabularStorage<typeof UserSchema, ["id"]>(
|
|
253
254
|
UserSchema,
|
|
254
255
|
["id"], // Primary key (can be compound: ["dept", "id"])
|
|
255
256
|
["email", "department", ["department", "age"]] // Indexes for fast lookups
|
|
256
257
|
);
|
|
257
258
|
```
|
|
258
259
|
|
|
260
|
+
#### Auto-Generated Primary Keys
|
|
261
|
+
|
|
262
|
+
TabularStorage supports automatic ID generation by marking schema properties with `x-auto-generated: true`:
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
const UserSchema = {
|
|
266
|
+
type: "object",
|
|
267
|
+
properties: {
|
|
268
|
+
id: { type: "integer", "x-auto-generated": true }, // Auto-increment
|
|
269
|
+
name: { type: "string" },
|
|
270
|
+
email: { type: "string" },
|
|
271
|
+
},
|
|
272
|
+
required: ["id", "name", "email"],
|
|
273
|
+
} as const;
|
|
274
|
+
|
|
275
|
+
const storage = new PostgresTabularStorage(db, "users", UserSchema, ["id"] as const);
|
|
276
|
+
|
|
277
|
+
// Insert without providing ID - database generates it
|
|
278
|
+
const user = await storage.put({ name: "Alice", email: "alice@example.com" });
|
|
279
|
+
console.log(user.id); // 1 (auto-generated)
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Generation Strategy** (inferred from type):
|
|
283
|
+
|
|
284
|
+
- `type: "integer"` → Auto-increment (SERIAL, INTEGER PRIMARY KEY, counter)
|
|
285
|
+
- `type: "string"` → UUID via `uuid4()` from `@workglow/util`
|
|
286
|
+
|
|
287
|
+
**Configuration Options:**
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
new PostgresTabularStorage(
|
|
291
|
+
db,
|
|
292
|
+
"users",
|
|
293
|
+
UserSchema,
|
|
294
|
+
["id"],
|
|
295
|
+
[],
|
|
296
|
+
{ clientProvidedKeys: "if-missing" } // "never" | "if-missing" | "always"
|
|
297
|
+
);
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
- `"if-missing"` (default): Use client value if provided, generate otherwise
|
|
301
|
+
- `"never"`: Always generate (most secure)
|
|
302
|
+
- `"always"`: Require client value (for testing)
|
|
303
|
+
|
|
304
|
+
See [Tabular Storage README](./src/tabular/README.md) for detailed documentation.
|
|
305
|
+
|
|
259
306
|
#### CRUD Operations
|
|
260
307
|
|
|
261
308
|
```typescript
|
|
@@ -342,9 +389,9 @@ await userRepo.deleteSearch({
|
|
|
342
389
|
|
|
343
390
|
```typescript
|
|
344
391
|
// SQLite (Node.js/Bun)
|
|
345
|
-
import {
|
|
392
|
+
import { SqliteTabularStorage } from "@workglow/storage";
|
|
346
393
|
|
|
347
|
-
const sqliteUsers = new
|
|
394
|
+
const sqliteUsers = new SqliteTabularStorage<typeof UserSchema, ["id"]>(
|
|
348
395
|
"./users.db",
|
|
349
396
|
"users",
|
|
350
397
|
UserSchema,
|
|
@@ -353,11 +400,11 @@ const sqliteUsers = new SqliteTabularRepository<typeof UserSchema, ["id"]>(
|
|
|
353
400
|
);
|
|
354
401
|
|
|
355
402
|
// PostgreSQL (Node.js/Bun)
|
|
356
|
-
import {
|
|
403
|
+
import { PostgresTabularStorage } from "@workglow/storage";
|
|
357
404
|
import { Pool } from "pg";
|
|
358
405
|
|
|
359
406
|
const pool = new Pool({ connectionString: "postgresql://..." });
|
|
360
|
-
const pgUsers = new
|
|
407
|
+
const pgUsers = new PostgresTabularStorage<typeof UserSchema, ["id"]>(
|
|
361
408
|
pool,
|
|
362
409
|
"users",
|
|
363
410
|
UserSchema,
|
|
@@ -366,11 +413,11 @@ const pgUsers = new PostgresTabularRepository<typeof UserSchema, ["id"]>(
|
|
|
366
413
|
);
|
|
367
414
|
|
|
368
415
|
// Supabase (Node.js/Bun)
|
|
369
|
-
import {
|
|
416
|
+
import { SupabaseTabularStorage } from "@workglow/storage";
|
|
370
417
|
import { createClient } from "@supabase/supabase-js";
|
|
371
418
|
|
|
372
419
|
const supabase = createClient("https://your-project.supabase.co", "your-anon-key");
|
|
373
|
-
const supabaseUsers = new
|
|
420
|
+
const supabaseUsers = new SupabaseTabularStorage<typeof UserSchema, ["id"]>(
|
|
374
421
|
supabase,
|
|
375
422
|
"users",
|
|
376
423
|
UserSchema,
|
|
@@ -379,8 +426,8 @@ const supabaseUsers = new SupabaseTabularRepository<typeof UserSchema, ["id"]>(
|
|
|
379
426
|
);
|
|
380
427
|
|
|
381
428
|
// IndexedDB (Browser)
|
|
382
|
-
import {
|
|
383
|
-
const browserUsers = new
|
|
429
|
+
import { IndexedDbTabularStorage } from "@workglow/storage";
|
|
430
|
+
const browserUsers = new IndexedDbTabularStorage<typeof UserSchema, ["id"]>(
|
|
384
431
|
"users",
|
|
385
432
|
UserSchema,
|
|
386
433
|
["id"],
|
|
@@ -388,8 +435,8 @@ const browserUsers = new IndexedDbTabularRepository<typeof UserSchema, ["id"]>(
|
|
|
388
435
|
);
|
|
389
436
|
|
|
390
437
|
// File-based (Node.js/Bun)
|
|
391
|
-
import {
|
|
392
|
-
const fileUsers = new
|
|
438
|
+
import { FsFolderTabularStorage } from "@workglow/storage";
|
|
439
|
+
const fileUsers = new FsFolderTabularStorage<typeof UserSchema, ["id"]>(
|
|
393
440
|
"./data/users",
|
|
394
441
|
UserSchema,
|
|
395
442
|
["id"],
|
|
@@ -463,23 +510,23 @@ await jobQueue.deleteJobsByStatusAndAge(JobStatus.COMPLETED, 24 * 60 * 60 * 1000
|
|
|
463
510
|
```typescript
|
|
464
511
|
import {
|
|
465
512
|
IndexedDbKvRepository,
|
|
466
|
-
|
|
513
|
+
IndexedDbTabularStorage,
|
|
467
514
|
IndexedDbQueueStorage,
|
|
468
515
|
SupabaseKvRepository,
|
|
469
|
-
|
|
516
|
+
SupabaseTabularStorage,
|
|
470
517
|
SupabaseQueueStorage,
|
|
471
518
|
} from "@workglow/storage";
|
|
472
519
|
import { createClient } from "@supabase/supabase-js";
|
|
473
520
|
|
|
474
521
|
// Local browser storage with IndexedDB
|
|
475
522
|
const settings = new IndexedDbKvRepository("app-settings");
|
|
476
|
-
const userData = new
|
|
523
|
+
const userData = new IndexedDbTabularStorage("users", UserSchema, ["id"]);
|
|
477
524
|
const jobQueue = new IndexedDbQueueStorage<any, any>("background-jobs");
|
|
478
525
|
|
|
479
526
|
// Or use Supabase for cloud storage from the browser
|
|
480
527
|
const supabase = createClient("https://your-project.supabase.co", "your-anon-key");
|
|
481
528
|
const cloudSettings = new SupabaseKvRepository(supabase, "app-settings");
|
|
482
|
-
const cloudUserData = new
|
|
529
|
+
const cloudUserData = new SupabaseTabularStorage(supabase, "users", UserSchema, ["id"]);
|
|
483
530
|
const cloudJobQueue = new SupabaseQueueStorage(supabase, "background-jobs");
|
|
484
531
|
```
|
|
485
532
|
|
|
@@ -488,13 +535,13 @@ const cloudJobQueue = new SupabaseQueueStorage(supabase, "background-jobs");
|
|
|
488
535
|
```typescript
|
|
489
536
|
import {
|
|
490
537
|
SqliteKvRepository,
|
|
491
|
-
|
|
538
|
+
PostgresTabularStorage,
|
|
492
539
|
FsFolderJsonKvRepository,
|
|
493
540
|
} from "@workglow/storage";
|
|
494
541
|
|
|
495
542
|
// Mix and match storage backends
|
|
496
543
|
const cache = new FsFolderJsonKvRepository("./cache");
|
|
497
|
-
const users = new
|
|
544
|
+
const users = new PostgresTabularStorage(pool, "users", UserSchema, ["id"]);
|
|
498
545
|
```
|
|
499
546
|
|
|
500
547
|
### Bun Environment
|
|
@@ -502,31 +549,120 @@ const users = new PostgresTabularRepository(pool, "users", UserSchema, ["id"]);
|
|
|
502
549
|
```typescript
|
|
503
550
|
// Bun has access to all implementations
|
|
504
551
|
import {
|
|
505
|
-
|
|
552
|
+
SqliteTabularStorage,
|
|
506
553
|
FsFolderJsonKvRepository,
|
|
507
554
|
PostgresQueueStorage,
|
|
508
|
-
|
|
555
|
+
SupabaseTabularStorage,
|
|
509
556
|
} from "@workglow/storage";
|
|
510
557
|
|
|
511
558
|
import { Database } from "bun:sqlite";
|
|
512
559
|
import { createClient } from "@supabase/supabase-js";
|
|
513
560
|
|
|
514
561
|
const db = new Database("./app.db");
|
|
515
|
-
const data = new
|
|
562
|
+
const data = new SqliteTabularStorage(db, "items", ItemSchema, ["id"]);
|
|
516
563
|
|
|
517
564
|
// Or use Supabase for cloud storage
|
|
518
565
|
const supabase = createClient("https://your-project.supabase.co", "your-anon-key");
|
|
519
|
-
const cloudData = new
|
|
566
|
+
const cloudData = new SupabaseTabularStorage(supabase, "items", ItemSchema, ["id"]);
|
|
520
567
|
```
|
|
521
568
|
|
|
522
569
|
## Advanced Features
|
|
523
570
|
|
|
571
|
+
### Repository Registry
|
|
572
|
+
|
|
573
|
+
Repositories can be registered globally by ID, allowing tasks to reference them by name rather than passing direct instances. This is useful for configuring repositories once at application startup and referencing them throughout your task graphs.
|
|
574
|
+
|
|
575
|
+
#### Registering Repositories
|
|
576
|
+
|
|
577
|
+
```typescript
|
|
578
|
+
import {
|
|
579
|
+
registerTabularStorage,
|
|
580
|
+
getTabularStorage,
|
|
581
|
+
InMemoryTabularStorage,
|
|
582
|
+
} from "@workglow/storage";
|
|
583
|
+
|
|
584
|
+
// Define your schema
|
|
585
|
+
const userSchema = {
|
|
586
|
+
type: "object",
|
|
587
|
+
properties: {
|
|
588
|
+
id: { type: "string" },
|
|
589
|
+
name: { type: "string" },
|
|
590
|
+
email: { type: "string" },
|
|
591
|
+
},
|
|
592
|
+
required: ["id", "name", "email"],
|
|
593
|
+
additionalProperties: false,
|
|
594
|
+
} as const;
|
|
595
|
+
|
|
596
|
+
// Create and register a repository
|
|
597
|
+
const userRepo = new InMemoryTabularStorage(userSchema, ["id"] as const);
|
|
598
|
+
registerTabularStorage("users", userRepo);
|
|
599
|
+
|
|
600
|
+
// Later, retrieve the repository by ID
|
|
601
|
+
const repo = getTabularStorage("users");
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
#### Using Repositories in Tasks
|
|
605
|
+
|
|
606
|
+
When using repositories with tasks, you can pass either the repository ID or a direct instance. The TaskRunner automatically resolves string IDs using the registry.
|
|
607
|
+
|
|
608
|
+
```typescript
|
|
609
|
+
import { TypeTabularStorage } from "@workglow/storage";
|
|
610
|
+
|
|
611
|
+
// In your task's input schema, use TypeTabularStorage
|
|
612
|
+
static inputSchema() {
|
|
613
|
+
return {
|
|
614
|
+
type: "object",
|
|
615
|
+
properties: {
|
|
616
|
+
dataSource: TypeTabularStorage({
|
|
617
|
+
title: "User Repository",
|
|
618
|
+
description: "Repository containing user records",
|
|
619
|
+
}),
|
|
620
|
+
},
|
|
621
|
+
required: ["dataSource"],
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Both approaches work:
|
|
626
|
+
await task.run({ dataSource: "users" }); // Resolved from registry
|
|
627
|
+
await task.run({ dataSource: userRepoInstance }); // Direct instance
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
#### Schema Helper Functions
|
|
631
|
+
|
|
632
|
+
The package provides schema helper functions for defining repository inputs with proper format annotations:
|
|
633
|
+
|
|
634
|
+
```typescript
|
|
635
|
+
import {
|
|
636
|
+
TypeTabularStorage,
|
|
637
|
+
TypeVectorRepository,
|
|
638
|
+
TypeDocumentRepository,
|
|
639
|
+
} from "@workglow/storage";
|
|
640
|
+
|
|
641
|
+
// Tabular repository (format: "storage:tabular")
|
|
642
|
+
const tabularSchema = TypeTabularStorage({
|
|
643
|
+
title: "Data Source",
|
|
644
|
+
description: "Tabular data repository",
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
// Vector repository (format: "repository:document-node-vector")
|
|
648
|
+
const vectorSchema = TypeVectorRepository({
|
|
649
|
+
title: "Embeddings Store",
|
|
650
|
+
description: "Vector embeddings repository",
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
// Document repository (format: "repository:document")
|
|
654
|
+
const docSchema = TypeDocumentRepository({
|
|
655
|
+
title: "Document Store",
|
|
656
|
+
description: "Document storage repository",
|
|
657
|
+
});
|
|
658
|
+
```
|
|
659
|
+
|
|
524
660
|
### Event-Driven Architecture
|
|
525
661
|
|
|
526
662
|
All storage implementations support event emission for monitoring and reactive programming:
|
|
527
663
|
|
|
528
664
|
```typescript
|
|
529
|
-
const store = new
|
|
665
|
+
const store = new InMemoryTabularStorage(UserSchema, ["id"]);
|
|
530
666
|
|
|
531
667
|
// Monitor all operations
|
|
532
668
|
store.on("put", (entity) => console.log("User created/updated:", entity));
|
|
@@ -555,7 +691,7 @@ const OrderLineSchema = {
|
|
|
555
691
|
additionalProperties: false,
|
|
556
692
|
} as const satisfies JsonSchema;
|
|
557
693
|
|
|
558
|
-
const orderLines = new
|
|
694
|
+
const orderLines = new InMemoryTabularStorage<typeof OrderLineSchema, ["orderId", "lineNumber"]>(
|
|
559
695
|
OrderLineSchema,
|
|
560
696
|
["orderId", "lineNumber"], // Compound primary key
|
|
561
697
|
["productId"] // Additional index
|
|
@@ -594,12 +730,12 @@ await files.put("note-1", "Hello world");
|
|
|
594
730
|
|
|
595
731
|
## API Reference
|
|
596
732
|
|
|
597
|
-
###
|
|
733
|
+
### IKvStorage<Key, Value>
|
|
598
734
|
|
|
599
735
|
Core interface for key-value storage:
|
|
600
736
|
|
|
601
737
|
```typescript
|
|
602
|
-
interface
|
|
738
|
+
interface IKvStorage<Key, Value> {
|
|
603
739
|
// Core operations
|
|
604
740
|
put(key: Key, value: Value): Promise<void>;
|
|
605
741
|
putBulk(items: Array<{ key: Key; value: Value }>): Promise<void>;
|
|
@@ -618,12 +754,12 @@ interface IKvRepository<Key, Value> {
|
|
|
618
754
|
}
|
|
619
755
|
```
|
|
620
756
|
|
|
621
|
-
###
|
|
757
|
+
### ITabularStorage<Schema, PrimaryKeyNames>
|
|
622
758
|
|
|
623
759
|
Core interface for tabular storage:
|
|
624
760
|
|
|
625
761
|
```typescript
|
|
626
|
-
interface
|
|
762
|
+
interface ITabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value> {
|
|
627
763
|
// Core operations
|
|
628
764
|
put(entity: Entity): Promise<void>;
|
|
629
765
|
putBulk(entities: Entity[]): Promise<void>;
|
|
@@ -705,7 +841,7 @@ interface IQueueStorage<Input, Output> {
|
|
|
705
841
|
|
|
706
842
|
```typescript
|
|
707
843
|
import { JsonSchema, FromSchema } from "@workglow/util";
|
|
708
|
-
import {
|
|
844
|
+
import { InMemoryTabularStorage, InMemoryKvStorage } from "@workglow/storage";
|
|
709
845
|
|
|
710
846
|
// User profile with tabular storage
|
|
711
847
|
const UserSchema = {
|
|
@@ -727,14 +863,14 @@ const UserSchema = {
|
|
|
727
863
|
additionalProperties: false,
|
|
728
864
|
} as const satisfies JsonSchema;
|
|
729
865
|
|
|
730
|
-
const userRepo = new
|
|
866
|
+
const userRepo = new InMemoryTabularStorage<typeof UserSchema, ["id"]>(
|
|
731
867
|
UserSchema,
|
|
732
868
|
["id"],
|
|
733
869
|
["email", "username"]
|
|
734
870
|
);
|
|
735
871
|
|
|
736
872
|
// User sessions with KV storage
|
|
737
|
-
const sessionStore = new
|
|
873
|
+
const sessionStore = new InMemoryKvStorage<string, { userId: string; expiresAt: string }>();
|
|
738
874
|
|
|
739
875
|
// User management class
|
|
740
876
|
class UserManager {
|
|
@@ -841,7 +977,7 @@ class ConfigManager {
|
|
|
841
977
|
import { createClient } from "@supabase/supabase-js";
|
|
842
978
|
import { JsonSchema } from "@workglow/util";
|
|
843
979
|
import {
|
|
844
|
-
|
|
980
|
+
SupabaseTabularStorage,
|
|
845
981
|
SupabaseKvRepository,
|
|
846
982
|
SupabaseQueueStorage,
|
|
847
983
|
} from "@workglow/storage";
|
|
@@ -882,7 +1018,7 @@ const OrderSchema = {
|
|
|
882
1018
|
} as const satisfies JsonSchema;
|
|
883
1019
|
|
|
884
1020
|
// Create repositories
|
|
885
|
-
const products = new
|
|
1021
|
+
const products = new SupabaseTabularStorage<typeof ProductSchema, ["id"]>(
|
|
886
1022
|
supabase,
|
|
887
1023
|
"products",
|
|
888
1024
|
ProductSchema,
|
|
@@ -890,7 +1026,7 @@ const products = new SupabaseTabularRepository<typeof ProductSchema, ["id"]>(
|
|
|
890
1026
|
["category", "name"] // Indexed columns for fast searching
|
|
891
1027
|
);
|
|
892
1028
|
|
|
893
|
-
const orders = new
|
|
1029
|
+
const orders = new SupabaseTabularStorage<typeof OrderSchema, ["id"]>(
|
|
894
1030
|
supabase,
|
|
895
1031
|
"orders",
|
|
896
1032
|
OrderSchema,
|
|
@@ -972,7 +1108,7 @@ bun test
|
|
|
972
1108
|
|
|
973
1109
|
# Run specific test suites
|
|
974
1110
|
bun test --grep "KvRepository"
|
|
975
|
-
bun test --grep "
|
|
1111
|
+
bun test --grep "TabularStorage"
|
|
976
1112
|
bun test --grep "QueueStorage"
|
|
977
1113
|
|
|
978
1114
|
# Test specific environments
|
|
@@ -985,17 +1121,13 @@ bun test --grep "Sqlite" # Native tests
|
|
|
985
1121
|
|
|
986
1122
|
```typescript
|
|
987
1123
|
import { describe, test, expect, beforeEach } from "vitest";
|
|
988
|
-
import {
|
|
1124
|
+
import { InMemoryTabularStorage } from "@workglow/storage";
|
|
989
1125
|
|
|
990
1126
|
describe("UserRepository", () => {
|
|
991
|
-
let userRepo:
|
|
1127
|
+
let userRepo: InMemoryTabularStorage<typeof UserSchema, ["id"]>;
|
|
992
1128
|
|
|
993
1129
|
beforeEach(() => {
|
|
994
|
-
userRepo = new
|
|
995
|
-
UserSchema,
|
|
996
|
-
["id"],
|
|
997
|
-
["email"]
|
|
998
|
-
);
|
|
1130
|
+
userRepo = new InMemoryTabularStorage<typeof UserSchema, ["id"]>(UserSchema, ["id"], ["email"]);
|
|
999
1131
|
});
|
|
1000
1132
|
|
|
1001
1133
|
test("should create and retrieve user", async () => {
|