@f0rbit/corpus 0.1.5 → 0.1.6
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/cloudflare.d.ts.map +1 -1
- package/dist/backend/cloudflare.js +140 -23
- package/dist/backend/file.d.ts.map +1 -1
- package/dist/backend/file.js +47 -48
- package/dist/backend/layered.d.ts.map +1 -1
- package/dist/backend/layered.js +67 -19
- package/dist/backend/memory.d.ts +2 -1
- package/dist/backend/memory.d.ts.map +1 -1
- package/dist/backend/memory.js +29 -43
- package/dist/corpus.d.ts +11 -0
- package/dist/corpus.d.ts.map +1 -1
- package/dist/corpus.js +52 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/observations/client.d.ts +12 -0
- package/dist/observations/client.d.ts.map +1 -0
- package/dist/observations/client.js +115 -0
- package/dist/observations/index.d.ts +12 -0
- package/dist/observations/index.d.ts.map +1 -0
- package/dist/observations/index.js +11 -0
- package/dist/observations/schema.d.ts +267 -0
- package/dist/observations/schema.d.ts.map +1 -0
- package/dist/observations/schema.js +55 -0
- package/dist/observations/storage.d.ts +75 -0
- package/dist/observations/storage.d.ts.map +1 -0
- package/dist/observations/storage.js +137 -0
- package/dist/observations/types.d.ts +219 -0
- package/dist/observations/types.d.ts.map +1 -0
- package/dist/observations/types.js +40 -0
- package/dist/observations/utils.d.ts +183 -0
- package/dist/observations/utils.d.ts.map +1 -0
- package/dist/observations/utils.js +272 -0
- package/dist/sst.d.ts +1 -1
- package/dist/sst.d.ts.map +1 -1
- package/dist/sst.js +20 -0
- package/dist/types.d.ts +61 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +38 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +84 -0
- package/package.json +1 -1
- package/dist/codecs.d.ts +0 -8
- package/dist/codecs.d.ts.map +0 -1
- package/dist/codecs.js +0 -6
- package/dist/core.d.ts +0 -9
- package/dist/core.d.ts.map +0 -1
- package/dist/core.js +0 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../backend/cloudflare.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,OAAO,
|
|
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;AAMrH,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"}
|
|
@@ -2,10 +2,138 @@
|
|
|
2
2
|
* @module Backends
|
|
3
3
|
* @description Cloudflare Workers storage backend using D1 and R2.
|
|
4
4
|
*/
|
|
5
|
-
import { eq, and, desc, lt, gt, like, sql } from "drizzle-orm";
|
|
5
|
+
import { eq, and, desc, lt, gt, like, sql, inArray } from "drizzle-orm";
|
|
6
6
|
import { drizzle } from "drizzle-orm/d1";
|
|
7
|
+
import { create_emitter, parse_snapshot_meta } from "../utils";
|
|
7
8
|
import { ok, err } from "../types";
|
|
8
9
|
import { corpus_snapshots } from "../schema";
|
|
10
|
+
import { corpus_observations, create_observations_client } from "../observations";
|
|
11
|
+
function create_cloudflare_storage(db) {
|
|
12
|
+
return {
|
|
13
|
+
async put_row(row) {
|
|
14
|
+
try {
|
|
15
|
+
await db.insert(corpus_observations).values(row);
|
|
16
|
+
return ok(row);
|
|
17
|
+
}
|
|
18
|
+
catch (cause) {
|
|
19
|
+
return err({
|
|
20
|
+
kind: "storage_error",
|
|
21
|
+
cause: cause,
|
|
22
|
+
operation: "observations.put"
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
async get_row(id) {
|
|
27
|
+
try {
|
|
28
|
+
const rows = await db
|
|
29
|
+
.select()
|
|
30
|
+
.from(corpus_observations)
|
|
31
|
+
.where(eq(corpus_observations.id, id))
|
|
32
|
+
.limit(1);
|
|
33
|
+
return ok(rows[0] ?? null);
|
|
34
|
+
}
|
|
35
|
+
catch (cause) {
|
|
36
|
+
return err({
|
|
37
|
+
kind: "storage_error",
|
|
38
|
+
cause: cause,
|
|
39
|
+
operation: "observations.get"
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
async *query_rows(opts = {}) {
|
|
44
|
+
const conditions = [];
|
|
45
|
+
if (opts.type) {
|
|
46
|
+
if (Array.isArray(opts.type)) {
|
|
47
|
+
conditions.push(inArray(corpus_observations.type, opts.type));
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
conditions.push(eq(corpus_observations.type, opts.type));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (opts.source_store_id) {
|
|
54
|
+
conditions.push(eq(corpus_observations.source_store_id, opts.source_store_id));
|
|
55
|
+
}
|
|
56
|
+
if (opts.source_version) {
|
|
57
|
+
conditions.push(eq(corpus_observations.source_version, opts.source_version));
|
|
58
|
+
}
|
|
59
|
+
if (opts.source_prefix) {
|
|
60
|
+
conditions.push(like(corpus_observations.source_version, `${opts.source_prefix}%`));
|
|
61
|
+
}
|
|
62
|
+
if (opts.created_after) {
|
|
63
|
+
conditions.push(gt(corpus_observations.created_at, opts.created_after));
|
|
64
|
+
}
|
|
65
|
+
if (opts.created_before) {
|
|
66
|
+
conditions.push(lt(corpus_observations.created_at, opts.created_before));
|
|
67
|
+
}
|
|
68
|
+
if (opts.observed_after) {
|
|
69
|
+
conditions.push(gt(corpus_observations.observed_at, opts.observed_after));
|
|
70
|
+
}
|
|
71
|
+
if (opts.observed_before) {
|
|
72
|
+
conditions.push(lt(corpus_observations.observed_at, opts.observed_before));
|
|
73
|
+
}
|
|
74
|
+
let query = db
|
|
75
|
+
.select()
|
|
76
|
+
.from(corpus_observations)
|
|
77
|
+
.where(conditions.length > 0 ? and(...conditions) : undefined)
|
|
78
|
+
.orderBy(desc(corpus_observations.created_at));
|
|
79
|
+
if (opts.limit) {
|
|
80
|
+
query = query.limit(opts.limit);
|
|
81
|
+
}
|
|
82
|
+
const rows = await query;
|
|
83
|
+
for (const row of rows) {
|
|
84
|
+
yield row;
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
async delete_row(id) {
|
|
88
|
+
try {
|
|
89
|
+
const existing = await db
|
|
90
|
+
.select()
|
|
91
|
+
.from(corpus_observations)
|
|
92
|
+
.where(eq(corpus_observations.id, id))
|
|
93
|
+
.limit(1);
|
|
94
|
+
if (existing.length === 0) {
|
|
95
|
+
return ok(false);
|
|
96
|
+
}
|
|
97
|
+
await db.delete(corpus_observations).where(eq(corpus_observations.id, id));
|
|
98
|
+
return ok(true);
|
|
99
|
+
}
|
|
100
|
+
catch (cause) {
|
|
101
|
+
return err({
|
|
102
|
+
kind: "storage_error",
|
|
103
|
+
cause: cause,
|
|
104
|
+
operation: "observations.delete"
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
async delete_by_source(store_id, version, path) {
|
|
109
|
+
try {
|
|
110
|
+
const conditions = [
|
|
111
|
+
eq(corpus_observations.source_store_id, store_id),
|
|
112
|
+
eq(corpus_observations.source_version, version)
|
|
113
|
+
];
|
|
114
|
+
if (path !== undefined) {
|
|
115
|
+
conditions.push(eq(corpus_observations.source_path, path));
|
|
116
|
+
}
|
|
117
|
+
const toDelete = await db
|
|
118
|
+
.select()
|
|
119
|
+
.from(corpus_observations)
|
|
120
|
+
.where(and(...conditions));
|
|
121
|
+
const count = toDelete.length;
|
|
122
|
+
if (count > 0) {
|
|
123
|
+
await db.delete(corpus_observations).where(and(...conditions));
|
|
124
|
+
}
|
|
125
|
+
return ok(count);
|
|
126
|
+
}
|
|
127
|
+
catch (cause) {
|
|
128
|
+
return err({
|
|
129
|
+
kind: "storage_error",
|
|
130
|
+
cause: cause,
|
|
131
|
+
operation: "observations.delete_by_source"
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
9
137
|
/**
|
|
10
138
|
* Creates a Cloudflare Workers storage backend using D1 and R2.
|
|
11
139
|
* @category Backends
|
|
@@ -45,22 +173,9 @@ import { corpus_snapshots } from "../schema";
|
|
|
45
173
|
export function create_cloudflare_backend(config) {
|
|
46
174
|
const db = drizzle(config.d1);
|
|
47
175
|
const { r2, on_event } = config;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
function row_to_meta(row) {
|
|
52
|
-
return {
|
|
53
|
-
store_id: row.store_id,
|
|
54
|
-
version: row.version,
|
|
55
|
-
parents: JSON.parse(row.parents),
|
|
56
|
-
created_at: new Date(row.created_at),
|
|
57
|
-
invoked_at: row.invoked_at ? new Date(row.invoked_at) : undefined,
|
|
58
|
-
content_hash: row.content_hash,
|
|
59
|
-
content_type: row.content_type,
|
|
60
|
-
size_bytes: row.size_bytes,
|
|
61
|
-
data_key: row.data_key,
|
|
62
|
-
tags: row.tags ? JSON.parse(row.tags) : undefined,
|
|
63
|
-
};
|
|
176
|
+
const emit = create_emitter(on_event);
|
|
177
|
+
function snapshot_row_to_meta(row) {
|
|
178
|
+
return parse_snapshot_meta(row);
|
|
64
179
|
}
|
|
65
180
|
const metadata = {
|
|
66
181
|
async get(store_id, version) {
|
|
@@ -75,7 +190,7 @@ export function create_cloudflare_backend(config) {
|
|
|
75
190
|
if (!row) {
|
|
76
191
|
return err({ kind: "not_found", store_id, version });
|
|
77
192
|
}
|
|
78
|
-
return ok(
|
|
193
|
+
return ok(snapshot_row_to_meta(row));
|
|
79
194
|
}
|
|
80
195
|
catch (cause) {
|
|
81
196
|
const error = { kind: "storage_error", cause: cause, operation: "metadata.get" };
|
|
@@ -152,7 +267,7 @@ export function create_cloudflare_backend(config) {
|
|
|
152
267
|
const rows = await query;
|
|
153
268
|
let count = 0;
|
|
154
269
|
for (const row of rows) {
|
|
155
|
-
const meta =
|
|
270
|
+
const meta = snapshot_row_to_meta(row);
|
|
156
271
|
if (opts?.tags?.length && !opts.tags.every(t => meta.tags?.includes(t))) {
|
|
157
272
|
continue;
|
|
158
273
|
}
|
|
@@ -168,7 +283,7 @@ export function create_cloudflare_backend(config) {
|
|
|
168
283
|
if (!row) {
|
|
169
284
|
return err({ kind: "not_found", store_id, version: "latest" });
|
|
170
285
|
}
|
|
171
|
-
return ok(
|
|
286
|
+
return ok(snapshot_row_to_meta(row));
|
|
172
287
|
}
|
|
173
288
|
catch (cause) {
|
|
174
289
|
const error = { kind: "storage_error", cause: cause, operation: "metadata.get_latest" };
|
|
@@ -186,7 +301,7 @@ export function create_cloudflare_backend(config) {
|
|
|
186
301
|
AND json_extract(value, '$.version') = ${parent_version}
|
|
187
302
|
)`);
|
|
188
303
|
for (const row of rows) {
|
|
189
|
-
yield
|
|
304
|
+
yield snapshot_row_to_meta(row);
|
|
190
305
|
}
|
|
191
306
|
},
|
|
192
307
|
async find_by_hash(store_id, content_hash) {
|
|
@@ -197,7 +312,7 @@ export function create_cloudflare_backend(config) {
|
|
|
197
312
|
.where(and(eq(corpus_snapshots.store_id, store_id), eq(corpus_snapshots.content_hash, content_hash)))
|
|
198
313
|
.limit(1);
|
|
199
314
|
const row = rows[0];
|
|
200
|
-
return row ?
|
|
315
|
+
return row ? snapshot_row_to_meta(row) : null;
|
|
201
316
|
}
|
|
202
317
|
catch {
|
|
203
318
|
return null;
|
|
@@ -255,5 +370,7 @@ export function create_cloudflare_backend(config) {
|
|
|
255
370
|
}
|
|
256
371
|
},
|
|
257
372
|
};
|
|
258
|
-
|
|
373
|
+
const storage = create_cloudflare_storage(db);
|
|
374
|
+
const observations = create_observations_client(storage, metadata);
|
|
375
|
+
return { metadata, data, observations, on_event };
|
|
259
376
|
}
|
|
@@ -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,EAAiE,YAAY,EAAE,MAAM,UAAU,CAAC;AAQrH,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,CA6MtE"}
|
package/dist/backend/file.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
* @module Backends
|
|
3
3
|
* @description File-system storage backend for local persistence.
|
|
4
4
|
*/
|
|
5
|
+
import { create_observations_client, create_observations_storage } from "../observations";
|
|
5
6
|
import { ok, err } from "../types";
|
|
7
|
+
import { to_bytes, create_emitter, filter_snapshots, parse_snapshot_meta } from "../utils";
|
|
6
8
|
import { mkdir, readdir } from "node:fs/promises";
|
|
7
9
|
import { join, dirname } from "node:path";
|
|
8
10
|
/**
|
|
@@ -38,9 +40,7 @@ import { join, dirname } from "node:path";
|
|
|
38
40
|
*/
|
|
39
41
|
export function create_file_backend(config) {
|
|
40
42
|
const { base_path, on_event } = config;
|
|
41
|
-
|
|
42
|
-
on_event?.(event);
|
|
43
|
-
}
|
|
43
|
+
const emit = create_emitter(on_event);
|
|
44
44
|
function meta_path(store_id) {
|
|
45
45
|
return join(base_path, store_id, "_meta.json");
|
|
46
46
|
}
|
|
@@ -54,13 +54,8 @@ export function create_file_backend(config) {
|
|
|
54
54
|
return new Map();
|
|
55
55
|
try {
|
|
56
56
|
const content = await file.text();
|
|
57
|
-
const entries = JSON.parse(content
|
|
58
|
-
|
|
59
|
-
return value ? new Date(value) : value;
|
|
60
|
-
}
|
|
61
|
-
return value;
|
|
62
|
-
});
|
|
63
|
-
return new Map(entries);
|
|
57
|
+
const entries = JSON.parse(content);
|
|
58
|
+
return new Map(entries.map(([key, raw]) => [key, parse_snapshot_meta(raw)]));
|
|
64
59
|
}
|
|
65
60
|
catch {
|
|
66
61
|
return new Map();
|
|
@@ -98,20 +93,9 @@ export function create_file_backend(config) {
|
|
|
98
93
|
},
|
|
99
94
|
async *list(store_id, opts) {
|
|
100
95
|
const store_meta = await read_store_meta(store_id);
|
|
101
|
-
const
|
|
102
|
-
.filter(meta => {
|
|
103
|
-
if (opts?.before && meta.created_at >= opts.before)
|
|
104
|
-
return false;
|
|
105
|
-
if (opts?.after && meta.created_at <= opts.after)
|
|
106
|
-
return false;
|
|
107
|
-
if (opts?.tags?.length && !opts.tags.every(t => meta.tags?.includes(t)))
|
|
108
|
-
return false;
|
|
109
|
-
return true;
|
|
110
|
-
})
|
|
111
|
-
.sort((a, b) => b.created_at.getTime() - a.created_at.getTime());
|
|
112
|
-
const limit = opts?.limit ?? Infinity;
|
|
96
|
+
const filtered = filter_snapshots(Array.from(store_meta.values()), opts);
|
|
113
97
|
let count = 0;
|
|
114
|
-
for (const meta of
|
|
98
|
+
for (const meta of filtered) {
|
|
115
99
|
yield meta;
|
|
116
100
|
count++;
|
|
117
101
|
}
|
|
@@ -174,21 +158,8 @@ export function create_file_backend(config) {
|
|
|
174
158
|
const path = data_path(data_key);
|
|
175
159
|
await mkdir(dirname(path), { recursive: true });
|
|
176
160
|
try {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
const chunks = [];
|
|
182
|
-
const reader = input.getReader();
|
|
183
|
-
while (true) {
|
|
184
|
-
const { done, value } = await reader.read();
|
|
185
|
-
if (done)
|
|
186
|
-
break;
|
|
187
|
-
chunks.push(value);
|
|
188
|
-
}
|
|
189
|
-
const bytes = concat_bytes(chunks);
|
|
190
|
-
await Bun.write(path, bytes);
|
|
191
|
-
}
|
|
161
|
+
const bytes = await to_bytes(input);
|
|
162
|
+
await Bun.write(path, bytes);
|
|
192
163
|
return ok(undefined);
|
|
193
164
|
}
|
|
194
165
|
catch (cause) {
|
|
@@ -214,15 +185,43 @@ export function create_file_backend(config) {
|
|
|
214
185
|
return file.exists();
|
|
215
186
|
},
|
|
216
187
|
};
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
188
|
+
const file_path = join(base_path, "_observations.json");
|
|
189
|
+
async function read_observations() {
|
|
190
|
+
const file = Bun.file(file_path);
|
|
191
|
+
if (!(await file.exists()))
|
|
192
|
+
return [];
|
|
193
|
+
try {
|
|
194
|
+
return await file.json();
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
226
199
|
}
|
|
227
|
-
|
|
200
|
+
async function write_observations(rows) {
|
|
201
|
+
await Bun.write(file_path, JSON.stringify(rows, null, 2));
|
|
202
|
+
}
|
|
203
|
+
const storage = create_observations_storage({
|
|
204
|
+
get_all: read_observations,
|
|
205
|
+
set_all: write_observations,
|
|
206
|
+
get_one: async (id) => {
|
|
207
|
+
const rows = await read_observations();
|
|
208
|
+
return rows.find(r => r.id === id) ?? null;
|
|
209
|
+
},
|
|
210
|
+
add_one: async (row) => {
|
|
211
|
+
const rows = await read_observations();
|
|
212
|
+
rows.push(row);
|
|
213
|
+
await write_observations(rows);
|
|
214
|
+
},
|
|
215
|
+
remove_one: async (id) => {
|
|
216
|
+
const rows = await read_observations();
|
|
217
|
+
const idx = rows.findIndex(r => r.id === id);
|
|
218
|
+
if (idx === -1)
|
|
219
|
+
return false;
|
|
220
|
+
rows.splice(idx, 1);
|
|
221
|
+
await write_observations(rows);
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
const observations = create_observations_client(storage, metadata);
|
|
226
|
+
return { metadata, data, observations, on_event };
|
|
228
227
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layered.d.ts","sourceRoot":"","sources":["../../backend/layered.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,
|
|
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;AAItI,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,CAkJ9E"}
|
package/dist/backend/layered.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @description Layered backend for caching and replication strategies.
|
|
4
4
|
*/
|
|
5
5
|
import { ok, err } from '../types';
|
|
6
|
+
import { to_bytes } from '../utils';
|
|
6
7
|
/**
|
|
7
8
|
* Creates a layered backend that combines multiple backends with read/write separation.
|
|
8
9
|
* @category Backends
|
|
@@ -169,25 +170,72 @@ export function create_layered_backend(options) {
|
|
|
169
170
|
return false;
|
|
170
171
|
},
|
|
171
172
|
};
|
|
172
|
-
|
|
173
|
+
const observations = createLayeredObservationsClient(read, write);
|
|
174
|
+
return {
|
|
175
|
+
metadata,
|
|
176
|
+
data,
|
|
177
|
+
...(observations ? { observations } : {}),
|
|
178
|
+
};
|
|
173
179
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
while (true) {
|
|
180
|
-
const { done, value } = await reader.read();
|
|
181
|
-
if (done)
|
|
182
|
-
break;
|
|
183
|
-
chunks.push(value);
|
|
184
|
-
}
|
|
185
|
-
const total = chunks.reduce((sum, c) => sum + c.length, 0);
|
|
186
|
-
const result = new Uint8Array(total);
|
|
187
|
-
let offset = 0;
|
|
188
|
-
for (const chunk of chunks) {
|
|
189
|
-
result.set(chunk, offset);
|
|
190
|
-
offset += chunk.length;
|
|
180
|
+
function createLayeredObservationsClient(readLayers, writeLayers) {
|
|
181
|
+
const readLayer = readLayers.find(l => l.observations);
|
|
182
|
+
const writeLayersWithObs = writeLayers.filter(l => l.observations);
|
|
183
|
+
if (!readLayer?.observations && writeLayersWithObs.length === 0) {
|
|
184
|
+
return undefined;
|
|
191
185
|
}
|
|
192
|
-
|
|
186
|
+
const primary = readLayer?.observations;
|
|
187
|
+
return {
|
|
188
|
+
async put(type, opts) {
|
|
189
|
+
if (writeLayersWithObs.length === 0) {
|
|
190
|
+
return err({ kind: 'invalid_config', message: 'No write layers support observations' });
|
|
191
|
+
}
|
|
192
|
+
let result;
|
|
193
|
+
for (const layer of writeLayersWithObs) {
|
|
194
|
+
result = await layer.observations.put(type, opts);
|
|
195
|
+
if (!result.ok)
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
return result;
|
|
199
|
+
},
|
|
200
|
+
async get(id) {
|
|
201
|
+
if (!primary) {
|
|
202
|
+
return err({ kind: 'observation_not_found', id });
|
|
203
|
+
}
|
|
204
|
+
return primary.get(id);
|
|
205
|
+
},
|
|
206
|
+
async *query(opts) {
|
|
207
|
+
if (!primary)
|
|
208
|
+
return;
|
|
209
|
+
yield* primary.query(opts);
|
|
210
|
+
},
|
|
211
|
+
async *query_meta(opts) {
|
|
212
|
+
if (!primary)
|
|
213
|
+
return;
|
|
214
|
+
yield* primary.query_meta(opts);
|
|
215
|
+
},
|
|
216
|
+
async delete(id) {
|
|
217
|
+
if (writeLayersWithObs.length === 0) {
|
|
218
|
+
return err({ kind: 'observation_not_found', id });
|
|
219
|
+
}
|
|
220
|
+
let result;
|
|
221
|
+
for (const layer of writeLayersWithObs) {
|
|
222
|
+
result = await layer.observations.delete(id);
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
225
|
+
},
|
|
226
|
+
async delete_by_source(source) {
|
|
227
|
+
let total = 0;
|
|
228
|
+
for (const layer of writeLayersWithObs) {
|
|
229
|
+
const result = await layer.observations.delete_by_source(source);
|
|
230
|
+
if (result.ok)
|
|
231
|
+
total += result.value;
|
|
232
|
+
}
|
|
233
|
+
return ok(total);
|
|
234
|
+
},
|
|
235
|
+
async is_stale(pointer) {
|
|
236
|
+
if (!primary)
|
|
237
|
+
return false;
|
|
238
|
+
return primary.is_stale(pointer);
|
|
239
|
+
},
|
|
240
|
+
};
|
|
193
241
|
}
|
package/dist/backend/memory.d.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* @module Backends
|
|
3
3
|
* @description In-memory storage backend for testing and development.
|
|
4
4
|
*/
|
|
5
|
-
import type { Backend
|
|
5
|
+
import type { Backend } from "../types";
|
|
6
|
+
import type { EventHandler } from "../types";
|
|
6
7
|
export type MemoryBackendOptions = {
|
|
7
8
|
on_event?: EventHandler;
|
|
8
9
|
};
|
|
@@ -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,EAAiE,MAAM,UAAU,CAAC;AAKvG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,MAAM,MAAM,oBAAoB,GAAG;IAClC,QAAQ,CAAC,EAAE,YAAY,CAAC;CACxB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CA4I7E"}
|
package/dist/backend/memory.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
* @module Backends
|
|
3
3
|
* @description In-memory storage backend for testing and development.
|
|
4
4
|
*/
|
|
5
|
+
import { create_observations_client, create_observations_storage } from "../observations";
|
|
5
6
|
import { ok, err } from "../types";
|
|
7
|
+
import { to_bytes, create_emitter, filter_snapshots } from "../utils";
|
|
6
8
|
/**
|
|
7
9
|
* Creates an in-memory storage backend.
|
|
8
10
|
* @category Backends
|
|
@@ -32,10 +34,9 @@ import { ok, err } from "../types";
|
|
|
32
34
|
export function create_memory_backend(options) {
|
|
33
35
|
const meta_store = new Map();
|
|
34
36
|
const data_store = new Map();
|
|
37
|
+
const observation_store = new Map();
|
|
35
38
|
const on_event = options?.on_event;
|
|
36
|
-
|
|
37
|
-
on_event?.(event);
|
|
38
|
-
}
|
|
39
|
+
const emit = create_emitter(on_event);
|
|
39
40
|
function make_meta_key(store_id, version) {
|
|
40
41
|
return `${store_id}:${version}`;
|
|
41
42
|
}
|
|
@@ -60,23 +61,16 @@ export function create_memory_backend(options) {
|
|
|
60
61
|
},
|
|
61
62
|
async *list(store_id, opts) {
|
|
62
63
|
const prefix = `${store_id}:`;
|
|
63
|
-
const
|
|
64
|
+
const store_metas = [];
|
|
64
65
|
for (const [key, meta] of meta_store) {
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
continue;
|
|
69
|
-
if (opts?.after && meta.created_at <= opts.after)
|
|
70
|
-
continue;
|
|
71
|
-
if (opts?.tags?.length && !opts.tags.every(t => meta.tags?.includes(t)))
|
|
72
|
-
continue;
|
|
73
|
-
matches.push(meta);
|
|
66
|
+
if (key.startsWith(prefix)) {
|
|
67
|
+
store_metas.push(meta);
|
|
68
|
+
}
|
|
74
69
|
}
|
|
75
|
-
|
|
76
|
-
const limit = opts?.limit ?? Infinity;
|
|
70
|
+
const filtered = filter_snapshots(store_metas, opts);
|
|
77
71
|
let count = 0;
|
|
78
|
-
for (const
|
|
79
|
-
yield
|
|
72
|
+
for (const meta of filtered) {
|
|
73
|
+
yield meta;
|
|
80
74
|
count++;
|
|
81
75
|
}
|
|
82
76
|
emit({ type: "meta_list", store_id, count });
|
|
@@ -131,21 +125,7 @@ export function create_memory_backend(options) {
|
|
|
131
125
|
});
|
|
132
126
|
},
|
|
133
127
|
async put(data_key, input) {
|
|
134
|
-
|
|
135
|
-
if (input instanceof Uint8Array) {
|
|
136
|
-
bytes = input;
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
const chunks = [];
|
|
140
|
-
const reader = input.getReader();
|
|
141
|
-
while (true) {
|
|
142
|
-
const { done, value } = await reader.read();
|
|
143
|
-
if (done)
|
|
144
|
-
break;
|
|
145
|
-
chunks.push(value);
|
|
146
|
-
}
|
|
147
|
-
bytes = concat_bytes(chunks);
|
|
148
|
-
}
|
|
128
|
+
const bytes = await to_bytes(input);
|
|
149
129
|
data_store.set(data_key, bytes);
|
|
150
130
|
return ok(undefined);
|
|
151
131
|
},
|
|
@@ -157,15 +137,21 @@ export function create_memory_backend(options) {
|
|
|
157
137
|
return data_store.has(data_key);
|
|
158
138
|
},
|
|
159
139
|
};
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
140
|
+
const storage = create_observations_storage({
|
|
141
|
+
get_all: async () => Array.from(observation_store.values()),
|
|
142
|
+
set_all: async (rows) => {
|
|
143
|
+
observation_store.clear();
|
|
144
|
+
for (const row of rows)
|
|
145
|
+
observation_store.set(row.id, row);
|
|
146
|
+
},
|
|
147
|
+
get_one: async (id) => observation_store.get(id) ?? null,
|
|
148
|
+
add_one: async (row) => { observation_store.set(row.id, row); },
|
|
149
|
+
remove_one: async (id) => {
|
|
150
|
+
const had = observation_store.has(id);
|
|
151
|
+
observation_store.delete(id);
|
|
152
|
+
return had;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
const observations = create_observations_client(storage, metadata);
|
|
156
|
+
return { metadata, data, observations, on_event };
|
|
171
157
|
}
|
package/dist/corpus.d.ts
CHANGED
|
@@ -64,6 +64,17 @@ export declare function create_store<T>(backend: Backend, definition: StoreDefin
|
|
|
64
64
|
* // Type-safe access to stores
|
|
65
65
|
* await corpus.stores.users.put({ name: 'Alice', email: 'alice@example.com' })
|
|
66
66
|
* await corpus.stores.notes.put('Hello, world!')
|
|
67
|
+
*
|
|
68
|
+
* // With observations
|
|
69
|
+
* const corpus_with_obs = create_corpus()
|
|
70
|
+
* .with_backend(create_memory_backend())
|
|
71
|
+
* .with_store(users)
|
|
72
|
+
* .with_observations([EntityType, SentimentType])
|
|
73
|
+
* .build()
|
|
74
|
+
*
|
|
75
|
+
* // Pointer utilities
|
|
76
|
+
* const pointer = corpus_with_obs.create_pointer('users', 'v123', '$.name')
|
|
77
|
+
* const value = await corpus_with_obs.resolve_pointer(pointer)
|
|
67
78
|
* ```
|
|
68
79
|
*/
|
|
69
80
|
export declare function create_corpus(): CorpusBuilder<{}>;
|
package/dist/corpus.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"corpus.d.ts","sourceRoot":"","sources":["../corpus.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAU,aAAa,EAAE,eAAe,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"corpus.d.ts","sourceRoot":"","sources":["../corpus.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAU,aAAa,EAAE,eAAe,EAAE,KAAK,EAAyE,MAAM,SAAS,CAAA;AAM5J;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAmJlG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,aAAa,IAAI,aAAa,CAAC,EAAE,CAAC,CAiFjD"}
|