@f0rbit/corpus 0.1.2 → 0.1.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.
- package/dist/backend/layered.d.ts +8 -0
- package/dist/backend/layered.d.ts.map +1 -0
- package/dist/backend/layered.js +155 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Backend } from '../types';
|
|
2
|
+
export type LayeredBackendOptions = {
|
|
3
|
+
read: Backend[];
|
|
4
|
+
write: Backend[];
|
|
5
|
+
list_strategy?: 'merge' | 'first';
|
|
6
|
+
};
|
|
7
|
+
export declare function create_layered_backend(options: LayeredBackendOptions): Backend;
|
|
8
|
+
//# sourceMappingURL=layered.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layered.d.ts","sourceRoot":"","sources":["../../backend/layered.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAA6E,MAAM,UAAU,CAAA;AAGlH,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,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CA4I9E"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { ok, err } from '../types';
|
|
2
|
+
export function create_layered_backend(options) {
|
|
3
|
+
const { read, write, list_strategy = 'merge' } = options;
|
|
4
|
+
const metadata = {
|
|
5
|
+
async get(store_id, version) {
|
|
6
|
+
for (const backend of read) {
|
|
7
|
+
const result = await backend.metadata.get(store_id, version);
|
|
8
|
+
if (result.ok)
|
|
9
|
+
return result;
|
|
10
|
+
if (result.error.kind !== 'not_found')
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
return err({ kind: 'not_found', store_id, version });
|
|
14
|
+
},
|
|
15
|
+
async put(meta) {
|
|
16
|
+
for (const backend of write) {
|
|
17
|
+
const result = await backend.metadata.put(meta);
|
|
18
|
+
if (!result.ok)
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
return ok(undefined);
|
|
22
|
+
},
|
|
23
|
+
async delete(store_id, version) {
|
|
24
|
+
for (const backend of write) {
|
|
25
|
+
const result = await backend.metadata.delete(store_id, version);
|
|
26
|
+
if (!result.ok && result.error.kind !== 'not_found')
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
return ok(undefined);
|
|
30
|
+
},
|
|
31
|
+
async *list(store_id, opts) {
|
|
32
|
+
if (read.length === 0)
|
|
33
|
+
return;
|
|
34
|
+
if (list_strategy === 'first') {
|
|
35
|
+
yield* read[0].metadata.list(store_id, opts);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const seen = new Set();
|
|
39
|
+
const all = [];
|
|
40
|
+
for (const backend of read) {
|
|
41
|
+
for await (const meta of backend.metadata.list(store_id, opts)) {
|
|
42
|
+
if (seen.has(meta.version))
|
|
43
|
+
continue;
|
|
44
|
+
seen.add(meta.version);
|
|
45
|
+
all.push(meta);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
all.sort((a, b) => b.created_at.getTime() - a.created_at.getTime());
|
|
49
|
+
const limit = opts?.limit ?? Infinity;
|
|
50
|
+
for (const meta of all.slice(0, limit)) {
|
|
51
|
+
yield meta;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
async get_latest(store_id) {
|
|
55
|
+
let latest = null;
|
|
56
|
+
for (const backend of read) {
|
|
57
|
+
const result = await backend.metadata.get_latest(store_id);
|
|
58
|
+
if (!result.ok) {
|
|
59
|
+
if (result.error.kind !== 'not_found')
|
|
60
|
+
return result;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (!latest || result.value.created_at > latest.created_at) {
|
|
64
|
+
latest = result.value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (!latest) {
|
|
68
|
+
return err({ kind: 'not_found', store_id, version: 'latest' });
|
|
69
|
+
}
|
|
70
|
+
return ok(latest);
|
|
71
|
+
},
|
|
72
|
+
async *get_children(parent_store_id, parent_version) {
|
|
73
|
+
const seen = new Set();
|
|
74
|
+
for (const backend of read) {
|
|
75
|
+
for await (const meta of backend.metadata.get_children(parent_store_id, parent_version)) {
|
|
76
|
+
const key = `${meta.store_id}:${meta.version}`;
|
|
77
|
+
if (seen.has(key))
|
|
78
|
+
continue;
|
|
79
|
+
seen.add(key);
|
|
80
|
+
yield meta;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
async find_by_hash(store_id, content_hash) {
|
|
85
|
+
for (const backend of read) {
|
|
86
|
+
const result = await backend.metadata.find_by_hash(store_id, content_hash);
|
|
87
|
+
if (result)
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
const data = {
|
|
94
|
+
async get(data_key) {
|
|
95
|
+
for (const backend of read) {
|
|
96
|
+
const result = await backend.data.get(data_key);
|
|
97
|
+
if (result.ok)
|
|
98
|
+
return result;
|
|
99
|
+
if (result.error.kind !== 'not_found')
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
return err({ kind: 'not_found', store_id: data_key, version: '' });
|
|
103
|
+
},
|
|
104
|
+
async put(data_key, data) {
|
|
105
|
+
if (write.length === 0)
|
|
106
|
+
return ok(undefined);
|
|
107
|
+
if (write.length === 1) {
|
|
108
|
+
return write[0].data.put(data_key, data);
|
|
109
|
+
}
|
|
110
|
+
const bytes = await to_bytes(data);
|
|
111
|
+
for (const backend of write) {
|
|
112
|
+
const result = await backend.data.put(data_key, bytes);
|
|
113
|
+
if (!result.ok)
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
return ok(undefined);
|
|
117
|
+
},
|
|
118
|
+
async delete(data_key) {
|
|
119
|
+
for (const backend of write) {
|
|
120
|
+
const result = await backend.data.delete(data_key);
|
|
121
|
+
if (!result.ok && result.error.kind !== 'not_found')
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
return ok(undefined);
|
|
125
|
+
},
|
|
126
|
+
async exists(data_key) {
|
|
127
|
+
for (const backend of read) {
|
|
128
|
+
if (await backend.data.exists(data_key))
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
return false;
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
return { metadata, data };
|
|
135
|
+
}
|
|
136
|
+
async function to_bytes(data) {
|
|
137
|
+
if (data instanceof Uint8Array)
|
|
138
|
+
return data;
|
|
139
|
+
const chunks = [];
|
|
140
|
+
const reader = data.getReader();
|
|
141
|
+
while (true) {
|
|
142
|
+
const { done, value } = await reader.read();
|
|
143
|
+
if (done)
|
|
144
|
+
break;
|
|
145
|
+
chunks.push(value);
|
|
146
|
+
}
|
|
147
|
+
const total = chunks.reduce((sum, c) => sum + c.length, 0);
|
|
148
|
+
const result = new Uint8Array(total);
|
|
149
|
+
let offset = 0;
|
|
150
|
+
for (const chunk of chunks) {
|
|
151
|
+
result.set(chunk, offset);
|
|
152
|
+
offset += chunk.length;
|
|
153
|
+
}
|
|
154
|
+
return result;
|
|
155
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { create_store } from './store';
|
|
|
3
3
|
export { create_memory_backend, type MemoryBackendOptions } from './backend/memory';
|
|
4
4
|
export { create_file_backend, type FileBackendConfig } from './backend/file';
|
|
5
5
|
export { create_cloudflare_backend, type CloudflareBackendConfig } from './backend/cloudflare';
|
|
6
|
+
export { create_layered_backend, type LayeredBackendOptions } from './backend/layered';
|
|
6
7
|
export { json_codec, text_codec, binary_codec } from './codec';
|
|
7
8
|
export { corpus_snapshots, type CorpusSnapshotRow, type CorpusSnapshotInsert } from './schema';
|
|
8
9
|
export { compute_hash } from './hash';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEtC,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;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEtC,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;AAEtF,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE9D,OAAO,EAAE,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAE9F,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAE5C,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,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,KAAK,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export { create_store } from './store';
|
|
|
3
3
|
export { create_memory_backend } from './backend/memory';
|
|
4
4
|
export { create_file_backend } from './backend/file';
|
|
5
5
|
export { create_cloudflare_backend } from './backend/cloudflare';
|
|
6
|
+
export { create_layered_backend } from './backend/layered';
|
|
6
7
|
export { json_codec, text_codec, binary_codec } from './codec';
|
|
7
8
|
export { corpus_snapshots } from './schema';
|
|
8
9
|
export { compute_hash } from './hash';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@f0rbit/corpus",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "A functional snapshotting library for TypeScript with versioned data storage, lineage tracking, and multiple backend support",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"main": "dist/index.js",
|