@dxos/plugin-wnfs 0.9.1-staging.ee54ba693a → 0.11.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/PLUGIN.mdl +92 -46
- package/dist/lib/WnfsPlugin.mjs +28 -0
- package/dist/lib/WnfsPlugin.mjs.map +1 -0
- package/dist/lib/WnfsPlugin.node.mjs +8 -0
- package/dist/lib/WnfsPlugin.node.mjs.map +1 -0
- package/dist/lib/WnfsPlugin.workerd.mjs +8 -0
- package/dist/lib/WnfsPlugin.workerd.mjs.map +1 -0
- package/dist/lib/capabilities.mjs +8 -0
- package/dist/lib/capabilities.mjs.map +1 -0
- package/dist/lib/chunk-blob-backend.mjs +118 -0
- package/dist/lib/chunk-blob-backend.mjs.map +1 -0
- package/dist/lib/chunk-dependencies.mjs +146 -0
- package/dist/lib/chunk-dependencies.mjs.map +1 -0
- package/dist/lib/chunk-helpers.mjs +198 -0
- package/dist/lib/chunk-helpers.mjs.map +1 -0
- package/dist/lib/chunk-meta.mjs +38 -0
- package/dist/lib/chunk-meta.mjs.map +1 -0
- package/dist/lib/chunk-types.mjs +46 -0
- package/dist/lib/chunk-types.mjs.map +1 -0
- package/dist/lib/helpers.mjs +2 -0
- package/dist/lib/index.mjs +4 -0
- package/dist/lib/meta.mjs +2 -0
- package/dist/lib/plugin.mjs +8 -0
- package/dist/lib/plugin.mjs.map +1 -0
- package/dist/lib/translations.mjs +7 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/lib/types.mjs +2 -0
- package/dist/types/src/WnfsPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/blob-backend.d.ts +22 -0
- package/dist/types/src/capabilities/blob-backend.d.ts.map +1 -0
- package/dist/types/src/capabilities/blob-backend.test.d.ts +2 -0
- package/dist/types/src/capabilities/blob-backend.test.d.ts.map +1 -0
- package/dist/types/src/capabilities/dependencies.d.ts +5 -0
- package/dist/types/src/capabilities/dependencies.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +2 -3
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/helpers/wnfs-url.d.ts +6 -0
- package/dist/types/src/helpers/wnfs-url.d.ts.map +1 -1
- package/dist/types/src/types/WnfsCapabilities.d.ts +7 -0
- package/dist/types/src/types/WnfsCapabilities.d.ts.map +1 -1
- package/dist/types/src/types/WnfsEvents.d.ts +11 -0
- package/dist/types/src/types/WnfsEvents.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +1 -0
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dx.config.ts +4 -4
- package/package.json +34 -32
- package/src/WnfsPlugin.tsx +9 -24
- package/src/capabilities/blob-backend.test.ts +108 -0
- package/src/capabilities/blob-backend.ts +104 -0
- package/src/capabilities/{blockstore.ts → dependencies.ts} +6 -1
- package/src/capabilities/index.ts +2 -4
- package/src/helpers/wnfs-url.ts +22 -4
- package/src/types/WnfsCapabilities.ts +9 -0
- package/src/types/WnfsEvents.ts +19 -0
- package/src/types/index.ts +1 -0
- package/dist/lib/neutral/WnfsPlugin.mjs +0 -51
- package/dist/lib/neutral/WnfsPlugin.mjs.map +0 -7
- package/dist/lib/neutral/WnfsPlugin.node.mjs +0 -12
- package/dist/lib/neutral/WnfsPlugin.node.mjs.map +0 -7
- package/dist/lib/neutral/WnfsPlugin.workerd.mjs +0 -12
- package/dist/lib/neutral/WnfsPlugin.workerd.mjs.map +0 -7
- package/dist/lib/neutral/backend-4HPTHS33.mjs +0 -47
- package/dist/lib/neutral/backend-4HPTHS33.mjs.map +0 -7
- package/dist/lib/neutral/blockstore-U6SPNL2C.mjs +0 -190
- package/dist/lib/neutral/blockstore-U6SPNL2C.mjs.map +0 -7
- package/dist/lib/neutral/capabilities/index.mjs +0 -13
- package/dist/lib/neutral/capabilities/index.mjs.map +0 -7
- package/dist/lib/neutral/chunk-2WLTMUHV.mjs +0 -19
- package/dist/lib/neutral/chunk-2WLTMUHV.mjs.map +0 -7
- package/dist/lib/neutral/chunk-H2YCLSRI.mjs +0 -47
- package/dist/lib/neutral/chunk-H2YCLSRI.mjs.map +0 -7
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-L33MOD23.mjs +0 -219
- package/dist/lib/neutral/chunk-L33MOD23.mjs.map +0 -7
- package/dist/lib/neutral/helpers/index.mjs +0 -26
- package/dist/lib/neutral/helpers/index.mjs.map +0 -7
- package/dist/lib/neutral/index.mjs +0 -36
- package/dist/lib/neutral/index.mjs.map +0 -7
- package/dist/lib/neutral/meta.json +0 -1
- package/dist/lib/neutral/meta.mjs +0 -8
- package/dist/lib/neutral/meta.mjs.map +0 -7
- package/dist/lib/neutral/plugin.mjs +0 -12
- package/dist/lib/neutral/plugin.mjs.map +0 -7
- package/dist/lib/neutral/translations.mjs +0 -17
- package/dist/lib/neutral/translations.mjs.map +0 -7
- package/dist/lib/neutral/types/index.mjs +0 -8
- package/dist/lib/neutral/types/index.mjs.map +0 -7
- package/dist/lib/neutral/url-resolver-BIRH7WHL.mjs +0 -47
- package/dist/lib/neutral/url-resolver-BIRH7WHL.mjs.map +0 -7
- package/dist/types/src/capabilities/backend.d.ts +0 -6
- package/dist/types/src/capabilities/backend.d.ts.map +0 -1
- package/dist/types/src/capabilities/blockstore.d.ts +0 -5
- package/dist/types/src/capabilities/blockstore.d.ts.map +0 -1
- package/dist/types/src/capabilities/url-resolver.d.ts +0 -6
- package/dist/types/src/capabilities/url-resolver.d.ts.map +0 -1
- package/src/capabilities/backend.ts +0 -43
- package/src/capabilities/url-resolver.ts +0 -44
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
import { Annotation, Obj } from "@dxos/echo";
|
|
3
|
+
import { CID } from "multiformats/cid";
|
|
4
|
+
import { sha256 } from "multiformats/hashes/sha2";
|
|
5
|
+
import * as crypto from "@dxos/crypto";
|
|
6
|
+
import * as Option from "effect/Option";
|
|
7
|
+
import { CID as CID$1 } from "multiformats";
|
|
8
|
+
import * as Uint8Arrays from "uint8arrays";
|
|
9
|
+
import { AccessKey, PrivateDirectory, PrivateForest, PrivateNode } from "wnfs";
|
|
10
|
+
import * as Raw from "multiformats/codecs/raw";
|
|
11
|
+
import { log } from "@dxos/log";
|
|
12
|
+
//#region src/annotations.ts
|
|
13
|
+
/** WNFS filesystem state stored on space properties meta. */
|
|
14
|
+
var WnfsStateAnnotation = Annotation.make({
|
|
15
|
+
id: "org.dxos.plugin.wnfs.state",
|
|
16
|
+
schema: Schema.Struct({
|
|
17
|
+
accessKey: Schema.String,
|
|
18
|
+
privateForestCid: Schema.String
|
|
19
|
+
})
|
|
20
|
+
});
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/helpers/common.ts
|
|
23
|
+
var filePath = (fileName, space) => {
|
|
24
|
+
return [
|
|
25
|
+
"spaces",
|
|
26
|
+
space.id,
|
|
27
|
+
"files",
|
|
28
|
+
fileName
|
|
29
|
+
];
|
|
30
|
+
};
|
|
31
|
+
var Rng = class {
|
|
32
|
+
randomBytes(count) {
|
|
33
|
+
return new Uint8Array(crypto.randomBytes(count));
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var store = (blockstore) => {
|
|
37
|
+
const getBlock = async (cid) => {
|
|
38
|
+
const decodedCid = CID.decode(cid);
|
|
39
|
+
return await blockstore.get(decodedCid);
|
|
40
|
+
};
|
|
41
|
+
const hasBlock = async (cid) => {
|
|
42
|
+
const decodedCid = CID.decode(cid);
|
|
43
|
+
return await blockstore.has(decodedCid);
|
|
44
|
+
};
|
|
45
|
+
const putBlockKeyed = async (cid, bytes) => {
|
|
46
|
+
const decodedCid = CID.decode(cid);
|
|
47
|
+
await blockstore.put(decodedCid, bytes);
|
|
48
|
+
};
|
|
49
|
+
const putBlock = async (bytes, codec) => {
|
|
50
|
+
const hash = await sha256.digest(bytes);
|
|
51
|
+
const cid = CID.create(1, codec, hash);
|
|
52
|
+
await blockstore.put(cid, bytes);
|
|
53
|
+
return cid.bytes;
|
|
54
|
+
};
|
|
55
|
+
return {
|
|
56
|
+
getBlock,
|
|
57
|
+
hasBlock,
|
|
58
|
+
putBlockKeyed,
|
|
59
|
+
putBlock
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
var storeName = () => "dxos/wnfs";
|
|
63
|
+
var readFile = (file) => {
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
const reader = new FileReader();
|
|
66
|
+
reader.onload = (event) => {
|
|
67
|
+
const result = event.target?.result;
|
|
68
|
+
if (result === null || result === void 0 || typeof result === "string") {
|
|
69
|
+
reject(/* @__PURE__ */ new Error("Expected an ArrayBuffer"));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
resolve(new Uint8Array(result));
|
|
73
|
+
};
|
|
74
|
+
reader.onerror = (err) => {
|
|
75
|
+
reject(err);
|
|
76
|
+
};
|
|
77
|
+
reader.readAsArrayBuffer(file);
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/helpers/load.ts
|
|
82
|
+
var loadWnfs = async ({ space, blockstore, instances }) => {
|
|
83
|
+
const propsAny = space.properties;
|
|
84
|
+
if (propsAny.wnfs_access_key !== void 0 && propsAny.wnfs_private_forest_cid !== void 0) Obj.update(space.properties, (obj) => {
|
|
85
|
+
delete obj["wnfs_access_key"];
|
|
86
|
+
delete obj["wnfs_private_forest_cid"];
|
|
87
|
+
});
|
|
88
|
+
if (propsAny.wnfs !== void 0 && Option.isNone(Annotation.get(space.properties, WnfsStateAnnotation))) Obj.update(space.properties, (properties) => {
|
|
89
|
+
Annotation.set(properties, WnfsStateAnnotation, propsAny.wnfs);
|
|
90
|
+
delete properties["wnfs"];
|
|
91
|
+
});
|
|
92
|
+
const wnfsState = Annotation.get(space.properties, WnfsStateAnnotation).pipe(Option.getOrUndefined);
|
|
93
|
+
const cacheKey = wnfsState?.privateForestCid;
|
|
94
|
+
if (cacheKey && instances?.[cacheKey]) return instances[cacheKey];
|
|
95
|
+
const instance = !!wnfsState ? await loadWnfsDir(blockstore, space) : await createWnfsDir(blockstore, space);
|
|
96
|
+
if (instances) {
|
|
97
|
+
const newCacheKey = Annotation.get(space.properties, WnfsStateAnnotation).pipe(Option.getOrUndefined)?.privateForestCid;
|
|
98
|
+
if (newCacheKey) instances[newCacheKey] = instance;
|
|
99
|
+
}
|
|
100
|
+
return instance;
|
|
101
|
+
};
|
|
102
|
+
var createWnfsDir = async (blockstore, space) => {
|
|
103
|
+
const wnfsStore = store(blockstore);
|
|
104
|
+
const rng = new Rng();
|
|
105
|
+
const forest = new PrivateForest(rng);
|
|
106
|
+
const dirResult = await PrivateDirectory.newAndStore(forest.emptyName(), /* @__PURE__ */ new Date(), forest, wnfsStore, rng);
|
|
107
|
+
const dir = dirResult.rootDir;
|
|
108
|
+
const [accessKeyRaw, newForest] = await dir.asNode().store(dirResult.forest, wnfsStore, rng);
|
|
109
|
+
const cidBytes = await newForest.store(wnfsStore);
|
|
110
|
+
Obj.update(space.properties, (properties) => {
|
|
111
|
+
Annotation.set(properties, WnfsStateAnnotation, {
|
|
112
|
+
accessKey: Uint8Arrays.toString(accessKeyRaw.toBytes(), "base64"),
|
|
113
|
+
privateForestCid: CID$1.decode(cidBytes).toString()
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
return {
|
|
117
|
+
directory: dir,
|
|
118
|
+
forest: newForest
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
var loadWnfsDir = async (blockstore, space) => {
|
|
122
|
+
const wnfsStore = store(blockstore);
|
|
123
|
+
const wnfsState = Annotation.get(space.properties, WnfsStateAnnotation).pipe(Option.getOrUndefined);
|
|
124
|
+
const accessKey = AccessKey.fromBytes(Uint8Arrays.fromString(wnfsState.accessKey, "base64"));
|
|
125
|
+
const forest = await PrivateForest.load(CID$1.parse(wnfsState.privateForestCid).bytes, wnfsStore);
|
|
126
|
+
return {
|
|
127
|
+
directory: (await PrivateNode.load(accessKey, forest, wnfsStore)).asDir(),
|
|
128
|
+
forest
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/helpers/wnfs-url.ts
|
|
133
|
+
var wnfsUrl = (filePath) => {
|
|
134
|
+
return "wnfs://" + filePath.map((f) => encodeURIComponent(f)).join("/");
|
|
135
|
+
};
|
|
136
|
+
var getPathFromUrl = (wnfsUrl) => wnfsUrl.replace(/^wnfs:\/\//, "").split("/").map((p) => decodeURIComponent(p));
|
|
137
|
+
var readWnfsFile = async ({ wnfsUrl, blockstore, forest, directory }) => {
|
|
138
|
+
const path = getPathFromUrl(wnfsUrl);
|
|
139
|
+
const wnfsStore = store(blockstore);
|
|
140
|
+
const { result } = await directory.read(path, true, forest, wnfsStore);
|
|
141
|
+
return result;
|
|
142
|
+
};
|
|
143
|
+
var getBlobUrl = async ({ wnfsUrl, blockstore, forest, directory, type }) => {
|
|
144
|
+
const result = await readWnfsFile({
|
|
145
|
+
wnfsUrl,
|
|
146
|
+
blockstore,
|
|
147
|
+
forest,
|
|
148
|
+
directory
|
|
149
|
+
});
|
|
150
|
+
const blob = new Blob([result], { type });
|
|
151
|
+
return URL.createObjectURL(blob);
|
|
152
|
+
};
|
|
153
|
+
//#endregion
|
|
154
|
+
//#region src/helpers/upload.ts
|
|
155
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-wnfs/src/helpers/upload.ts";
|
|
156
|
+
var upload = async ({ file, blockstore, instances, space }) => {
|
|
157
|
+
const { directory, forest } = await loadWnfs({
|
|
158
|
+
blockstore,
|
|
159
|
+
instances,
|
|
160
|
+
space
|
|
161
|
+
});
|
|
162
|
+
const wnfsStore = store(blockstore);
|
|
163
|
+
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
164
|
+
const hash = await sha256.digest(bytes);
|
|
165
|
+
const cid = CID$1.create(1, Raw.code, hash);
|
|
166
|
+
const path = filePath(cid.toString(), space);
|
|
167
|
+
const result = await directory.write(path, true, bytes, /* @__PURE__ */ new Date(), forest, wnfsStore, new Rng());
|
|
168
|
+
const [_, updatedForest] = await result.rootDir.store(result.forest, wnfsStore, new Rng());
|
|
169
|
+
const cidBytes = await updatedForest.store(wnfsStore);
|
|
170
|
+
const currentState = Annotation.get(space.properties, WnfsStateAnnotation).pipe(Option.getOrUndefined);
|
|
171
|
+
if (!currentState) throw new Error("WnfsStateAnnotation missing after loadWnfs; cannot persist forest CID.");
|
|
172
|
+
Obj.update(space.properties, (properties) => {
|
|
173
|
+
Annotation.set(properties, WnfsStateAnnotation, {
|
|
174
|
+
...currentState,
|
|
175
|
+
privateForestCid: CID$1.decode(cidBytes).toString()
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
const info = {
|
|
179
|
+
name: file.name,
|
|
180
|
+
type: file.type,
|
|
181
|
+
url: wnfsUrl(path),
|
|
182
|
+
cid: cid.toString()
|
|
183
|
+
};
|
|
184
|
+
log("upload", {
|
|
185
|
+
file,
|
|
186
|
+
info
|
|
187
|
+
}, {
|
|
188
|
+
"~LogMeta": "~LogMeta",
|
|
189
|
+
F: __dxlog_file,
|
|
190
|
+
L: 71,
|
|
191
|
+
S: void 0
|
|
192
|
+
});
|
|
193
|
+
return info;
|
|
194
|
+
};
|
|
195
|
+
//#endregion
|
|
196
|
+
export { wnfsUrl as a, filePath as c, storeName as d, WnfsStateAnnotation as f, readWnfsFile as i, readFile as l, getBlobUrl as n, loadWnfs as o, getPathFromUrl as r, Rng as s, upload as t, store as u };
|
|
197
|
+
|
|
198
|
+
//# sourceMappingURL=chunk-helpers.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-helpers.mjs","names":[],"sources":["../../src/annotations.ts","../../src/helpers/common.ts","../../src/helpers/load.ts","../../src/helpers/wnfs-url.ts","../../src/helpers/upload.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { Annotation } from '@dxos/echo';\n\n/** WNFS filesystem state stored on space properties meta. */\nexport const WnfsStateAnnotation = Annotation.make({\n id: 'org.dxos.plugin.wnfs.state',\n schema: Schema.Struct({\n accessKey: Schema.String,\n privateForestCid: Schema.String,\n }),\n});\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport type { Blockstore } from 'interface-blockstore';\nimport { CID } from 'multiformats/cid';\nimport { sha256 } from 'multiformats/hashes/sha2';\nimport { type BlockStore as WnfsBlockStore } from 'wnfs';\n\nimport * as crypto from '@dxos/crypto';\nimport { type Space } from '@dxos/react-client/echo';\n\n//\n// PATH\n//\n\nexport const filePath = (fileName: string, space: Space) => {\n return ['spaces', space.id, 'files', fileName];\n};\n\n//\n// RNG\n//\n\nexport class Rng {\n randomBytes(count: number): Uint8Array {\n return new Uint8Array(crypto.randomBytes(count));\n }\n}\n\n//\n// STORE\n//\n\nexport const store = (blockstore: Blockstore): WnfsBlockStore => {\n const getBlock = async (cid: Uint8Array): Promise<Uint8Array | undefined> => {\n const decodedCid = CID.decode(cid);\n return await blockstore.get(decodedCid);\n };\n\n const hasBlock = async (cid: Uint8Array): Promise<boolean> => {\n const decodedCid = CID.decode(cid);\n return await blockstore.has(decodedCid);\n };\n\n const putBlockKeyed = async (cid: Uint8Array, bytes: Uint8Array): Promise<void> => {\n const decodedCid = CID.decode(cid);\n await blockstore.put(decodedCid, bytes);\n };\n\n // Don't hash blocks with the rs-wnfs default Blake 3, sha256 has better support.\n const putBlock = async (bytes: Uint8Array, codec: number): Promise<Uint8Array> => {\n const hash = await sha256.digest(bytes);\n const cid = CID.create(1, codec, hash);\n await blockstore.put(cid, bytes);\n return cid.bytes;\n };\n\n return { getBlock, hasBlock, putBlockKeyed, putBlock };\n};\n\nexport const storeName = () => 'dxos/wnfs';\n\n//\n// OTHER\n//\n\nexport const readFile = (file: File): Promise<Uint8Array> => {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = (event) => {\n const result = event.target?.result;\n if (result === null || result === undefined || typeof result === 'string') {\n reject(new Error('Expected an ArrayBuffer'));\n return;\n }\n resolve(new Uint8Array(result));\n };\n reader.onerror = (err) => {\n reject(err);\n };\n reader.readAsArrayBuffer(file);\n });\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Option from 'effect/Option';\nimport type { Blockstore } from 'interface-blockstore';\nimport { CID } from 'multiformats';\nimport * as Uint8Arrays from 'uint8arrays';\nimport { AccessKey, PrivateDirectory, PrivateForest, PrivateNode } from 'wnfs';\n\nimport { Annotation, Obj } from '@dxos/echo';\nimport { type Space } from '@dxos/react-client/echo';\n\nimport { type WnfsCapabilities } from '#types';\n\nimport { WnfsStateAnnotation } from '../annotations';\nimport { Rng, store } from './common';\n\n//\n// LOAD\n//\n\nexport const loadWnfs = async ({\n space,\n blockstore,\n instances,\n}: {\n space: Space;\n blockstore: Blockstore;\n instances?: WnfsCapabilities.Instances;\n}) => {\n // TODO(wittjosiah): Remove.\n // Delete old properties if they exist (pre-DX-971 migration cleanup).\n const propsAny = space.properties as any;\n if (propsAny.wnfs_access_key !== undefined && propsAny.wnfs_private_forest_cid !== undefined) {\n Obj.update(space.properties, (obj) => {\n delete (obj as any)['wnfs_access_key'];\n delete (obj as any)['wnfs_private_forest_cid'];\n });\n }\n // Migrate legacy wnfs data key to annotation.\n if (propsAny.wnfs !== undefined && Option.isNone(Annotation.get(space.properties, WnfsStateAnnotation))) {\n Obj.update(space.properties, (properties) => {\n Annotation.set(properties, WnfsStateAnnotation, propsAny.wnfs);\n delete (properties as any)['wnfs'];\n });\n }\n\n const wnfsState = Annotation.get(space.properties, WnfsStateAnnotation).pipe(Option.getOrUndefined);\n const cacheKey = wnfsState?.privateForestCid as any;\n if (cacheKey && instances?.[cacheKey]) {\n return instances[cacheKey];\n }\n\n const exists = !!wnfsState;\n const instance = exists ? await loadWnfsDir(blockstore, space) : await createWnfsDir(blockstore, space);\n if (instances) {\n // Re-read after createWnfsDir so newly created instances are cached under the real CID.\n const newCacheKey = Annotation.get(space.properties, WnfsStateAnnotation).pipe(Option.getOrUndefined)\n ?.privateForestCid as any;\n if (newCacheKey) {\n instances[newCacheKey] = instance;\n }\n }\n\n return instance;\n};\n\n//\n// PRIVATE\n//\n\nconst createWnfsDir = async (blockstore: Blockstore, space: Space) => {\n const wnfsStore = store(blockstore);\n const rng = new Rng();\n const forest = new PrivateForest(rng);\n\n const dirResult = await PrivateDirectory.newAndStore(forest.emptyName(), new Date(), forest, wnfsStore, rng);\n const dir = dirResult.rootDir as PrivateDirectory;\n\n const [accessKeyRaw, newForest]: [AccessKey, PrivateForest] = await dir\n .asNode()\n .store(dirResult.forest as PrivateForest, wnfsStore, rng);\n\n const cidBytes = await newForest.store(wnfsStore);\n\n Obj.update(space.properties, (properties) => {\n Annotation.set(properties, WnfsStateAnnotation, {\n accessKey: Uint8Arrays.toString(accessKeyRaw.toBytes(), 'base64'),\n privateForestCid: CID.decode(cidBytes).toString(),\n });\n });\n\n return {\n directory: dir,\n forest: newForest,\n };\n};\n\nconst loadWnfsDir = async (blockstore: Blockstore, space: Space) => {\n const wnfsStore = store(blockstore);\n\n const wnfsState = Annotation.get(space.properties, WnfsStateAnnotation).pipe(Option.getOrUndefined)!;\n const accessKey = AccessKey.fromBytes(Uint8Arrays.fromString(wnfsState.accessKey, 'base64'));\n const forest: PrivateForest = await PrivateForest.load(CID.parse(wnfsState.privateForestCid).bytes, wnfsStore);\n const node: PrivateNode = await PrivateNode.load(accessKey, forest, wnfsStore);\n\n return {\n directory: node.asDir(),\n forest,\n };\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport type { Blockstore } from 'interface-blockstore';\nimport { type PrivateDirectory, type PrivateForest } from 'wnfs';\n\nimport { store } from './common';\n\nexport const wnfsUrl = (filePath: string[]) => {\n return 'wnfs://' + filePath.map((f) => encodeURIComponent(f)).join('/');\n};\n\nexport const getPathFromUrl = (wnfsUrl: string) =>\n wnfsUrl\n .replace(/^wnfs:\\/\\//, '')\n .split('/')\n .map((p) => decodeURIComponent(p));\n\nexport const readWnfsFile = async ({\n wnfsUrl,\n blockstore,\n forest,\n directory,\n}: {\n wnfsUrl: string;\n blockstore: Blockstore;\n forest: PrivateForest;\n directory: PrivateDirectory;\n}): Promise<Uint8Array> => {\n const path = getPathFromUrl(wnfsUrl);\n const wnfsStore = store(blockstore);\n const { result } = await directory.read(path, true, forest, wnfsStore);\n return result;\n};\n\nexport const getBlobUrl = async ({\n wnfsUrl,\n blockstore,\n forest,\n directory,\n type,\n}: {\n wnfsUrl: string;\n blockstore: Blockstore;\n forest: PrivateForest;\n directory: PrivateDirectory;\n type?: string;\n}) => {\n const result = await readWnfsFile({ wnfsUrl, blockstore, forest, directory });\n // `Uint8Array` is generic over `ArrayBufferLike` (incl. `SharedArrayBuffer`) while DOM's\n // `BlobPart` only covers `ArrayBuffer`-backed views — a gap between the DOM lib types and the\n // TS standard lib, not fixable by typing `result` differently.\n const blob = new Blob([result as BlobPart], { type });\n return URL.createObjectURL(blob);\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Option from 'effect/Option';\nimport type { Blockstore } from 'interface-blockstore';\nimport { CID } from 'multiformats';\nimport * as Raw from 'multiformats/codecs/raw';\nimport { sha256 } from 'multiformats/hashes/sha2';\n\nimport type { Space } from '@dxos/client/echo';\nimport { Annotation, Obj } from '@dxos/echo';\nimport { log } from '@dxos/log';\n\nimport { type WnfsCapabilities } from '#types';\n\nimport { WnfsStateAnnotation } from '../annotations';\nimport { Rng, filePath, store } from './common';\nimport { loadWnfs } from './load';\nimport { wnfsUrl } from './wnfs-url';\n\nexport const upload = async ({\n file,\n blockstore,\n instances,\n space,\n}: {\n file: File;\n blockstore: Blockstore;\n instances?: WnfsCapabilities.Instances;\n space: Space;\n}) => {\n const { directory, forest } = await loadWnfs({ blockstore, instances, space });\n const wnfsStore = store(blockstore);\n\n const bytes = new Uint8Array(await file.arrayBuffer());\n const hash = await sha256.digest(bytes);\n const cid = CID.create(1, Raw.code, hash);\n\n const path = filePath(cid.toString(), space);\n\n // Given the root directory of the private file system,\n // write the file contents to `path` in said directory.\n const result = await directory.write(path, true, bytes, new Date(), forest, wnfsStore, new Rng());\n\n // Given the new immutable instance of the root directory after writing to it,\n // **store** the changes in the \"dark forest\" and the associated (block) store.\n const [_, updatedForest] = await result.rootDir.store(result.forest, wnfsStore, new Rng());\n const cidBytes = await updatedForest.store(wnfsStore);\n\n // Update the forest pointer on the associated space.\n const currentState = Annotation.get(space.properties, WnfsStateAnnotation).pipe(Option.getOrUndefined);\n if (!currentState) {\n throw new Error('WnfsStateAnnotation missing after loadWnfs; cannot persist forest CID.');\n }\n Obj.update(space.properties, (properties) => {\n Annotation.set(properties, WnfsStateAnnotation, {\n ...currentState,\n privateForestCid: CID.decode(cidBytes).toString(),\n });\n });\n\n // Generate `wnfs://` URL & return the info.\n const info = {\n name: file.name,\n type: file.type,\n url: wnfsUrl(path),\n cid: cid.toString(),\n };\n\n log('upload', { file, info });\n return info;\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Plugin } from "@dxos/app-framework";
|
|
2
|
+
import { Config2 } from "@dxos/app-framework/config";
|
|
3
|
+
import { trim } from "@dxos/util";
|
|
4
|
+
//#region dx.config.ts
|
|
5
|
+
var dx_config_default = Config2.make({ plugin: {
|
|
6
|
+
key: "org.dxos.plugin.wnfs",
|
|
7
|
+
name: "WNFS",
|
|
8
|
+
author: "DXOS",
|
|
9
|
+
description: trim`
|
|
10
|
+
Decentralized, end-to-end encrypted file storage for DXOS Composer built on the Web Native File System (WNFS) protocol.
|
|
11
|
+
|
|
12
|
+
WNFS organizes files inside a cryptographic "dark forest" — a content-addressed private file system
|
|
13
|
+
where each write produces a new immutable root CID. Files are stored as IPLD blocks (CIDv1, sha2-256),
|
|
14
|
+
cached locally in IndexedDB, and asynchronously replicated to the DXOS edge blob service as CAR archives.
|
|
15
|
+
Uploads and reads are scoped to a DXOS Space; the forest root CID is persisted atomically on the
|
|
16
|
+
space's ECHO properties so the file system state survives across sessions and devices.
|
|
17
|
+
|
|
18
|
+
The plugin registers a \`BlobBackend\` on the ECHO Hypergraph (and a matching \`FileCapabilities.Backend\`
|
|
19
|
+
descriptor) so any plugin that uses \`plugin-file\` (e.g. \`plugin-studio\`) can upload files and resolve
|
|
20
|
+
\`wnfs://\` URLs without coupling to the storage implementation. The blockstore automatically queues
|
|
21
|
+
blocks while offline and flushes them when connectivity is restored.
|
|
22
|
+
`,
|
|
23
|
+
icon: {
|
|
24
|
+
key: "ph--file-cloud--regular",
|
|
25
|
+
hue: "teal"
|
|
26
|
+
},
|
|
27
|
+
source: "https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-wnfs",
|
|
28
|
+
spec: "PLUGIN.mdl",
|
|
29
|
+
tags: ["labs"],
|
|
30
|
+
dependsOn: ["org.dxos.plugin.file"]
|
|
31
|
+
} });
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/meta.ts
|
|
34
|
+
var meta = Plugin.getMetaFromConfig(dx_config_default);
|
|
35
|
+
//#endregion
|
|
36
|
+
export { meta as t };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=chunk-meta.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-meta.mjs","names":[],"sources":["../../dx.config.ts","../../src/meta.ts"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport { Config2 } from '@dxos/app-framework/config';\nimport { trim } from '@dxos/util';\n\nexport default Config2.make({\n plugin: {\n key: 'org.dxos.plugin.wnfs',\n name: 'WNFS',\n author: 'DXOS',\n description: trim`\n Decentralized, end-to-end encrypted file storage for DXOS Composer built on the Web Native File System (WNFS) protocol.\n\n WNFS organizes files inside a cryptographic \"dark forest\" — a content-addressed private file system\n where each write produces a new immutable root CID. Files are stored as IPLD blocks (CIDv1, sha2-256),\n cached locally in IndexedDB, and asynchronously replicated to the DXOS edge blob service as CAR archives.\n Uploads and reads are scoped to a DXOS Space; the forest root CID is persisted atomically on the\n space's ECHO properties so the file system state survives across sessions and devices.\n\n The plugin registers a \\`BlobBackend\\` on the ECHO Hypergraph (and a matching \\`FileCapabilities.Backend\\`\n descriptor) so any plugin that uses \\`plugin-file\\` (e.g. \\`plugin-studio\\`) can upload files and resolve\n \\`wnfs://\\` URLs without coupling to the storage implementation. The blockstore automatically queues\n blocks while offline and flushes them when connectivity is restored.\n `,\n icon: { key: 'ph--file-cloud--regular', hue: 'teal' },\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-wnfs',\n spec: 'PLUGIN.mdl',\n tags: ['labs'],\n dependsOn: ['org.dxos.plugin.file'],\n },\n});\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\n\nimport config from '../dx.config';\n\nexport const meta = Plugin.getMetaFromConfig(config);\n"],"mappings":";;;;AAOA,IAAA,oBAAe,QAAQ,KAAK,EAC1B,QAAQ;CACN,KAAK;CACL,MAAM;CACN,QAAQ;CACR,aAAa,IAAI;;;;;;;;;;;;;;CAcjB,MAAM;EAAE,KAAK;EAA2B,KAAK;CAAO;CACpD,QAAQ;CACR,MAAM;CACN,MAAM,CAAC,MAAM;CACb,WAAW,CAAC,sBAAsB;AACpC,EACF,CAAC;;;ACxBD,IAAa,OAAO,OAAO,kBAAkB,iBAAM"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ActivationEvent, Capability } from "@dxos/app-framework";
|
|
2
|
+
import { meta } from "#meta";
|
|
3
|
+
//#region \0rolldown/runtime.js
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __exportAll = (all, no_symbols) => {
|
|
6
|
+
let target = {};
|
|
7
|
+
for (var name in all) __defProp(target, name, {
|
|
8
|
+
get: all[name],
|
|
9
|
+
enumerable: true
|
|
10
|
+
});
|
|
11
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
12
|
+
return target;
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/types/WnfsCapabilities.ts
|
|
16
|
+
var WnfsCapabilities_exports = /* @__PURE__ */ __exportAll({
|
|
17
|
+
Blockstore: () => Blockstore,
|
|
18
|
+
Instances: () => Instances,
|
|
19
|
+
WNFS_BACKEND: () => WNFS_BACKEND,
|
|
20
|
+
WNFS_SCHEME: () => WNFS_SCHEME
|
|
21
|
+
});
|
|
22
|
+
var Blockstore = Capability.make(`${meta.profile.key}.capability.blockstore`);
|
|
23
|
+
var Instances = Capability.make(`${meta.profile.key}.capability.instances`);
|
|
24
|
+
/**
|
|
25
|
+
* Name this extension registers its `BlobBackend` under on the ECHO Hypergraph. Core packages
|
|
26
|
+
* (`@dxos/echo`, `@dxos/echo-client`, `@dxos/client`) never reference this constant.
|
|
27
|
+
*/
|
|
28
|
+
var WNFS_BACKEND = "wnfs";
|
|
29
|
+
/** URI scheme this extension's `BlobBackend` resolves at read time. */
|
|
30
|
+
var WNFS_SCHEME = "wnfs";
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/types/WnfsEvents.ts
|
|
33
|
+
var WnfsEvents_exports = /* @__PURE__ */ __exportAll({ DependenciesReady: () => DependenciesReady });
|
|
34
|
+
/**
|
|
35
|
+
* Fired by the `dependencies` module (via `firesAfterActivation`) once it finishes contributing
|
|
36
|
+
* `WnfsCapabilities.Blockstore`/`Instances`. `blob-backend` activates on this event rather than
|
|
37
|
+
* `ClientEvents.ClientReady` directly — `dependencies` also activates on `ClientReady`, and
|
|
38
|
+
* modules activating on the same event load concurrently with capabilities invisible to each
|
|
39
|
+
* other until the whole batch settles, so `blob-backend` couldn't otherwise be guaranteed to run
|
|
40
|
+
* after `dependencies`.
|
|
41
|
+
*/
|
|
42
|
+
var DependenciesReady = ActivationEvent.make(`${meta.profile.key}.event.dependenciesReady`);
|
|
43
|
+
//#endregion
|
|
44
|
+
export { WnfsCapabilities_exports as n, WnfsEvents_exports as t };
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=chunk-types.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-types.mjs","names":[],"sources":["../../src/types/WnfsCapabilities.ts","../../src/types/WnfsEvents.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\nimport { type Blockstore as BlockstoreInterface } from 'interface-blockstore';\nimport { type PrivateDirectory, type PrivateForest } from 'wnfs';\n\nimport { Capability } from '@dxos/app-framework';\nimport { type SpaceId } from '@dxos/keys';\n\nimport { meta } from '#meta';\n\nexport const Blockstore = Capability.make<BlockstoreInterface>(`${meta.profile.key}.capability.blockstore`);\n\nexport type Instances = Record<SpaceId, { directory: PrivateDirectory; forest: PrivateForest }>;\nexport const Instances = Capability.make<Instances>(`${meta.profile.key}.capability.instances`);\n\n/**\n * Name this extension registers its `BlobBackend` under on the ECHO Hypergraph. Core packages\n * (`@dxos/echo`, `@dxos/echo-client`, `@dxos/client`) never reference this constant.\n */\nexport const WNFS_BACKEND = 'wnfs';\n\n/** URI scheme this extension's `BlobBackend` resolves at read time. */\nexport const WNFS_SCHEME = 'wnfs';\n","//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport { ActivationEvent } from '@dxos/app-framework';\n\nimport { meta } from '#meta';\n\n/**\n * Fired by the `dependencies` module (via `firesAfterActivation`) once it finishes contributing\n * `WnfsCapabilities.Blockstore`/`Instances`. `blob-backend` activates on this event rather than\n * `ClientEvents.ClientReady` directly — `dependencies` also activates on `ClientReady`, and\n * modules activating on the same event load concurrently with capabilities invisible to each\n * other until the whole batch settles, so `blob-backend` couldn't otherwise be guaranteed to run\n * after `dependencies`.\n */\nexport const DependenciesReady = ActivationEvent.make(`${meta.profile.key}.event.dependenciesReady`);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAcA,IAAa,aAAa,WAAW,KAA0B,GAAG,KAAK,QAAQ,IAAI,uBAAuB;AAG1G,IAAa,YAAY,WAAW,KAAgB,GAAG,KAAK,QAAQ,IAAI,sBAAsB;;;;;AAM9F,IAAa,eAAe;;AAG5B,IAAa,cAAc;;;;;;;;;;;;ACR3B,IAAa,oBAAoB,gBAAgB,KAAK,GAAG,KAAK,QAAQ,IAAI,yBAAyB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as wnfsUrl, c as filePath, d as storeName, i as readWnfsFile, l as readFile, n as getBlobUrl, o as loadWnfs, r as getPathFromUrl, s as Rng, t as upload, u as store } from "./chunk-helpers.mjs";
|
|
2
|
+
export { Rng, filePath, getBlobUrl, getPathFromUrl, loadWnfs, readFile, readWnfsFile, store, storeName, upload, wnfsUrl };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { n as WnfsCapabilities_exports, t as WnfsEvents_exports } from "./chunk-types.mjs";
|
|
2
|
+
import { a as wnfsUrl, c as filePath, d as storeName, f as WnfsStateAnnotation, i as readWnfsFile, l as readFile, n as getBlobUrl, o as loadWnfs, r as getPathFromUrl, s as Rng, t as upload, u as store } from "./chunk-helpers.mjs";
|
|
3
|
+
import { t as meta } from "./chunk-meta.mjs";
|
|
4
|
+
export { Rng, WnfsCapabilities_exports as WnfsCapabilities, WnfsEvents_exports as WnfsEvents, WnfsStateAnnotation, filePath, getBlobUrl, getPathFromUrl, loadWnfs, meta, readFile, readWnfsFile, store, storeName, upload, wnfsUrl };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.mjs","names":[],"sources":["../../src/plugin.ts"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\n\nimport { meta } from './meta';\n\nexport const WnfsPlugin = Plugin.lazy(meta, () => import('#plugin'));\n"],"mappings":";;;AAQA,IAAa,aAAa,OAAO,KAAK,YAAY,OAAO,UAAU"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translations.mjs","names":[],"sources":["../../src/translations.ts"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Resource } from '@dxos/react-ui';\n\nimport { meta } from '#meta';\n\nexport const translations = [\n {\n 'en-US': {\n [meta.profile.key]: {\n 'plugin.name': 'WNFS',\n },\n },\n },\n] as const satisfies Resource[];\n"],"mappings":";;AAQA,IAAa,eAAe,CAC1B,EACE,SAAS,GACN,KAAK,QAAQ,MAAM,EAClB,eAAe,OACjB,EACF,EACF,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WnfsPlugin.d.ts","sourceRoot":"","sources":["../../../src/WnfsPlugin.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WnfsPlugin.d.ts","sourceRoot":"","sources":["../../../src/WnfsPlugin.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAY7C,eAAO,MAAM,UAAU,4BAiBtB,CAAC;eAEa,UAAU"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as Effect from 'effect/Effect';
|
|
2
|
+
import type { Blockstore } from 'interface-blockstore';
|
|
3
|
+
import { Capability } from '@dxos/app-framework';
|
|
4
|
+
import { type Client } from '@dxos/client';
|
|
5
|
+
import { type BlobBackend } from '@dxos/echo-protocol';
|
|
6
|
+
import { WnfsCapabilities } from '#types';
|
|
7
|
+
interface CreateWnfsBlobBackendOptions {
|
|
8
|
+
client: Client;
|
|
9
|
+
blockstore: Blockstore;
|
|
10
|
+
instances?: WnfsCapabilities.Instances;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Blob backend that stores bytes in a space's WNFS private forest, addressed by `wnfs://…` URIs.
|
|
14
|
+
* The underlying WASM bindings (`directory.read`) don't expose a distinct not-found error type, so
|
|
15
|
+
* `readBytes`/`getUrl` can't tell a missing path from a genuine transport/blockstore failure —
|
|
16
|
+
* both are logged and reported as a miss (`undefined`) rather than risk rethrowing on the common
|
|
17
|
+
* missing-file path.
|
|
18
|
+
*/
|
|
19
|
+
export declare const createWnfsBlobBackend: ({ client, blockstore, instances }: CreateWnfsBlobBackendOptions) => BlobBackend;
|
|
20
|
+
declare const _default: (props: void) => Effect.Effect<Capability.Any, Error, import("effect/Scope").Scope | Capability.Service>;
|
|
21
|
+
export default _default;
|
|
22
|
+
//# sourceMappingURL=blob-backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-backend.d.ts","sourceRoot":"","sources":["../../../../src/capabilities/blob-backend.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAOvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAI1C,UAAU,4BAA4B;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,CAAC,EAAE,gBAAgB,CAAC,SAAS,CAAC;CACxC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,sCAAuC,4BAA4B,KAAG,WA+CvG,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-backend.test.d.ts","sourceRoot":"","sources":["../../../../src/capabilities/blob-backend.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import * as Effect from 'effect/Effect';
|
|
2
|
+
import { Capability } from '@dxos/app-framework';
|
|
3
|
+
declare const _default: (props: void) => Effect.Effect<[Capability.Any, Capability.Any], Error, import("effect/Scope").Scope | Capability.Service>;
|
|
4
|
+
export default _default;
|
|
5
|
+
//# sourceMappingURL=dependencies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../../../../src/capabilities/dependencies.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Capability } from '@dxos/app-framework';
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const UrlResolver: Capability.LazyCapability<void, Capability.ModuleReturn, Error>;
|
|
2
|
+
export declare const BlobBackend: Capability.LazyCapability<void, Capability.ModuleReturn, Error>;
|
|
3
|
+
export declare const Dependencies: Capability.LazyCapability<void, Capability.ModuleReturn, Error>;
|
|
5
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/capabilities/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,eAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/capabilities/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,eAAO,MAAM,WAAW,iEAAiE,CAAC;AAE1F,eAAO,MAAM,YAAY,iEAAkE,CAAC"}
|
|
@@ -2,6 +2,12 @@ import type { Blockstore } from 'interface-blockstore';
|
|
|
2
2
|
import { type PrivateDirectory, type PrivateForest } from 'wnfs';
|
|
3
3
|
export declare const wnfsUrl: (filePath: string[]) => string;
|
|
4
4
|
export declare const getPathFromUrl: (wnfsUrl: string) => string[];
|
|
5
|
+
export declare const readWnfsFile: ({ wnfsUrl, blockstore, forest, directory, }: {
|
|
6
|
+
wnfsUrl: string;
|
|
7
|
+
blockstore: Blockstore;
|
|
8
|
+
forest: PrivateForest;
|
|
9
|
+
directory: PrivateDirectory;
|
|
10
|
+
}) => Promise<Uint8Array>;
|
|
5
11
|
export declare const getBlobUrl: ({ wnfsUrl, blockstore, forest, directory, type, }: {
|
|
6
12
|
wnfsUrl: string;
|
|
7
13
|
blockstore: Blockstore;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wnfs-url.d.ts","sourceRoot":"","sources":["../../../../src/helpers/wnfs-url.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,MAAM,CAAC;AAIjE,eAAO,MAAM,OAAO,aAAc,MAAM,EAAE,WAEzC,CAAC;AAEF,eAAO,MAAM,cAAc,YAAa,MAAM,aAIR,CAAC;AAEvC,eAAO,MAAM,UAAU,sDAMpB;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,gBAAgB,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,
|
|
1
|
+
{"version":3,"file":"wnfs-url.d.ts","sourceRoot":"","sources":["../../../../src/helpers/wnfs-url.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,MAAM,CAAC;AAIjE,eAAO,MAAM,OAAO,aAAc,MAAM,EAAE,WAEzC,CAAC;AAEF,eAAO,MAAM,cAAc,YAAa,MAAM,aAIR,CAAC;AAEvC,eAAO,MAAM,YAAY,gDAKtB;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,gBAAgB,CAAC;CAC7B,KAAG,OAAO,CAAC,UAAU,CAKrB,CAAC;AAEF,eAAO,MAAM,UAAU,sDAMpB;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,gBAAgB,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,oBAOA,CAAC"}
|
|
@@ -8,4 +8,11 @@ export type Instances = Record<SpaceId, {
|
|
|
8
8
|
forest: PrivateForest;
|
|
9
9
|
}>;
|
|
10
10
|
export declare const Instances: Capability.InterfaceDef<Instances>;
|
|
11
|
+
/**
|
|
12
|
+
* Name this extension registers its `BlobBackend` under on the ECHO Hypergraph. Core packages
|
|
13
|
+
* (`@dxos/echo`, `@dxos/echo-client`, `@dxos/client`) never reference this constant.
|
|
14
|
+
*/
|
|
15
|
+
export declare const WNFS_BACKEND = "wnfs";
|
|
16
|
+
/** URI scheme this extension's `BlobBackend` resolves at read time. */
|
|
17
|
+
export declare const WNFS_SCHEME = "wnfs";
|
|
11
18
|
//# sourceMappingURL=WnfsCapabilities.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WnfsCapabilities.d.ts","sourceRoot":"","sources":["../../../../src/types/WnfsCapabilities.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,UAAU,IAAI,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,MAAM,CAAC;AAEjE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAI1C,eAAO,MAAM,UAAU,8EAAoF,CAAC;AAE5G,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,EAAE;IAAE,SAAS,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC,CAAC;AAChG,eAAO,MAAM,SAAS,oCAAyE,CAAC"}
|
|
1
|
+
{"version":3,"file":"WnfsCapabilities.d.ts","sourceRoot":"","sources":["../../../../src/types/WnfsCapabilities.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,UAAU,IAAI,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,MAAM,CAAC;AAEjE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAI1C,eAAO,MAAM,UAAU,8EAAoF,CAAC;AAE5G,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,EAAE;IAAE,SAAS,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC,CAAC;AAChG,eAAO,MAAM,SAAS,oCAAyE,CAAC;AAEhG;;;GAGG;AACH,eAAO,MAAM,YAAY,SAAS,CAAC;AAEnC,uEAAuE;AACvE,eAAO,MAAM,WAAW,SAAS,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ActivationEvent } from '@dxos/app-framework';
|
|
2
|
+
/**
|
|
3
|
+
* Fired by the `dependencies` module (via `firesAfterActivation`) once it finishes contributing
|
|
4
|
+
* `WnfsCapabilities.Blockstore`/`Instances`. `blob-backend` activates on this event rather than
|
|
5
|
+
* `ClientEvents.ClientReady` directly — `dependencies` also activates on `ClientReady`, and
|
|
6
|
+
* modules activating on the same event load concurrently with capabilities invisible to each
|
|
7
|
+
* other until the whole batch settles, so `blob-backend` couldn't otherwise be guaranteed to run
|
|
8
|
+
* after `dependencies`.
|
|
9
|
+
*/
|
|
10
|
+
export declare const DependenciesReady: ActivationEvent.ActivationEvent;
|
|
11
|
+
//# sourceMappingURL=WnfsEvents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WnfsEvents.d.ts","sourceRoot":"","sources":["../../../../src/types/WnfsEvents.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAItD;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,iCAAsE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/types/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,gBAAgB,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/types/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,gBAAgB,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC"}
|