@storacha/clawracha 0.3.14 → 0.4.0
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/LICENSE.md +204 -0
- package/README.md +117 -110
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +3 -3
- package/dist/handlers/apply.d.ts +3 -11
- package/dist/handlers/apply.d.ts.map +1 -1
- package/dist/handlers/apply.js +5 -32
- package/dist/handlers/process.d.ts +3 -6
- package/dist/handlers/process.d.ts.map +1 -1
- package/dist/handlers/process.js +30 -60
- package/dist/handlers/remote.d.ts +1 -3
- package/dist/handlers/remote.d.ts.map +1 -1
- package/dist/handlers/remote.js +4 -34
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/mdsync/index.d.ts +2 -2
- package/dist/mdsync/index.d.ts.map +1 -1
- package/dist/mdsync/index.js +14 -17
- package/dist/plugin.js +2 -2
- package/dist/sync.d.ts +20 -10
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +76 -105
- package/dist/types/index.d.ts +11 -5
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/config.d.ts +26 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +89 -0
- package/dist/utils/contentfetcher.d.ts +6 -0
- package/dist/utils/contentfetcher.d.ts.map +1 -0
- package/dist/utils/contentfetcher.js +58 -0
- package/dist/utils/crypto.d.ts +0 -6
- package/dist/utils/crypto.d.ts.map +1 -1
- package/dist/utils/crypto.js +0 -45
- package/dist/utils/differ.d.ts.map +1 -1
- package/dist/utils/differ.js +6 -0
- package/dist/utils/encoder.d.ts +2 -15
- package/dist/utils/encoder.d.ts.map +1 -1
- package/dist/utils/encoder.js +8 -49
- package/dist/utils/tempcar.d.ts +1 -1
- package/dist/utils/tempcar.d.ts.map +1 -1
- package/dist/utils/tempcar.js +4 -2
- package/package.json +3 -2
package/dist/handlers/process.js
CHANGED
|
@@ -8,8 +8,6 @@
|
|
|
8
8
|
* before upload via encryptToBlockStream.
|
|
9
9
|
*/
|
|
10
10
|
import { Revision } from "@storacha/ucn/pail";
|
|
11
|
-
import { encodeFiles } from "../utils/encoder.js";
|
|
12
|
-
import { encryptToBlockStream } from "../utils/crypto.js";
|
|
13
11
|
import * as mdsync from "../mdsync/index.js";
|
|
14
12
|
import * as fs from "node:fs/promises";
|
|
15
13
|
import * as path from "node:path";
|
|
@@ -29,7 +27,7 @@ async function drainBlockStream(stream, sink) {
|
|
|
29
27
|
throw new Error("Empty block stream");
|
|
30
28
|
return root;
|
|
31
29
|
}
|
|
32
|
-
export async function processChanges(changes, workspace, current, blocks, sink,
|
|
30
|
+
export async function processChanges(changes, workspace, current, blocks, sink, encoder, contentFetcher) {
|
|
33
31
|
const pendingOps = [];
|
|
34
32
|
const mdChanges = changes.filter((c) => isMarkdown(c.path));
|
|
35
33
|
const regularChanges = changes.filter((c) => !isMarkdown(c.path));
|
|
@@ -37,79 +35,51 @@ export async function processChanges(changes, workspace, current, blocks, sink,
|
|
|
37
35
|
const toEncode = regularChanges
|
|
38
36
|
.filter((c) => c.type !== "unlink")
|
|
39
37
|
.map((c) => c.path);
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
catch (err) {
|
|
51
|
-
if (err.code === "ENOENT") {
|
|
52
|
-
console.warn(`File not found during encoding: ${relPath}`);
|
|
53
|
-
continue;
|
|
38
|
+
for (const relPath of toEncode) {
|
|
39
|
+
try {
|
|
40
|
+
const fileBytes = await fs.readFile(path.join(workspace, relPath));
|
|
41
|
+
const existing = current
|
|
42
|
+
? await Revision.get(blocks, current, relPath)
|
|
43
|
+
: null;
|
|
44
|
+
if (existing) {
|
|
45
|
+
const existingBytes = await contentFetcher(existing);
|
|
46
|
+
if (Buffer.compare(existingBytes, fileBytes) === 0) {
|
|
47
|
+
continue; // No change detected, skip encoding/uploading.
|
|
54
48
|
}
|
|
55
|
-
throw err;
|
|
56
49
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
else {
|
|
60
|
-
// Public space: UnixFS encode
|
|
61
|
-
const encoded = await encodeFiles(workspace, toEncode);
|
|
62
|
-
for (const file of encoded) {
|
|
63
|
-
const rootCID = await drainBlockStream(file.blocks, sink);
|
|
64
|
-
files.push({ path: file.path, rootCID });
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
for (const file of files) {
|
|
68
|
-
const existing = current
|
|
69
|
-
? await Revision.get(blocks, current, file.path)
|
|
70
|
-
: null;
|
|
71
|
-
if (!existing || !existing.equals(file.rootCID)) {
|
|
50
|
+
const encStream = await encoder(new Blob([fileBytes]));
|
|
51
|
+
const rootCID = await drainBlockStream(encStream, sink);
|
|
72
52
|
pendingOps.push({
|
|
73
53
|
type: "put",
|
|
74
|
-
key:
|
|
75
|
-
value:
|
|
54
|
+
key: relPath,
|
|
55
|
+
value: rootCID,
|
|
76
56
|
});
|
|
77
57
|
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
if (err.code === "ENOENT") {
|
|
60
|
+
console.warn(`File not found during encoding: ${relPath}`);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
78
65
|
}
|
|
79
66
|
// --- Markdown files (CRDT merge via mdsync) ---
|
|
80
67
|
const mdPuts = mdChanges.filter((c) => c.type !== "unlink");
|
|
81
68
|
for (const change of mdPuts) {
|
|
82
69
|
const content = await fs.readFile(path.join(workspace, change.path), "utf-8");
|
|
83
70
|
const block = current
|
|
84
|
-
? await mdsync.put(blocks, current, change.path, content)
|
|
71
|
+
? await mdsync.put(blocks, contentFetcher, current, change.path, content)
|
|
85
72
|
: await mdsync.v0Put(content);
|
|
86
73
|
if (!block) {
|
|
87
74
|
continue; // No change detected, skip writing a new entry.
|
|
88
75
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
pendingOps.push({
|
|
97
|
-
type: "put",
|
|
98
|
-
key: change.path,
|
|
99
|
-
value: rootCID,
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
// Public space: store block directly
|
|
104
|
-
await sink(block);
|
|
105
|
-
if (store)
|
|
106
|
-
await store(block);
|
|
107
|
-
pendingOps.push({
|
|
108
|
-
type: "put",
|
|
109
|
-
key: change.path,
|
|
110
|
-
value: block.cid,
|
|
111
|
-
});
|
|
112
|
-
}
|
|
76
|
+
const encStream = await encoder(new Blob([block.bytes]));
|
|
77
|
+
const rootCID = await drainBlockStream(encStream, sink);
|
|
78
|
+
pendingOps.push({
|
|
79
|
+
type: "put",
|
|
80
|
+
key: change.path,
|
|
81
|
+
value: rootCID,
|
|
82
|
+
});
|
|
113
83
|
}
|
|
114
84
|
// --- Deletes (both regular and markdown) ---
|
|
115
85
|
const toDelete = changes
|
|
@@ -8,10 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { CID } from "multiformats/cid";
|
|
10
10
|
import type { BlockFetcher, ValueView } from "@storacha/ucn/pail/api";
|
|
11
|
-
export declare function applyRemoteChanges(changedPaths: string[], entries: Map<string, CID>, workspace: string, options?: {
|
|
12
|
-
gateway?: string;
|
|
11
|
+
export declare function applyRemoteChanges(changedPaths: string[], entries: Map<string, CID>, workspace: string, contentFetcher: (cid: CID) => Promise<Uint8Array>, options?: {
|
|
13
12
|
blocks?: BlockFetcher;
|
|
14
13
|
current?: ValueView;
|
|
15
|
-
decrypt?: (cid: CID) => Promise<Uint8Array>;
|
|
16
14
|
}): Promise<void>;
|
|
17
15
|
//# sourceMappingURL=remote.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../src/handlers/remote.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../src/handlers/remote.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAKtE,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,EAAE,EACtB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,UAAU,CAAC,EACjD,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB,GACA,OAAO,CAAC,IAAI,CAAC,CAmCf"}
|
package/dist/handlers/remote.js
CHANGED
|
@@ -9,29 +9,8 @@
|
|
|
9
9
|
import * as fs from "node:fs/promises";
|
|
10
10
|
import * as path from "node:path";
|
|
11
11
|
import * as mdsync from "../mdsync/index.js";
|
|
12
|
-
const DEFAULT_GATEWAY = "https://storacha.link";
|
|
13
12
|
const isMarkdown = (filePath) => filePath.endsWith(".md");
|
|
14
|
-
|
|
15
|
-
async function drainStream(stream) {
|
|
16
|
-
const reader = stream.getReader();
|
|
17
|
-
const chunks = [];
|
|
18
|
-
while (true) {
|
|
19
|
-
const { done, value } = await reader.read();
|
|
20
|
-
if (done)
|
|
21
|
-
break;
|
|
22
|
-
chunks.push(value);
|
|
23
|
-
}
|
|
24
|
-
const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);
|
|
25
|
-
const result = new Uint8Array(totalLength);
|
|
26
|
-
let offset = 0;
|
|
27
|
-
for (const chunk of chunks) {
|
|
28
|
-
result.set(chunk, offset);
|
|
29
|
-
offset += chunk.length;
|
|
30
|
-
}
|
|
31
|
-
return result;
|
|
32
|
-
}
|
|
33
|
-
export async function applyRemoteChanges(changedPaths, entries, workspace, options) {
|
|
34
|
-
const gateway = options?.gateway ?? DEFAULT_GATEWAY;
|
|
13
|
+
export async function applyRemoteChanges(changedPaths, entries, workspace, contentFetcher, options) {
|
|
35
14
|
for (const relativePath of changedPaths) {
|
|
36
15
|
const cid = entries.get(relativePath);
|
|
37
16
|
const fullPath = path.join(workspace, relativePath);
|
|
@@ -50,25 +29,16 @@ export async function applyRemoteChanges(changedPaths, entries, workspace, optio
|
|
|
50
29
|
options?.current) {
|
|
51
30
|
// Markdown: resolve via mdsync CRDT merge.
|
|
52
31
|
// For single-device, unencrypted blocks are stored locally.
|
|
53
|
-
const content = await mdsync.get(options.blocks, options.current, relativePath
|
|
32
|
+
const content = await mdsync.get(options.blocks, contentFetcher, options.current, relativePath);
|
|
54
33
|
if (content != null) {
|
|
55
34
|
await fs.mkdir(path.dirname(fullPath), { recursive: true });
|
|
56
35
|
await fs.writeFile(fullPath, content);
|
|
57
36
|
}
|
|
58
37
|
}
|
|
59
|
-
else if (options?.decrypt) {
|
|
60
|
-
const bytes = await options.decrypt(cid);
|
|
61
|
-
await fs.mkdir(path.dirname(fullPath), { recursive: true });
|
|
62
|
-
await fs.writeFile(fullPath, bytes);
|
|
63
|
-
}
|
|
64
38
|
else {
|
|
65
|
-
|
|
66
|
-
const res = await fetch(`${gateway}/ipfs/${cid}`);
|
|
67
|
-
if (!res.ok) {
|
|
68
|
-
throw new Error(`Gateway fetch failed for ${cid}: ${res.status}`);
|
|
69
|
-
}
|
|
39
|
+
const bytes = await contentFetcher(cid);
|
|
70
40
|
await fs.mkdir(path.dirname(fullPath), { recursive: true });
|
|
71
|
-
await fs.writeFile(fullPath,
|
|
41
|
+
await fs.writeFile(fullPath, bytes);
|
|
72
42
|
}
|
|
73
43
|
}
|
|
74
44
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export * from "./types/index.js";
|
|
5
5
|
export * from "./blockstore/index.js";
|
|
6
|
-
export { encodeWorkspaceFile, encodeFiles } from "./utils/encoder.js";
|
|
7
6
|
export { diffEntries, diffRemoteChanges } from "./utils/differ.js";
|
|
8
7
|
export { SyncEngine } from "./sync.js";
|
|
9
8
|
export { FileWatcher } from "./watcher.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export * from "./types/index.js";
|
|
5
5
|
export * from "./blockstore/index.js";
|
|
6
|
-
export { encodeWorkspaceFile, encodeFiles } from "./utils/encoder.js";
|
|
7
6
|
export { diffEntries, diffRemoteChanges } from "./utils/differ.js";
|
|
8
7
|
export { SyncEngine } from "./sync.js";
|
|
9
8
|
export { FileWatcher } from "./watcher.js";
|
package/dist/mdsync/index.d.ts
CHANGED
|
@@ -78,11 +78,11 @@ export declare const v0Put: (newMarkdown: string) => Promise<Block>;
|
|
|
78
78
|
* Returns a single block to store, or null if no changes detected.
|
|
79
79
|
* Caller is responsible for creating the Pail revision via Revision.put.
|
|
80
80
|
*/
|
|
81
|
-
export declare const put: (blocks: BlockFetcher, current: ValueView, key: string, newMarkdown: string) => Promise<Block | null>;
|
|
81
|
+
export declare const put: (blocks: BlockFetcher, contentFetcher: (cid: CID) => Promise<Uint8Array>, current: ValueView, key: string, newMarkdown: string) => Promise<Block | null>;
|
|
82
82
|
/**
|
|
83
83
|
* Get the current markdown string for a key, resolving concurrent heads.
|
|
84
84
|
* Returns undefined if the key doesn't exist.
|
|
85
85
|
*/
|
|
86
|
-
export declare const get: (blocks: BlockFetcher,
|
|
86
|
+
export declare const get: (blocks: BlockFetcher, contentFetcher: (cid: CID) => Promise<Uint8Array>, current: ValueView, key: string) => Promise<string | undefined>;
|
|
87
87
|
export {};
|
|
88
88
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mdsync/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EACL,YAAY,EACZ,SAAS,EAET,SAAS,EACV,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,EAEL,GAAG,EAGH,WAAW,EACX,YAAY,EAUb,MAAM,oBAAoB,CAAC;AAQ5B;;;;;;;;GAQG;AACH,cAAM,aAAa;IACjB,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;gBAEd,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IAIrC,QAAQ;CAGT;AAyBD,wDAAwD;AACxD,KAAK,QAAQ,GAAG,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AAElD,UAAU,6BAA6B;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,IAAI,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;IACjC;;;;OAIG;IACH,MAAM,EAAE,QAAQ,CAAC;CAClB;AAED,UAAU,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mdsync/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EACL,YAAY,EACZ,SAAS,EAET,SAAS,EACV,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,EAEL,GAAG,EAGH,WAAW,EACX,YAAY,EAUb,MAAM,oBAAoB,CAAC;AAQ5B;;;;;;;;GAQG;AACH,cAAM,aAAa;IACjB,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;gBAEd,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IAIrC,QAAQ;CAGT;AAyBD,wDAAwD;AACxD,KAAK,QAAQ,GAAG,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AAElD,UAAU,6BAA6B;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,IAAI,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;IACjC;;;;OAIG;IACH,MAAM,EAAE,QAAQ,CAAC;CAClB;AAED,UAAU,gCAAiC,SAAQ,6BAA6B;IAC9E,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,UAAU,+BAAgC,SAAQ,6BAA6B;IAC7E,IAAI,EAAE,QAAQ,CAAC;IACf,0EAA0E;IAC1E,SAAS,EAAE,YAAY,CAAC,aAAa,CAAC,CAAC;CACxC;AAED,KAAK,yBAAyB,GAC1B,gCAAgC,GAChC,+BAA+B,CAAC;AA8BpC;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAC9B,OAAO,yBAAyB,KAC/B,OAAO,CAAC,KAAK,CAcf,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAAU,OAAO;IAC/C,KAAK,EAAE,UAAU,CAAC;CACnB,KAAG,OAAO,CAAC,yBAAyB,CA+BpC,CAAC;AA0BF;;;;GAIG;AACH,eAAO,MAAM,KAAK,GAAU,aAAa,MAAM,KAAG,OAAO,CAAC,KAAK,CAG9D,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,GAAG,GACd,QAAQ,YAAY,EACpB,gBAAgB,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,UAAU,CAAC,EACjD,SAAS,SAAS,EAClB,KAAK,MAAM,EACX,aAAa,MAAM,KAClB,OAAO,CAAC,KAAK,GAAG,IAAI,CAiCtB,CAAC;AA8IF;;;GAGG;AACH,eAAO,MAAM,GAAG,GACd,QAAQ,YAAY,EACpB,gBAAgB,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,UAAU,CAAC,EACjD,SAAS,SAAS,EAClB,KAAK,MAAM,KACV,OAAO,CAAC,MAAM,GAAG,SAAS,CAM5B,CAAC"}
|
package/dist/mdsync/index.js
CHANGED
|
@@ -152,8 +152,8 @@ export const v0Put = async (newMarkdown) => {
|
|
|
152
152
|
* Returns a single block to store, or null if no changes detected.
|
|
153
153
|
* Caller is responsible for creating the Pail revision via Revision.put.
|
|
154
154
|
*/
|
|
155
|
-
export const put = async (blocks, current, key, newMarkdown) => {
|
|
156
|
-
const mdEntry = await resolveValue(blocks, current, key);
|
|
155
|
+
export const put = async (blocks, contentFetcher, current, key, newMarkdown) => {
|
|
156
|
+
const mdEntry = await resolveValue(blocks, contentFetcher, current, key);
|
|
157
157
|
if (!mdEntry) {
|
|
158
158
|
// Key doesn't exist yet — bootstrap with firstPut.
|
|
159
159
|
const entry = firstPut(newMarkdown, current.revision.map((r) => r.event.cid));
|
|
@@ -188,7 +188,7 @@ export const put = async (blocks, current, key, newMarkdown) => {
|
|
|
188
188
|
* If there are multiple heads, finds their common ancestor in the Pail's
|
|
189
189
|
* merkle clock, then replays all events from ancestor → heads in causal order.
|
|
190
190
|
*/
|
|
191
|
-
const resolveValue = async (blocks, current, key
|
|
191
|
+
const resolveValue = async (blocks, contentFetcher, current, key) => {
|
|
192
192
|
const mdEntryBlockCid = await Pail.get(blocks, current.root, key);
|
|
193
193
|
if (!mdEntryBlockCid) {
|
|
194
194
|
return undefined;
|
|
@@ -196,18 +196,11 @@ const resolveValue = async (blocks, current, key, decrypt) => {
|
|
|
196
196
|
// Cache event blocks in memory so EventFetcher can find them.
|
|
197
197
|
blocks = withCache(blocks, new MemoryBlockstore(current.revision.map((r) => r.event)));
|
|
198
198
|
const events = new EventFetcher(blocks);
|
|
199
|
-
// Fetch entry bytes: decrypt callback for private spaces, or raw block fetch.
|
|
200
|
-
const getEntryBytes = async (cid) => {
|
|
201
|
-
if (decrypt)
|
|
202
|
-
return decrypt(cid);
|
|
203
|
-
const block = await blocks.get(cid);
|
|
204
|
-
if (!block)
|
|
205
|
-
throw new Error(`Could not find block for CID ${cid}`);
|
|
206
|
-
return block.bytes;
|
|
207
|
-
};
|
|
208
199
|
// Fast path: single head, no merge needed.
|
|
209
200
|
if (current.revision.length === 1) {
|
|
210
|
-
return decodeMarkdownEntry({
|
|
201
|
+
return decodeMarkdownEntry({
|
|
202
|
+
bytes: await contentFetcher(mdEntryBlockCid),
|
|
203
|
+
});
|
|
211
204
|
}
|
|
212
205
|
// Multi-head: find common ancestor and replay events in causal order.
|
|
213
206
|
const ancestor = await CRDT.findCommonAncestor(events, current.revision.map((r) => r.event.cid));
|
|
@@ -220,7 +213,9 @@ const resolveValue = async (blocks, current, key, decrypt) => {
|
|
|
220
213
|
const rootMDEntryCid = await Pail.get(blocks, root, key);
|
|
221
214
|
let mdEntry;
|
|
222
215
|
if (rootMDEntryCid) {
|
|
223
|
-
mdEntry = await decodeMarkdownEntry({
|
|
216
|
+
mdEntry = await decodeMarkdownEntry({
|
|
217
|
+
bytes: await contentFetcher(rootMDEntryCid),
|
|
218
|
+
});
|
|
224
219
|
}
|
|
225
220
|
// Get all events from ancestor → heads, sorted in deterministic causal order.
|
|
226
221
|
const sorted = await CRDT.findSortedEvents(events, current.revision.map((r) => r.event.cid), ancestor);
|
|
@@ -254,7 +249,9 @@ const resolveValue = async (blocks, current, key, decrypt) => {
|
|
|
254
249
|
if (!mdEntryCid) {
|
|
255
250
|
throw new Error(`Could not find markdown entry for CID ${data.root} and key ${key}`);
|
|
256
251
|
}
|
|
257
|
-
const newMDEntry = await decodeMarkdownEntry({
|
|
252
|
+
const newMDEntry = await decodeMarkdownEntry({
|
|
253
|
+
bytes: await contentFetcher(mdEntryCid),
|
|
254
|
+
});
|
|
258
255
|
if (newMDEntry.type === "initial") {
|
|
259
256
|
if (mdEntry) {
|
|
260
257
|
// Concurrent initial — merge event histories and RGA trees.
|
|
@@ -295,8 +292,8 @@ const resolveValue = async (blocks, current, key, decrypt) => {
|
|
|
295
292
|
* Get the current markdown string for a key, resolving concurrent heads.
|
|
296
293
|
* Returns undefined if the key doesn't exist.
|
|
297
294
|
*/
|
|
298
|
-
export const get = async (blocks, current, key
|
|
299
|
-
const mdEntry = await resolveValue(blocks, current, key
|
|
295
|
+
export const get = async (blocks, contentFetcher, current, key) => {
|
|
296
|
+
const mdEntry = await resolveValue(blocks, contentFetcher, current, key);
|
|
300
297
|
if (!mdEntry) {
|
|
301
298
|
return undefined;
|
|
302
299
|
}
|
package/dist/plugin.js
CHANGED
|
@@ -367,8 +367,8 @@ export default function plugin(api) {
|
|
|
367
367
|
engine = activeSync.engine;
|
|
368
368
|
}
|
|
369
369
|
else {
|
|
370
|
-
engine =
|
|
371
|
-
await engine.
|
|
370
|
+
engine = await SyncEngine.fromConfig(workspace, deviceConfig);
|
|
371
|
+
await engine.start();
|
|
372
372
|
}
|
|
373
373
|
const state = await engine.inspect();
|
|
374
374
|
console.log(`🔥 Storacha Inspect [${agentId}]`);
|
package/dist/sync.d.ts
CHANGED
|
@@ -8,8 +8,18 @@
|
|
|
8
8
|
* 5. Upload all blocks as CAR
|
|
9
9
|
* 6. Apply remote changes to local filesystem
|
|
10
10
|
*/
|
|
11
|
-
import type {
|
|
11
|
+
import type { NameView, ClockConnection } from "@storacha/ucn/pail/api";
|
|
12
|
+
import type { SyncState, FileChange, DeviceConfig, ContentFetcher, Encoder, StorageClient } from "./types/index.js";
|
|
13
|
+
import { type WorkspaceBlockstore } from "./blockstore/index.js";
|
|
12
14
|
import { type PailEntries } from "./utils/differ.js";
|
|
15
|
+
export interface SyncDeps {
|
|
16
|
+
blocks: WorkspaceBlockstore;
|
|
17
|
+
name: NameView;
|
|
18
|
+
client: StorageClient;
|
|
19
|
+
encoder: Encoder;
|
|
20
|
+
contentFetcher: ContentFetcher;
|
|
21
|
+
remotes?: ClockConnection[];
|
|
22
|
+
}
|
|
13
23
|
export declare class SyncEngine {
|
|
14
24
|
private workspace;
|
|
15
25
|
private blocks;
|
|
@@ -19,23 +29,22 @@ export declare class SyncEngine {
|
|
|
19
29
|
private carFile;
|
|
20
30
|
private lastSync;
|
|
21
31
|
private syncLock;
|
|
22
|
-
private
|
|
23
|
-
private
|
|
24
|
-
private
|
|
25
|
-
|
|
32
|
+
private client;
|
|
33
|
+
private name;
|
|
34
|
+
private encoder;
|
|
35
|
+
private contentFetcher;
|
|
36
|
+
private remotes?;
|
|
37
|
+
constructor(workspace: string, deps: SyncDeps);
|
|
38
|
+
start(): Promise<void>;
|
|
26
39
|
/**
|
|
27
40
|
* Initialize sync engine with device config.
|
|
28
41
|
* Creates the Storacha client and resolves the UCN name.
|
|
29
42
|
*/
|
|
30
|
-
|
|
43
|
+
static fromConfig(workspace: string, config: DeviceConfig): Promise<SyncEngine>;
|
|
31
44
|
/**
|
|
32
45
|
* Require running state or throw.
|
|
33
46
|
*/
|
|
34
47
|
private requireRunning;
|
|
35
|
-
/**
|
|
36
|
-
* Require state is initialized or throw.
|
|
37
|
-
*/
|
|
38
|
-
private requireInitialized;
|
|
39
48
|
/**
|
|
40
49
|
* Process a batch of file changes.
|
|
41
50
|
* Can be called even when not running (accumulates pending ops).
|
|
@@ -83,5 +92,6 @@ export declare class SyncEngine {
|
|
|
83
92
|
status(): Promise<SyncState>;
|
|
84
93
|
exportNameArchive(): Promise<string>;
|
|
85
94
|
private storeBlocks;
|
|
95
|
+
private storeForUpload;
|
|
86
96
|
}
|
|
87
97
|
//# sourceMappingURL=sync.d.ts.map
|
package/dist/sync.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAa,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEnF,OAAO,KAAK,EACV,SAAS,EACT,UAAU,EAEV,YAAY,EACZ,cAAc,EACd,OAAO,EACP,aAAa,EACd,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAiBxE,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;CAC7B;AACD,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,IAAI,CAAW;IACvB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,OAAO,CAAC,CAAoB;gBACxB,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ;IAUvC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB5B;;;OAGG;WACU,UAAU,CACrB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,UAAU,CAAC;IAoBtB;;OAEG;IACH,OAAO,CAAC,cAAc;IAOtB;;;OAGG;IACG,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB1D;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAMb,UAAU;IAwExB;;OAEG;YACW,iBAAiB;IAe/B;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;IAc5C;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;YAMrB,gBAAgB;IAgC9B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC;QACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,SAAS,EAAE;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QAC/B,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,UAAU,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QAC5D,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;IAkBI,MAAM,IAAI,OAAO,CAAC,SAAS,CAAC;IAW5B,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;YAK5B,WAAW;YAMX,cAAc;CAI7B"}
|