@f0rbit/corpus 0.1.1 → 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/file.js +2 -2
- 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/cloudflare.d.ts +15 -0
- package/dist/cloudflare.d.ts.map +1 -0
- package/dist/cloudflare.js +13 -0
- package/dist/codec.d.ts +5 -2
- package/dist/codec.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/package.json +5 -1
package/dist/backend/file.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ok, err } from '../types';
|
|
2
|
-
import { mkdir,
|
|
2
|
+
import { mkdir, readdir } from 'node:fs/promises';
|
|
3
3
|
import { join, dirname } from 'node:path';
|
|
4
4
|
export function create_file_backend(config) {
|
|
5
5
|
const { base_path, on_event } = config;
|
|
@@ -166,7 +166,7 @@ export function create_file_backend(config) {
|
|
|
166
166
|
try {
|
|
167
167
|
const file = Bun.file(path);
|
|
168
168
|
if (await file.exists()) {
|
|
169
|
-
await
|
|
169
|
+
await file.delete();
|
|
170
170
|
}
|
|
171
171
|
return ok(undefined);
|
|
172
172
|
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare Workers compatible exports
|
|
3
|
+
* This entry point excludes the file backend which uses Node.js APIs
|
|
4
|
+
*/
|
|
5
|
+
export { create_corpus } from './corpus';
|
|
6
|
+
export { create_store } from './store';
|
|
7
|
+
export { create_memory_backend, type MemoryBackendOptions } from './backend/memory';
|
|
8
|
+
export { create_cloudflare_backend, type CloudflareBackendConfig } from './backend/cloudflare';
|
|
9
|
+
export { json_codec, text_codec, binary_codec } from './codec';
|
|
10
|
+
export { corpus_snapshots, type CorpusSnapshotRow, type CorpusSnapshotInsert } from './schema';
|
|
11
|
+
export { compute_hash } from './hash';
|
|
12
|
+
export { generate_version } from './version';
|
|
13
|
+
export type { ContentType, ParentRef, SnapshotMeta, Snapshot, DataHandle, MetadataClient, DataClient, ListOpts, Backend, Codec, Store, StoreDefinition, PutOpts, CorpusBuilder, Corpus, CorpusError, Result, CorpusEvent, EventHandler, } from './types';
|
|
14
|
+
export { ok, err, define_store } from './types';
|
|
15
|
+
//# sourceMappingURL=cloudflare.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../cloudflare.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,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,yBAAyB,EAAE,KAAK,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAE9F,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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare Workers compatible exports
|
|
3
|
+
* This entry point excludes the file backend which uses Node.js APIs
|
|
4
|
+
*/
|
|
5
|
+
export { create_corpus } from './corpus';
|
|
6
|
+
export { create_store } from './store';
|
|
7
|
+
export { create_memory_backend } from './backend/memory';
|
|
8
|
+
export { create_cloudflare_backend } from './backend/cloudflare';
|
|
9
|
+
export { json_codec, text_codec, binary_codec } from './codec';
|
|
10
|
+
export { corpus_snapshots } from './schema';
|
|
11
|
+
export { compute_hash } from './hash';
|
|
12
|
+
export { generate_version } from './version';
|
|
13
|
+
export { ok, err, define_store } from './types';
|
package/dist/codec.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import type { ZodSchema } from "zod";
|
|
2
1
|
import type { Codec } from "./types";
|
|
3
|
-
|
|
2
|
+
type ZodLike<T> = {
|
|
3
|
+
parse: (data: unknown) => T;
|
|
4
|
+
};
|
|
5
|
+
export declare function json_codec<T>(schema: ZodLike<T>): Codec<T>;
|
|
4
6
|
export declare function text_codec(): Codec<string>;
|
|
5
7
|
export declare function binary_codec(): Codec<Uint8Array>;
|
|
8
|
+
export {};
|
|
6
9
|
//# sourceMappingURL=codec.d.ts.map
|
package/dist/codec.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../codec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../codec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGrC,KAAK,OAAO,CAAC,CAAC,IAAI;IAAE,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,CAAC,CAAA;CAAE,CAAC;AAElD,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAM1D;AAED,wBAAgB,UAAU,IAAI,KAAK,CAAC,MAAM,CAAC,CAM1C;AAED,wBAAgB,YAAY,IAAI,KAAK,CAAC,UAAU,CAAC,CAMhD"}
|
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",
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
"import": "./dist/index.js",
|
|
12
12
|
"types": "./dist/index.d.ts"
|
|
13
13
|
},
|
|
14
|
+
"./cloudflare": {
|
|
15
|
+
"import": "./dist/cloudflare.js",
|
|
16
|
+
"types": "./dist/cloudflare.d.ts"
|
|
17
|
+
},
|
|
14
18
|
"./types": {
|
|
15
19
|
"import": "./dist/types.js",
|
|
16
20
|
"types": "./dist/types.d.ts"
|