@f0rbit/corpus 0.1.9 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend/base.d.ts +23 -0
- package/dist/backend/base.d.ts.map +1 -0
- package/dist/backend/base.js +101 -0
- package/dist/backend/cloudflare.d.ts.map +1 -1
- package/dist/backend/cloudflare.js +6 -5
- package/dist/backend/file.d.ts.map +1 -1
- package/dist/backend/file.js +38 -76
- package/dist/backend/layered.d.ts.map +1 -1
- package/dist/backend/layered.js +5 -1
- package/dist/backend/memory.d.ts.map +1 -1
- package/dist/backend/memory.js +18 -69
- package/dist/backends.d.ts +1 -0
- package/dist/backends.d.ts.map +1 -1
- package/dist/backends.js +1 -0
- package/dist/cloudflare.d.ts +1 -0
- package/dist/cloudflare.d.ts.map +1 -1
- package/dist/cloudflare.js +1 -0
- package/dist/concurrency.d.ts +78 -0
- package/dist/concurrency.d.ts.map +1 -0
- package/dist/concurrency.js +108 -0
- package/dist/index.d.ts +13 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -10
- package/dist/observations/index.d.ts +1 -1
- package/dist/observations/index.d.ts.map +1 -1
- package/dist/observations/storage.d.ts +33 -4
- package/dist/observations/storage.d.ts.map +1 -1
- package/dist/observations/storage.js +63 -43
- package/dist/observations/utils.d.ts.map +1 -1
- package/dist/observations/utils.js +5 -2
- package/dist/result.d.ts +361 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +410 -0
- package/dist/types.d.ts +33 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +39 -6
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +47 -15
- package/package.json +1 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Backend Base
|
|
3
|
+
* @description Base abstraction layer for backend implementations.
|
|
4
|
+
*/
|
|
5
|
+
import type { MetadataClient, DataClient, SnapshotMeta, CorpusEvent } from "../types";
|
|
6
|
+
export type MetadataStorage = {
|
|
7
|
+
get: (store_id: string, version: string) => Promise<SnapshotMeta | null>;
|
|
8
|
+
put: (meta: SnapshotMeta) => Promise<void>;
|
|
9
|
+
delete: (store_id: string, version: string) => Promise<void>;
|
|
10
|
+
list: (store_id: string) => AsyncIterable<SnapshotMeta>;
|
|
11
|
+
find_by_hash: (store_id: string, hash: string) => Promise<SnapshotMeta | null>;
|
|
12
|
+
};
|
|
13
|
+
export type DataStorage = {
|
|
14
|
+
get: (data_key: string) => Promise<Uint8Array | null>;
|
|
15
|
+
put: (data_key: string, data: Uint8Array) => Promise<void>;
|
|
16
|
+
delete: (data_key: string) => Promise<void>;
|
|
17
|
+
exists: (data_key: string) => Promise<boolean>;
|
|
18
|
+
};
|
|
19
|
+
type Emit = (event: CorpusEvent) => void;
|
|
20
|
+
export declare function create_metadata_client(storage: MetadataStorage, emit: Emit): MetadataClient;
|
|
21
|
+
export declare function create_data_client(storage: DataStorage, emit: Emit): DataClient;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../backend/base.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,UAAU,EACV,YAAY,EAGZ,WAAW,EAGZ,MAAM,UAAU,CAAC;AAKlB,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IACzE,GAAG,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,aAAa,CAAC,YAAY,CAAC,CAAC;IACxD,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;CAChF,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACtD,GAAG,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAChD,CAAC;AAEF,KAAK,IAAI,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;AAEzC,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,IAAI,GACT,cAAc,CAoEhB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,GAAG,UAAU,CA0C/E"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Backend Base
|
|
3
|
+
* @description Base abstraction layer for backend implementations.
|
|
4
|
+
*/
|
|
5
|
+
import { ok, err } from "../types";
|
|
6
|
+
import { to_bytes, filter_snapshots } from "../utils";
|
|
7
|
+
import { first, to_fallback } from "../result";
|
|
8
|
+
export function create_metadata_client(storage, emit) {
|
|
9
|
+
return {
|
|
10
|
+
async get(store_id, version) {
|
|
11
|
+
const meta = await storage.get(store_id, version);
|
|
12
|
+
emit({ type: "meta_get", store_id, version, found: !!meta });
|
|
13
|
+
if (!meta) {
|
|
14
|
+
return err({ kind: "not_found", store_id, version });
|
|
15
|
+
}
|
|
16
|
+
return ok(meta);
|
|
17
|
+
},
|
|
18
|
+
async put(meta) {
|
|
19
|
+
await storage.put(meta);
|
|
20
|
+
emit({ type: "meta_put", store_id: meta.store_id, version: meta.version });
|
|
21
|
+
return ok(undefined);
|
|
22
|
+
},
|
|
23
|
+
async delete(store_id, version) {
|
|
24
|
+
await storage.delete(store_id, version);
|
|
25
|
+
emit({ type: "meta_delete", store_id, version });
|
|
26
|
+
return ok(undefined);
|
|
27
|
+
},
|
|
28
|
+
async *list(store_id, opts) {
|
|
29
|
+
const all = [];
|
|
30
|
+
for await (const meta of storage.list(store_id)) {
|
|
31
|
+
all.push(meta);
|
|
32
|
+
}
|
|
33
|
+
const filtered = filter_snapshots(all, opts);
|
|
34
|
+
let count = 0;
|
|
35
|
+
for (const meta of filtered) {
|
|
36
|
+
yield meta;
|
|
37
|
+
count++;
|
|
38
|
+
}
|
|
39
|
+
emit({ type: "meta_list", store_id, count });
|
|
40
|
+
},
|
|
41
|
+
async get_latest(store_id) {
|
|
42
|
+
let latest = null;
|
|
43
|
+
for await (const meta of storage.list(store_id)) {
|
|
44
|
+
if (!latest || meta.created_at > latest.created_at) {
|
|
45
|
+
latest = meta;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (!latest) {
|
|
49
|
+
return err({ kind: "not_found", store_id, version: "latest" });
|
|
50
|
+
}
|
|
51
|
+
return ok(latest);
|
|
52
|
+
},
|
|
53
|
+
async *get_children(parent_store_id, parent_version) {
|
|
54
|
+
for await (const meta of storage.list("")) {
|
|
55
|
+
const is_child = meta.parents.some((p) => p.store_id === parent_store_id && p.version === parent_version);
|
|
56
|
+
if (is_child)
|
|
57
|
+
yield meta;
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
async find_by_hash(store_id, content_hash) {
|
|
61
|
+
return storage.find_by_hash(store_id, content_hash);
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export function create_data_client(storage, emit) {
|
|
66
|
+
return {
|
|
67
|
+
async get(data_key) {
|
|
68
|
+
const bytes = await storage.get(data_key);
|
|
69
|
+
emit({
|
|
70
|
+
type: "data_get",
|
|
71
|
+
store_id: to_fallback(first(data_key.split("/")), data_key),
|
|
72
|
+
version: data_key,
|
|
73
|
+
found: !!bytes,
|
|
74
|
+
});
|
|
75
|
+
if (!bytes) {
|
|
76
|
+
return err({ kind: "not_found", store_id: data_key, version: "" });
|
|
77
|
+
}
|
|
78
|
+
return ok({
|
|
79
|
+
stream: () => new ReadableStream({
|
|
80
|
+
start(controller) {
|
|
81
|
+
controller.enqueue(bytes);
|
|
82
|
+
controller.close();
|
|
83
|
+
},
|
|
84
|
+
}),
|
|
85
|
+
bytes: async () => bytes,
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
async put(data_key, input) {
|
|
89
|
+
const bytes = await to_bytes(input);
|
|
90
|
+
await storage.put(data_key, bytes);
|
|
91
|
+
return ok(undefined);
|
|
92
|
+
},
|
|
93
|
+
async delete(data_key) {
|
|
94
|
+
await storage.delete(data_key);
|
|
95
|
+
return ok(undefined);
|
|
96
|
+
},
|
|
97
|
+
async exists(data_key) {
|
|
98
|
+
return storage.exists(data_key);
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../backend/cloudflare.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAiE,YAAY,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../backend/cloudflare.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAiE,YAAY,EAAE,MAAM,UAAU,CAAC;AAOrH,KAAK,UAAU,GAAG;IAAE,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;CAAE,CAAC;AACxD,KAAK,QAAQ,GAAG;IACf,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;QAAC,WAAW,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACpH,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnF,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACrC,EAAE,EAAE,UAAU,CAAC;IACf,EAAE,EAAE,QAAQ,CAAC;IACb,QAAQ,CAAC,EAAE,YAAY,CAAC;CACxB,CAAC;AA6IF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAmOlF"}
|
|
@@ -6,6 +6,7 @@ import { eq, and, desc, lt, gt, like, sql, inArray } from "drizzle-orm";
|
|
|
6
6
|
import { drizzle } from "drizzle-orm/d1";
|
|
7
7
|
import { create_emitter, parse_snapshot_meta } from "../utils";
|
|
8
8
|
import { ok, err } from "../types";
|
|
9
|
+
import { first, to_nullable, to_fallback } from "../result";
|
|
9
10
|
import { corpus_snapshots } from "../schema";
|
|
10
11
|
import { corpus_observations, create_observations_client } from "../observations";
|
|
11
12
|
function create_cloudflare_storage(db) {
|
|
@@ -30,7 +31,7 @@ function create_cloudflare_storage(db) {
|
|
|
30
31
|
.from(corpus_observations)
|
|
31
32
|
.where(eq(corpus_observations.id, id))
|
|
32
33
|
.limit(1);
|
|
33
|
-
return ok(rows
|
|
34
|
+
return ok(to_nullable(first(rows)));
|
|
34
35
|
}
|
|
35
36
|
catch (cause) {
|
|
36
37
|
return err({
|
|
@@ -185,7 +186,7 @@ export function create_cloudflare_backend(config) {
|
|
|
185
186
|
.from(corpus_snapshots)
|
|
186
187
|
.where(and(eq(corpus_snapshots.store_id, store_id), eq(corpus_snapshots.version, version)))
|
|
187
188
|
.limit(1);
|
|
188
|
-
const row = rows
|
|
189
|
+
const row = to_nullable(first(rows));
|
|
189
190
|
emit({ type: "meta_get", store_id, version, found: !!row });
|
|
190
191
|
if (!row) {
|
|
191
192
|
return err({ kind: "not_found", store_id, version });
|
|
@@ -279,7 +280,7 @@ export function create_cloudflare_backend(config) {
|
|
|
279
280
|
async get_latest(store_id) {
|
|
280
281
|
try {
|
|
281
282
|
const rows = await db.select().from(corpus_snapshots).where(eq(corpus_snapshots.store_id, store_id)).orderBy(desc(corpus_snapshots.created_at)).limit(1);
|
|
282
|
-
const row = rows
|
|
283
|
+
const row = to_nullable(first(rows));
|
|
283
284
|
if (!row) {
|
|
284
285
|
return err({ kind: "not_found", store_id, version: "latest" });
|
|
285
286
|
}
|
|
@@ -311,7 +312,7 @@ export function create_cloudflare_backend(config) {
|
|
|
311
312
|
.from(corpus_snapshots)
|
|
312
313
|
.where(and(eq(corpus_snapshots.store_id, store_id), eq(corpus_snapshots.content_hash, content_hash)))
|
|
313
314
|
.limit(1);
|
|
314
|
-
const row = rows
|
|
315
|
+
const row = to_nullable(first(rows));
|
|
315
316
|
return row ? snapshot_row_to_meta(row) : null;
|
|
316
317
|
}
|
|
317
318
|
catch {
|
|
@@ -323,7 +324,7 @@ export function create_cloudflare_backend(config) {
|
|
|
323
324
|
async get(data_key) {
|
|
324
325
|
try {
|
|
325
326
|
const object = await r2.get(data_key);
|
|
326
|
-
emit({ type: "data_get", store_id: data_key.split("/")
|
|
327
|
+
emit({ type: "data_get", store_id: to_fallback(first(data_key.split("/")), data_key), version: data_key, found: !!object });
|
|
327
328
|
if (!object) {
|
|
328
329
|
return err({ kind: "not_found", store_id: data_key, version: "" });
|
|
329
330
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../backend/file.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../backend/file.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAgB,YAAY,EAAE,MAAM,UAAU,CAAC;AASpE,MAAM,MAAM,iBAAiB,GAAG;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,YAAY,CAAC;CACxB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAiKtE"}
|
package/dist/backend/file.js
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* @description File-system storage backend for local persistence.
|
|
4
4
|
*/
|
|
5
5
|
import { create_observations_client, create_observations_storage } from "../observations";
|
|
6
|
-
import {
|
|
7
|
-
import { to_bytes, create_emitter, filter_snapshots, parse_snapshot_meta } from "../utils";
|
|
6
|
+
import { create_emitter, parse_snapshot_meta } from "../utils";
|
|
8
7
|
import { mkdir, readdir } from "node:fs/promises";
|
|
9
8
|
import { join, dirname } from "node:path";
|
|
9
|
+
import { create_metadata_client, create_data_client } from "./base";
|
|
10
10
|
/**
|
|
11
11
|
* Creates a file-system storage backend for local persistence.
|
|
12
12
|
* @category Backends
|
|
@@ -67,68 +67,47 @@ export function create_file_backend(config) {
|
|
|
67
67
|
const entries = Array.from(meta_map.entries());
|
|
68
68
|
await Bun.write(path, JSON.stringify(entries));
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
async function* list_all_stores() {
|
|
71
|
+
try {
|
|
72
|
+
const entries = await readdir(base_path, { withFileTypes: true });
|
|
73
|
+
for (const entry of entries) {
|
|
74
|
+
if (entry.isDirectory() && !entry.name.startsWith("_")) {
|
|
75
|
+
yield entry.name;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch { }
|
|
80
|
+
}
|
|
81
|
+
const metadata_storage = {
|
|
71
82
|
async get(store_id, version) {
|
|
72
83
|
const store_meta = await read_store_meta(store_id);
|
|
73
|
-
|
|
74
|
-
emit({ type: "meta_get", store_id, version, found: !!meta });
|
|
75
|
-
if (!meta) {
|
|
76
|
-
return err({ kind: "not_found", store_id, version });
|
|
77
|
-
}
|
|
78
|
-
return ok(meta);
|
|
84
|
+
return store_meta.get(version) ?? null;
|
|
79
85
|
},
|
|
80
86
|
async put(meta) {
|
|
81
87
|
const store_meta = await read_store_meta(meta.store_id);
|
|
82
88
|
store_meta.set(meta.version, meta);
|
|
83
89
|
await write_store_meta(meta.store_id, store_meta);
|
|
84
|
-
emit({ type: "meta_put", store_id: meta.store_id, version: meta.version });
|
|
85
|
-
return ok(undefined);
|
|
86
90
|
},
|
|
87
91
|
async delete(store_id, version) {
|
|
88
92
|
const store_meta = await read_store_meta(store_id);
|
|
89
93
|
store_meta.delete(version);
|
|
90
94
|
await write_store_meta(store_id, store_meta);
|
|
91
|
-
emit({ type: "meta_delete", store_id, version });
|
|
92
|
-
return ok(undefined);
|
|
93
95
|
},
|
|
94
|
-
async *list(store_id
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
yield meta;
|
|
100
|
-
count++;
|
|
101
|
-
}
|
|
102
|
-
emit({ type: "meta_list", store_id, count });
|
|
103
|
-
},
|
|
104
|
-
async get_latest(store_id) {
|
|
105
|
-
const store_meta = await read_store_meta(store_id);
|
|
106
|
-
let latest = null;
|
|
107
|
-
for (const meta of store_meta.values()) {
|
|
108
|
-
if (!latest || meta.created_at > latest.created_at) {
|
|
109
|
-
latest = meta;
|
|
96
|
+
async *list(store_id) {
|
|
97
|
+
if (store_id) {
|
|
98
|
+
const store_meta = await read_store_meta(store_id);
|
|
99
|
+
for (const meta of store_meta.values()) {
|
|
100
|
+
yield meta;
|
|
110
101
|
}
|
|
111
102
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return ok(latest);
|
|
116
|
-
},
|
|
117
|
-
async *get_children(parent_store_id, parent_version) {
|
|
118
|
-
try {
|
|
119
|
-
const entries = await readdir(base_path, { withFileTypes: true });
|
|
120
|
-
for (const entry of entries) {
|
|
121
|
-
if (!entry.isDirectory() || entry.name.startsWith("_"))
|
|
122
|
-
continue;
|
|
123
|
-
const store_meta = await read_store_meta(entry.name);
|
|
103
|
+
else {
|
|
104
|
+
for await (const sid of list_all_stores()) {
|
|
105
|
+
const store_meta = await read_store_meta(sid);
|
|
124
106
|
for (const meta of store_meta.values()) {
|
|
125
|
-
|
|
126
|
-
if (is_child)
|
|
127
|
-
yield meta;
|
|
107
|
+
yield meta;
|
|
128
108
|
}
|
|
129
109
|
}
|
|
130
110
|
}
|
|
131
|
-
catch { }
|
|
132
111
|
},
|
|
133
112
|
async find_by_hash(store_id, content_hash) {
|
|
134
113
|
const store_meta = await read_store_meta(store_id);
|
|
@@ -140,43 +119,24 @@ export function create_file_backend(config) {
|
|
|
140
119
|
return null;
|
|
141
120
|
},
|
|
142
121
|
};
|
|
143
|
-
const
|
|
122
|
+
const data_storage = {
|
|
144
123
|
async get(data_key) {
|
|
145
124
|
const path = data_path(data_key);
|
|
146
125
|
const file = Bun.file(path);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
return err({ kind: "not_found", store_id: data_key, version: "" });
|
|
151
|
-
}
|
|
152
|
-
return ok({
|
|
153
|
-
stream: () => file.stream(),
|
|
154
|
-
bytes: async () => new Uint8Array(await file.arrayBuffer()),
|
|
155
|
-
});
|
|
126
|
+
if (!(await file.exists()))
|
|
127
|
+
return null;
|
|
128
|
+
return new Uint8Array(await file.arrayBuffer());
|
|
156
129
|
},
|
|
157
|
-
async put(data_key,
|
|
130
|
+
async put(data_key, data) {
|
|
158
131
|
const path = data_path(data_key);
|
|
159
132
|
await mkdir(dirname(path), { recursive: true });
|
|
160
|
-
|
|
161
|
-
const bytes = await to_bytes(input);
|
|
162
|
-
await Bun.write(path, bytes);
|
|
163
|
-
return ok(undefined);
|
|
164
|
-
}
|
|
165
|
-
catch (cause) {
|
|
166
|
-
return err({ kind: "storage_error", cause: cause, operation: "put" });
|
|
167
|
-
}
|
|
133
|
+
await Bun.write(path, data);
|
|
168
134
|
},
|
|
169
135
|
async delete(data_key) {
|
|
170
136
|
const path = data_path(data_key);
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
await file.delete();
|
|
175
|
-
}
|
|
176
|
-
return ok(undefined);
|
|
177
|
-
}
|
|
178
|
-
catch (cause) {
|
|
179
|
-
return err({ kind: "storage_error", cause: cause, operation: "delete" });
|
|
137
|
+
const file = Bun.file(path);
|
|
138
|
+
if (await file.exists()) {
|
|
139
|
+
await file.delete();
|
|
180
140
|
}
|
|
181
141
|
},
|
|
182
142
|
async exists(data_key) {
|
|
@@ -185,6 +145,8 @@ export function create_file_backend(config) {
|
|
|
185
145
|
return file.exists();
|
|
186
146
|
},
|
|
187
147
|
};
|
|
148
|
+
const metadata = create_metadata_client(metadata_storage, emit);
|
|
149
|
+
const data = create_data_client(data_storage, emit);
|
|
188
150
|
const file_path = join(base_path, "_observations.json");
|
|
189
151
|
async function read_observations() {
|
|
190
152
|
const file = Bun.file(file_path);
|
|
@@ -205,7 +167,7 @@ export function create_file_backend(config) {
|
|
|
205
167
|
set_all: write_observations,
|
|
206
168
|
get_one: async (id) => {
|
|
207
169
|
const rows = await read_observations();
|
|
208
|
-
return rows.find(r => r.id === id) ?? null;
|
|
170
|
+
return rows.find((r) => r.id === id) ?? null;
|
|
209
171
|
},
|
|
210
172
|
add_one: async (row) => {
|
|
211
173
|
const rows = await read_observations();
|
|
@@ -214,13 +176,13 @@ export function create_file_backend(config) {
|
|
|
214
176
|
},
|
|
215
177
|
remove_one: async (id) => {
|
|
216
178
|
const rows = await read_observations();
|
|
217
|
-
const idx = rows.findIndex(r => r.id === id);
|
|
179
|
+
const idx = rows.findIndex((r) => r.id === id);
|
|
218
180
|
if (idx === -1)
|
|
219
181
|
return false;
|
|
220
182
|
rows.splice(idx, 1);
|
|
221
183
|
await write_observations(rows);
|
|
222
184
|
return true;
|
|
223
|
-
}
|
|
185
|
+
},
|
|
224
186
|
});
|
|
225
187
|
const observations = create_observations_client(storage, metadata);
|
|
226
188
|
return { metadata, data, observations, on_event };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layered.d.ts","sourceRoot":"","sources":["../../backend/layered.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAiG,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"layered.d.ts","sourceRoot":"","sources":["../../backend/layered.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAiG,MAAM,UAAU,CAAA;AAKtI,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,OAAO,EAAE,CAAA;IACf,KAAK,EAAE,OAAO,EAAE,CAAA;IAChB,aAAa,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;CAClC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAoJ9E"}
|
package/dist/backend/layered.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { ok, err } from '../types';
|
|
6
6
|
import { to_bytes } from '../utils';
|
|
7
|
+
import { first, to_nullable } from '../result';
|
|
7
8
|
/**
|
|
8
9
|
* Creates a layered backend that combines multiple backends with read/write separation.
|
|
9
10
|
* @category Backends
|
|
@@ -71,7 +72,10 @@ export function create_layered_backend(options) {
|
|
|
71
72
|
if (read.length === 0)
|
|
72
73
|
return;
|
|
73
74
|
if (list_strategy === 'first') {
|
|
74
|
-
|
|
75
|
+
const first_backend = to_nullable(first(read));
|
|
76
|
+
if (!first_backend)
|
|
77
|
+
return;
|
|
78
|
+
yield* first_backend.metadata.list(store_id, opts);
|
|
75
79
|
return;
|
|
76
80
|
}
|
|
77
81
|
const seen = new Set();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../backend/memory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../backend/memory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,UAAU,CAAC;AAItD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAI7C,MAAM,MAAM,oBAAoB,GAAG;IAClC,QAAQ,CAAC,EAAE,YAAY,CAAC;CACxB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAoF7E"}
|
package/dist/backend/memory.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* @description In-memory storage backend for testing and development.
|
|
4
4
|
*/
|
|
5
5
|
import { create_observations_client, create_observations_storage } from "../observations";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { create_emitter } from "../utils";
|
|
7
|
+
import { create_metadata_client, create_data_client } from "./base";
|
|
8
8
|
/**
|
|
9
9
|
* Creates an in-memory storage backend.
|
|
10
10
|
* @category Backends
|
|
@@ -40,61 +40,22 @@ export function create_memory_backend(options) {
|
|
|
40
40
|
function make_meta_key(store_id, version) {
|
|
41
41
|
return `${store_id}:${version}`;
|
|
42
42
|
}
|
|
43
|
-
const
|
|
43
|
+
const metadata_storage = {
|
|
44
44
|
async get(store_id, version) {
|
|
45
|
-
|
|
46
|
-
emit({ type: "meta_get", store_id, version, found: !!meta });
|
|
47
|
-
if (!meta) {
|
|
48
|
-
return err({ kind: "not_found", store_id, version });
|
|
49
|
-
}
|
|
50
|
-
return ok(meta);
|
|
45
|
+
return meta_store.get(make_meta_key(store_id, version)) ?? null;
|
|
51
46
|
},
|
|
52
47
|
async put(meta) {
|
|
53
48
|
meta_store.set(make_meta_key(meta.store_id, meta.version), meta);
|
|
54
|
-
emit({ type: "meta_put", store_id: meta.store_id, version: meta.version });
|
|
55
|
-
return ok(undefined);
|
|
56
49
|
},
|
|
57
50
|
async delete(store_id, version) {
|
|
58
51
|
meta_store.delete(make_meta_key(store_id, version));
|
|
59
|
-
emit({ type: "meta_delete", store_id, version });
|
|
60
|
-
return ok(undefined);
|
|
61
|
-
},
|
|
62
|
-
async *list(store_id, opts) {
|
|
63
|
-
const prefix = `${store_id}:`;
|
|
64
|
-
const store_metas = [];
|
|
65
|
-
for (const [key, meta] of meta_store) {
|
|
66
|
-
if (key.startsWith(prefix)) {
|
|
67
|
-
store_metas.push(meta);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
const filtered = filter_snapshots(store_metas, opts);
|
|
71
|
-
let count = 0;
|
|
72
|
-
for (const meta of filtered) {
|
|
73
|
-
yield meta;
|
|
74
|
-
count++;
|
|
75
|
-
}
|
|
76
|
-
emit({ type: "meta_list", store_id, count });
|
|
77
52
|
},
|
|
78
|
-
async
|
|
79
|
-
|
|
80
|
-
const prefix = `${store_id}:`;
|
|
53
|
+
async *list(store_id) {
|
|
54
|
+
const prefix = store_id ? `${store_id}:` : "";
|
|
81
55
|
for (const [key, meta] of meta_store) {
|
|
82
|
-
if (!key.startsWith(prefix))
|
|
83
|
-
continue;
|
|
84
|
-
if (!latest || meta.created_at > latest.created_at) {
|
|
85
|
-
latest = meta;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
if (!latest) {
|
|
89
|
-
return err({ kind: "not_found", store_id, version: "latest" });
|
|
90
|
-
}
|
|
91
|
-
return ok(latest);
|
|
92
|
-
},
|
|
93
|
-
async *get_children(parent_store_id, parent_version) {
|
|
94
|
-
for (const meta of meta_store.values()) {
|
|
95
|
-
const is_child = meta.parents.some(p => p.store_id === parent_store_id && p.version === parent_version);
|
|
96
|
-
if (is_child)
|
|
56
|
+
if (!prefix || key.startsWith(prefix)) {
|
|
97
57
|
yield meta;
|
|
58
|
+
}
|
|
98
59
|
}
|
|
99
60
|
},
|
|
100
61
|
async find_by_hash(store_id, content_hash) {
|
|
@@ -107,36 +68,22 @@ export function create_memory_backend(options) {
|
|
|
107
68
|
return null;
|
|
108
69
|
},
|
|
109
70
|
};
|
|
110
|
-
const
|
|
71
|
+
const data_storage = {
|
|
111
72
|
async get(data_key) {
|
|
112
|
-
|
|
113
|
-
emit({ type: "data_get", store_id: data_key.split("/")[0] ?? data_key, version: data_key, found: !!bytes });
|
|
114
|
-
if (!bytes) {
|
|
115
|
-
return err({ kind: "not_found", store_id: data_key, version: "" });
|
|
116
|
-
}
|
|
117
|
-
return ok({
|
|
118
|
-
stream: () => new ReadableStream({
|
|
119
|
-
start(controller) {
|
|
120
|
-
controller.enqueue(bytes);
|
|
121
|
-
controller.close();
|
|
122
|
-
},
|
|
123
|
-
}),
|
|
124
|
-
bytes: async () => bytes,
|
|
125
|
-
});
|
|
73
|
+
return data_store.get(data_key) ?? null;
|
|
126
74
|
},
|
|
127
|
-
async put(data_key,
|
|
128
|
-
|
|
129
|
-
data_store.set(data_key, bytes);
|
|
130
|
-
return ok(undefined);
|
|
75
|
+
async put(data_key, data) {
|
|
76
|
+
data_store.set(data_key, data);
|
|
131
77
|
},
|
|
132
78
|
async delete(data_key) {
|
|
133
79
|
data_store.delete(data_key);
|
|
134
|
-
return ok(undefined);
|
|
135
80
|
},
|
|
136
81
|
async exists(data_key) {
|
|
137
82
|
return data_store.has(data_key);
|
|
138
83
|
},
|
|
139
84
|
};
|
|
85
|
+
const metadata = create_metadata_client(metadata_storage, emit);
|
|
86
|
+
const data = create_data_client(data_storage, emit);
|
|
140
87
|
const storage = create_observations_storage({
|
|
141
88
|
get_all: async () => Array.from(observation_store.values()),
|
|
142
89
|
set_all: async (rows) => {
|
|
@@ -145,12 +92,14 @@ export function create_memory_backend(options) {
|
|
|
145
92
|
observation_store.set(row.id, row);
|
|
146
93
|
},
|
|
147
94
|
get_one: async (id) => observation_store.get(id) ?? null,
|
|
148
|
-
add_one: async (row) => {
|
|
95
|
+
add_one: async (row) => {
|
|
96
|
+
observation_store.set(row.id, row);
|
|
97
|
+
},
|
|
149
98
|
remove_one: async (id) => {
|
|
150
99
|
const had = observation_store.has(id);
|
|
151
100
|
observation_store.delete(id);
|
|
152
101
|
return had;
|
|
153
|
-
}
|
|
102
|
+
},
|
|
154
103
|
});
|
|
155
104
|
const observations = create_observations_client(storage, metadata);
|
|
156
105
|
return { metadata, data, observations, on_event };
|
package/dist/backends.d.ts
CHANGED
|
@@ -7,5 +7,6 @@ export { create_memory_backend, type MemoryBackendOptions } from './backend/memo
|
|
|
7
7
|
export { create_file_backend, type FileBackendConfig } from './backend/file';
|
|
8
8
|
export { create_cloudflare_backend, type CloudflareBackendConfig } from './backend/cloudflare';
|
|
9
9
|
export { create_layered_backend, type LayeredBackendOptions } from './backend/layered';
|
|
10
|
+
export { create_metadata_client, create_data_client, type MetadataStorage, type DataStorage } from './backend/base';
|
|
10
11
|
export type { Backend, MetadataClient, DataClient, DataHandle, EventHandler, CorpusEvent } from './types';
|
|
11
12
|
//# sourceMappingURL=backends.d.ts.map
|
package/dist/backends.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backends.d.ts","sourceRoot":"","sources":["../backends.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,qBAAqB,EAAE,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AACnF,OAAO,EAAE,mBAAmB,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAC5E,OAAO,EAAE,yBAAyB,EAAE,KAAK,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAC9F,OAAO,EAAE,sBAAsB,EAAE,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AACtF,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"backends.d.ts","sourceRoot":"","sources":["../backends.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,qBAAqB,EAAE,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AACnF,OAAO,EAAE,mBAAmB,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAC5E,OAAO,EAAE,yBAAyB,EAAE,KAAK,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAC9F,OAAO,EAAE,sBAAsB,EAAE,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AACtF,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACnH,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA"}
|
package/dist/backends.js
CHANGED
|
@@ -7,3 +7,4 @@ export { create_memory_backend } from './backend/memory';
|
|
|
7
7
|
export { create_file_backend } from './backend/file';
|
|
8
8
|
export { create_cloudflare_backend } from './backend/cloudflare';
|
|
9
9
|
export { create_layered_backend } from './backend/layered';
|
|
10
|
+
export { create_metadata_client, create_data_client } from './backend/base';
|
package/dist/cloudflare.d.ts
CHANGED
|
@@ -9,4 +9,5 @@ export { json_codec, text_codec, binary_codec, compute_hash, generate_version }
|
|
|
9
9
|
export { corpus_snapshots, type CorpusSnapshotRow, type CorpusSnapshotInsert } from './schema';
|
|
10
10
|
export type { ContentType, ParentRef, SnapshotMeta, Snapshot, DataHandle, MetadataClient, DataClient, ListOpts, Backend, Codec, Store, StoreDefinition, PutOpts, CorpusBuilder, Corpus, CorpusError, Result, CorpusEvent, EventHandler, } from './types';
|
|
11
11
|
export { ok, err, define_store } from './types';
|
|
12
|
+
export * from './observations';
|
|
12
13
|
//# sourceMappingURL=cloudflare.d.ts.map
|
package/dist/cloudflare.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../cloudflare.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEtD,OAAO,EAAE,qBAAqB,EAAE,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AACnF,OAAO,EAAE,yBAAyB,EAAE,KAAK,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAE9F,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE9F,OAAO,EAAE,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAE9F,YAAY,EACV,WAAW,EACX,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,cAAc,EACd,UAAU,EACV,QAAQ,EACR,OAAO,EACP,KAAK,EACL,KAAK,EACL,eAAe,EACf,OAAO,EACP,aAAa,EACb,MAAM,EACN,WAAW,EACX,MAAM,EACN,WAAW,EACX,YAAY,GACb,MAAM,SAAS,CAAA;AAEhB,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../cloudflare.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEtD,OAAO,EAAE,qBAAqB,EAAE,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AACnF,OAAO,EAAE,yBAAyB,EAAE,KAAK,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAE9F,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE9F,OAAO,EAAE,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAE9F,YAAY,EACV,WAAW,EACX,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,cAAc,EACd,UAAU,EACV,QAAQ,EACR,OAAO,EACP,KAAK,EACL,KAAK,EACL,eAAe,EACf,OAAO,EACP,aAAa,EACb,MAAM,EACN,WAAW,EACX,MAAM,EACN,WAAW,EACX,YAAY,GACb,MAAM,SAAS,CAAA;AAEhB,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE/C,cAAc,gBAAgB,CAAA"}
|
package/dist/cloudflare.js
CHANGED
|
@@ -8,3 +8,4 @@ export { create_cloudflare_backend } from './backend/cloudflare';
|
|
|
8
8
|
export { json_codec, text_codec, binary_codec, compute_hash, generate_version } from './utils';
|
|
9
9
|
export { corpus_snapshots } from './schema';
|
|
10
10
|
export { ok, err, define_store } from './types';
|
|
11
|
+
export * from './observations';
|