@dxos/plugin-wnfs 0.8.4-main.fcfe5033a5 → 0.8.4-staging.60fe92afc8

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.
Files changed (178) hide show
  1. package/LICENSE +102 -5
  2. package/PLUGIN.mdl +371 -0
  3. package/README.md +2 -2
  4. package/dist/lib/neutral/WnfsPlugin.mjs +51 -0
  5. package/dist/lib/neutral/WnfsPlugin.mjs.map +7 -0
  6. package/dist/lib/neutral/WnfsPlugin.node.mjs +12 -0
  7. package/dist/lib/neutral/WnfsPlugin.node.mjs.map +7 -0
  8. package/dist/lib/neutral/WnfsPlugin.workerd.mjs +12 -0
  9. package/dist/lib/neutral/WnfsPlugin.workerd.mjs.map +7 -0
  10. package/dist/lib/neutral/backend-4HPTHS33.mjs +47 -0
  11. package/dist/lib/neutral/backend-4HPTHS33.mjs.map +7 -0
  12. package/dist/lib/neutral/blockstore-U6SPNL2C.mjs +190 -0
  13. package/dist/lib/neutral/blockstore-U6SPNL2C.mjs.map +7 -0
  14. package/dist/lib/neutral/capabilities/index.mjs +13 -0
  15. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  16. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
  17. package/dist/lib/neutral/chunk-KUQHRT52.mjs +39 -0
  18. package/dist/lib/neutral/chunk-KUQHRT52.mjs.map +7 -0
  19. package/dist/lib/{browser/chunk-N6Y4QPNF.mjs → neutral/chunk-L33MOD23.mjs} +97 -28
  20. package/dist/lib/neutral/chunk-L33MOD23.mjs.map +7 -0
  21. package/dist/lib/neutral/chunk-QODCKFTY.mjs +19 -0
  22. package/dist/lib/neutral/chunk-QODCKFTY.mjs.map +7 -0
  23. package/dist/lib/neutral/helpers/index.mjs +26 -0
  24. package/dist/lib/neutral/helpers/index.mjs.map +7 -0
  25. package/dist/lib/neutral/index.mjs +36 -0
  26. package/dist/lib/neutral/index.mjs.map +7 -0
  27. package/dist/lib/neutral/meta.json +1 -0
  28. package/dist/lib/neutral/meta.mjs +8 -0
  29. package/dist/lib/neutral/meta.mjs.map +7 -0
  30. package/dist/lib/neutral/plugin.mjs +12 -0
  31. package/dist/lib/neutral/plugin.mjs.map +7 -0
  32. package/dist/lib/neutral/translations.mjs +17 -0
  33. package/dist/lib/neutral/translations.mjs.map +7 -0
  34. package/dist/lib/neutral/types/index.mjs +8 -0
  35. package/dist/lib/neutral/types/index.mjs.map +7 -0
  36. package/dist/lib/neutral/url-resolver-BIRH7WHL.mjs +47 -0
  37. package/dist/lib/neutral/url-resolver-BIRH7WHL.mjs.map +7 -0
  38. package/dist/types/src/WnfsPlugin.d.ts +1 -0
  39. package/dist/types/src/WnfsPlugin.d.ts.map +1 -1
  40. package/dist/types/src/WnfsPlugin.node.d.ts +4 -0
  41. package/dist/types/src/WnfsPlugin.node.d.ts.map +1 -0
  42. package/dist/types/src/WnfsPlugin.test.d.ts +2 -0
  43. package/dist/types/src/WnfsPlugin.test.d.ts.map +1 -0
  44. package/dist/types/src/WnfsPlugin.workerd.d.ts +4 -0
  45. package/dist/types/src/WnfsPlugin.workerd.d.ts.map +1 -0
  46. package/dist/types/src/annotations.d.ts +7 -0
  47. package/dist/types/src/annotations.d.ts.map +1 -0
  48. package/dist/types/src/blockstore.d.ts.map +1 -1
  49. package/dist/types/src/capabilities/backend.d.ts +7 -0
  50. package/dist/types/src/capabilities/backend.d.ts.map +1 -0
  51. package/dist/types/src/capabilities/blockstore.d.ts.map +1 -1
  52. package/dist/types/src/capabilities/index.d.ts +3 -5
  53. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  54. package/dist/types/src/capabilities/url-resolver.d.ts +7 -0
  55. package/dist/types/src/capabilities/url-resolver.d.ts.map +1 -0
  56. package/dist/types/src/helpers/common.d.ts.map +1 -1
  57. package/dist/types/src/helpers/load.d.ts.map +1 -1
  58. package/dist/types/src/helpers/upload.d.ts.map +1 -1
  59. package/dist/types/src/helpers/wnfs-url.d.ts.map +1 -1
  60. package/dist/types/src/index.d.ts +3 -2
  61. package/dist/types/src/index.d.ts.map +1 -1
  62. package/dist/types/src/meta.d.ts +1 -1
  63. package/dist/types/src/meta.d.ts.map +1 -1
  64. package/dist/types/src/plugin.d.ts +3 -0
  65. package/dist/types/src/plugin.d.ts.map +1 -0
  66. package/dist/types/src/translations.d.ts +2 -16
  67. package/dist/types/src/translations.d.ts.map +1 -1
  68. package/dist/types/src/types/WnfsCapabilities.d.ts +11 -0
  69. package/dist/types/src/types/WnfsCapabilities.d.ts.map +1 -0
  70. package/dist/types/src/types/index.d.ts +1 -3
  71. package/dist/types/src/types/index.d.ts.map +1 -1
  72. package/dist/types/tsconfig.tsbuildinfo +1 -1
  73. package/package.json +74 -61
  74. package/src/WnfsPlugin.node.ts +11 -0
  75. package/src/WnfsPlugin.test.ts +20 -0
  76. package/src/WnfsPlugin.tsx +16 -40
  77. package/src/WnfsPlugin.workerd.ts +11 -0
  78. package/src/annotations.ts +16 -0
  79. package/src/capabilities/backend.ts +43 -0
  80. package/src/capabilities/blockstore.ts +1 -1
  81. package/src/capabilities/index.ts +11 -8
  82. package/src/capabilities/url-resolver.ts +44 -0
  83. package/src/helpers/load.ts +32 -18
  84. package/src/helpers/upload.ts +12 -3
  85. package/src/index.ts +3 -2
  86. package/src/meta.ts +22 -6
  87. package/src/plugin.ts +9 -0
  88. package/src/translations.ts +1 -14
  89. package/src/types/WnfsCapabilities.ts +18 -0
  90. package/src/types/index.ts +1 -3
  91. package/src/vite-env.d.ts +10 -0
  92. package/dist/lib/browser/chunk-BM3MEFES.mjs +0 -69
  93. package/dist/lib/browser/chunk-BM3MEFES.mjs.map +0 -7
  94. package/dist/lib/browser/chunk-N6Y4QPNF.mjs.map +0 -7
  95. package/dist/lib/browser/chunk-VXUCZHVZ.mjs +0 -69
  96. package/dist/lib/browser/chunk-VXUCZHVZ.mjs.map +0 -7
  97. package/dist/lib/browser/create-NOHKWE67.mjs +0 -24
  98. package/dist/lib/browser/create-NOHKWE67.mjs.map +0 -7
  99. package/dist/lib/browser/create-file-N7ADCFOF.mjs +0 -49
  100. package/dist/lib/browser/create-file-N7ADCFOF.mjs.map +0 -7
  101. package/dist/lib/browser/index.mjs +0 -117
  102. package/dist/lib/browser/index.mjs.map +0 -7
  103. package/dist/lib/browser/meta.json +0 -1
  104. package/dist/lib/browser/operations/index.mjs +0 -13
  105. package/dist/lib/browser/operations/index.mjs.map +0 -7
  106. package/dist/lib/browser/types/index.mjs +0 -11
  107. package/dist/lib/browser/upload-DA7GBOXF.mjs +0 -42
  108. package/dist/lib/browser/upload-DA7GBOXF.mjs.map +0 -7
  109. package/dist/types/src/capabilities/file-uploader.d.ts +0 -6
  110. package/dist/types/src/capabilities/file-uploader.d.ts.map +0 -1
  111. package/dist/types/src/capabilities/markdown.d.ts +0 -5
  112. package/dist/types/src/capabilities/markdown.d.ts.map +0 -1
  113. package/dist/types/src/capabilities/operation-handler.d.ts +0 -6
  114. package/dist/types/src/capabilities/operation-handler.d.ts.map +0 -1
  115. package/dist/types/src/capabilities/react-surface.d.ts +0 -5
  116. package/dist/types/src/capabilities/react-surface.d.ts.map +0 -1
  117. package/dist/types/src/components/FileInput/FileInput.d.ts +0 -8
  118. package/dist/types/src/components/FileInput/FileInput.d.ts.map +0 -1
  119. package/dist/types/src/components/FileInput/index.d.ts +0 -2
  120. package/dist/types/src/components/FileInput/index.d.ts.map +0 -1
  121. package/dist/types/src/components/FilePreview/FilePreview.d.ts +0 -12
  122. package/dist/types/src/components/FilePreview/FilePreview.d.ts.map +0 -1
  123. package/dist/types/src/components/FilePreview/index.d.ts +0 -2
  124. package/dist/types/src/components/FilePreview/index.d.ts.map +0 -1
  125. package/dist/types/src/components/index.d.ts +0 -3
  126. package/dist/types/src/components/index.d.ts.map +0 -1
  127. package/dist/types/src/containers/FileContainer/FileContainer.d.ts +0 -7
  128. package/dist/types/src/containers/FileContainer/FileContainer.d.ts.map +0 -1
  129. package/dist/types/src/containers/FileContainer/index.d.ts +0 -2
  130. package/dist/types/src/containers/FileContainer/index.d.ts.map +0 -1
  131. package/dist/types/src/containers/index.d.ts +0 -3
  132. package/dist/types/src/containers/index.d.ts.map +0 -1
  133. package/dist/types/src/extensions/image.d.ts +0 -14
  134. package/dist/types/src/extensions/image.d.ts.map +0 -1
  135. package/dist/types/src/extensions/image.stories.d.ts +0 -11
  136. package/dist/types/src/extensions/image.stories.d.ts.map +0 -1
  137. package/dist/types/src/extensions/index.d.ts +0 -2
  138. package/dist/types/src/extensions/index.d.ts.map +0 -1
  139. package/dist/types/src/operations/create-file.d.ts +0 -5
  140. package/dist/types/src/operations/create-file.d.ts.map +0 -1
  141. package/dist/types/src/operations/create.d.ts +0 -5
  142. package/dist/types/src/operations/create.d.ts.map +0 -1
  143. package/dist/types/src/operations/definitions.d.ts +0 -38
  144. package/dist/types/src/operations/definitions.d.ts.map +0 -1
  145. package/dist/types/src/operations/index.d.ts +0 -4
  146. package/dist/types/src/operations/index.d.ts.map +0 -1
  147. package/dist/types/src/operations/upload.d.ts +0 -5
  148. package/dist/types/src/operations/upload.d.ts.map +0 -1
  149. package/dist/types/src/types/File.d.ts +0 -16
  150. package/dist/types/src/types/File.d.ts.map +0 -1
  151. package/dist/types/src/types/capabilities.d.ts +0 -13
  152. package/dist/types/src/types/capabilities.d.ts.map +0 -1
  153. package/dist/types/src/types/types.d.ts +0 -9
  154. package/dist/types/src/types/types.d.ts.map +0 -1
  155. package/src/capabilities/file-uploader.ts +0 -34
  156. package/src/capabilities/markdown.ts +0 -34
  157. package/src/capabilities/operation-handler.ts +0 -16
  158. package/src/capabilities/react-surface.tsx +0 -54
  159. package/src/components/FileInput/FileInput.tsx +0 -47
  160. package/src/components/FileInput/index.ts +0 -5
  161. package/src/components/FilePreview/FilePreview.tsx +0 -43
  162. package/src/components/FilePreview/index.ts +0 -5
  163. package/src/components/index.ts +0 -6
  164. package/src/containers/FileContainer/FileContainer.tsx +0 -57
  165. package/src/containers/FileContainer/index.ts +0 -5
  166. package/src/containers/index.ts +0 -7
  167. package/src/extensions/image.stories.tsx +0 -103
  168. package/src/extensions/image.tsx +0 -204
  169. package/src/extensions/index.ts +0 -5
  170. package/src/operations/create-file.ts +0 -31
  171. package/src/operations/create.ts +0 -22
  172. package/src/operations/definitions.ts +0 -41
  173. package/src/operations/index.ts +0 -13
  174. package/src/operations/upload.ts +0 -29
  175. package/src/types/File.ts +0 -28
  176. package/src/types/capabilities.ts +0 -18
  177. package/src/types/types.ts +0 -24
  178. /package/dist/lib/{browser/types/index.mjs.map → neutral/chunk-J5LGTIGS.mjs.map} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-wnfs",
3
- "version": "0.8.4-main.fcfe5033a5",
3
+ "version": "0.8.4-staging.60fe92afc8",
4
4
  "description": "WNFS file management plugin",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -8,102 +8,115 @@
8
8
  "type": "git",
9
9
  "url": "https://github.com/dxos/dxos"
10
10
  },
11
- "license": "MIT",
11
+ "license": "FSL-1.1-Apache-2.0",
12
12
  "author": "DXOS.org",
13
+ "sideEffects": true,
13
14
  "type": "module",
14
15
  "imports": {
15
- "#capabilities": "./src/capabilities/index.ts",
16
- "#components": "./src/components/index.ts",
17
- "#containers": "./src/containers/index.ts",
18
- "#meta": "./src/meta.ts",
19
- "#operations": "./src/operations/index.ts",
20
- "#types": "./src/types/index.ts"
16
+ "#capabilities": {
17
+ "source": "./src/capabilities/index.ts",
18
+ "types": "./dist/types/src/capabilities/index.d.ts",
19
+ "default": "./dist/lib/neutral/capabilities/index.mjs"
20
+ },
21
+ "#helpers": {
22
+ "source": "./src/helpers/index.ts",
23
+ "types": "./dist/types/src/helpers/index.d.ts",
24
+ "default": "./dist/lib/neutral/helpers/index.mjs"
25
+ },
26
+ "#meta": {
27
+ "source": "./src/meta.ts",
28
+ "types": "./dist/types/src/meta.d.ts",
29
+ "default": "./dist/lib/neutral/meta.mjs"
30
+ },
31
+ "#plugin": {
32
+ "source": {
33
+ "workerd": "./src/WnfsPlugin.workerd.ts",
34
+ "node": "./src/WnfsPlugin.node.ts",
35
+ "default": "./src/WnfsPlugin.tsx"
36
+ },
37
+ "types": "./dist/types/src/WnfsPlugin.d.ts",
38
+ "workerd": "./dist/lib/neutral/WnfsPlugin.workerd.mjs",
39
+ "node": "./dist/lib/neutral/WnfsPlugin.node.mjs",
40
+ "default": "./dist/lib/neutral/WnfsPlugin.mjs"
41
+ },
42
+ "#translations": {
43
+ "source": "./src/translations.ts",
44
+ "types": "./dist/types/src/translations.d.ts",
45
+ "default": "./dist/lib/neutral/translations.mjs"
46
+ },
47
+ "#types": {
48
+ "source": "./src/types/index.ts",
49
+ "types": "./dist/types/src/types/index.d.ts",
50
+ "default": "./dist/lib/neutral/types/index.mjs"
51
+ }
21
52
  },
22
53
  "exports": {
23
54
  ".": {
24
55
  "source": "./src/index.ts",
25
- "browser": "./dist/lib/browser/index.mjs",
26
- "types": "./dist/types/src/index.d.ts"
56
+ "types": "./dist/types/src/index.d.ts",
57
+ "default": "./dist/lib/neutral/index.mjs"
27
58
  },
28
- "./operations": {
29
- "source": "./src/operations/index.ts",
30
- "browser": "./dist/lib/browser/operations/index.mjs",
31
- "types": "./dist/types/src/operations/index.d.ts"
59
+ "./assets/PLUGIN.mdl": "./PLUGIN.mdl",
60
+ "./plugin": {
61
+ "source": "./src/plugin.ts",
62
+ "types": "./dist/types/src/plugin.d.ts",
63
+ "default": "./dist/lib/neutral/plugin.mjs"
32
64
  },
33
- "./types": {
34
- "source": "./src/types/index.ts",
35
- "browser": "./dist/lib/browser/types/index.mjs",
36
- "types": "./dist/types/src/types/index.d.ts"
65
+ "./translations": {
66
+ "source": "./src/translations.ts",
67
+ "types": "./dist/types/src/translations.d.ts",
68
+ "default": "./dist/lib/neutral/translations.mjs"
37
69
  }
38
70
  },
39
71
  "types": "dist/types/src/index.d.ts",
40
- "typesVersions": {
41
- "*": {
42
- "types": [
43
- "dist/types/src/types/index.d.ts"
44
- ],
45
- "operations": [
46
- "dist/types/src/operations/index.d.ts"
47
- ]
48
- }
49
- },
50
72
  "files": [
51
73
  "dist",
52
- "src"
74
+ "src",
75
+ "PLUGIN.mdl"
53
76
  ],
54
77
  "dependencies": {
55
- "@codemirror/language": "^6.11.3",
56
- "@codemirror/state": "^6.5.2",
57
- "@codemirror/view": "^6.38.4",
58
78
  "@ipld/car": "^5.3.3",
59
79
  "blockstore-core": "^5.0.1",
60
80
  "blockstore-idb": "^2.0.0",
61
81
  "debounce": "^2.2.0",
62
- "effect": "3.20.0",
82
+ "effect": "3.21.3",
63
83
  "idb-keyval": "^6.2.1",
64
84
  "interface-blockstore": "^5.2.10",
65
85
  "it-all": "^3.0.6",
66
86
  "multiformats": "^13.2.2",
67
- "react-dropzone": "^14.2.3",
68
87
  "uint8arrays": "^5.1.0",
69
88
  "wnfs": "0.2.2",
70
- "@dxos/app-framework": "0.8.4-main.fcfe5033a5",
71
- "@dxos/app-toolkit": "0.8.4-main.fcfe5033a5",
72
- "@dxos/crypto": "0.8.4-main.fcfe5033a5",
73
- "@dxos/echo": "0.8.4-main.fcfe5033a5",
74
- "@dxos/effect": "0.8.4-main.fcfe5033a5",
75
- "@dxos/invariant": "0.8.4-main.fcfe5033a5",
76
- "@dxos/log": "0.8.4-main.fcfe5033a5",
77
- "@dxos/plugin-markdown": "0.8.4-main.fcfe5033a5",
78
- "@dxos/plugin-space": "0.8.4-main.fcfe5033a5",
79
- "@dxos/react-client": "0.8.4-main.fcfe5033a5",
80
- "@dxos/react-ui": "0.8.4-main.fcfe5033a5",
81
- "@dxos/operation": "0.8.4-main.fcfe5033a5",
82
- "@dxos/react-ui-editor": "0.8.4-main.fcfe5033a5",
83
- "@dxos/react-ui-form": "0.8.4-main.fcfe5033a5",
84
- "@dxos/react-ui-mosaic": "0.8.4-main.fcfe5033a5",
85
- "@dxos/react-ui-stack": "0.8.4-main.fcfe5033a5",
86
- "@dxos/ui-editor": "0.8.4-main.fcfe5033a5",
87
- "@dxos/schema": "0.8.4-main.fcfe5033a5",
88
- "@dxos/plugin-client": "0.8.4-main.fcfe5033a5",
89
- "@dxos/util": "0.8.4-main.fcfe5033a5"
89
+ "@dxos/app-framework": "0.8.4-staging.60fe92afc8",
90
+ "@dxos/app-toolkit": "0.8.4-staging.60fe92afc8",
91
+ "@dxos/crypto": "0.8.4-staging.60fe92afc8",
92
+ "@dxos/echo": "0.8.4-staging.60fe92afc8",
93
+ "@dxos/invariant": "0.8.4-staging.60fe92afc8",
94
+ "@dxos/log": "0.8.4-staging.60fe92afc8",
95
+ "@dxos/plugin-client": "0.8.4-staging.60fe92afc8",
96
+ "@dxos/keys": "0.8.4-staging.60fe92afc8",
97
+ "@dxos/plugin-file": "0.8.4-staging.60fe92afc8",
98
+ "@dxos/react-client": "0.8.4-staging.60fe92afc8",
99
+ "@dxos/react-ui": "0.8.4-staging.60fe92afc8",
100
+ "@dxos/util": "0.8.4-staging.60fe92afc8",
101
+ "@dxos/types": "0.8.4-staging.60fe92afc8"
90
102
  },
91
103
  "devDependencies": {
92
104
  "@types/react": "~19.2.7",
93
105
  "@types/react-dom": "~19.2.3",
94
106
  "react": "~19.2.3",
95
107
  "react-dom": "~19.2.3",
96
- "vite": "^7.1.11",
97
- "@dxos/random": "0.8.4-main.fcfe5033a5",
98
- "@dxos/storybook-utils": "0.8.4-main.fcfe5033a5",
99
- "@dxos/ui-theme": "0.8.4-main.fcfe5033a5"
108
+ "vite": "^8.0.16",
109
+ "@dxos/random": "0.8.4-staging.60fe92afc8",
110
+ "@dxos/ui-theme": "0.8.4-staging.60fe92afc8",
111
+ "@dxos/storybook-utils": "0.8.4-staging.60fe92afc8",
112
+ "@dxos/plugin-testing": "0.8.4-staging.60fe92afc8"
100
113
  },
101
114
  "peerDependencies": {
102
- "effect": "3.20.0",
115
+ "effect": "3.21.3",
103
116
  "react": "~19.2.3",
104
117
  "react-dom": "~19.2.3",
105
- "@dxos/react-ui": "0.8.4-main.fcfe5033a5",
106
- "@dxos/ui-theme": "0.8.4-main.fcfe5033a5"
118
+ "@dxos/react-ui": "0.8.4-staging.60fe92afc8",
119
+ "@dxos/ui-theme": "0.8.4-staging.60fe92afc8"
107
120
  },
108
121
  "publishConfig": {
109
122
  "access": "public"
@@ -0,0 +1,11 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { Plugin } from '@dxos/app-framework';
6
+
7
+ import { meta } from '#meta';
8
+
9
+ export const WnfsPlugin = Plugin.define(meta).pipe(Plugin.make);
10
+
11
+ export default WnfsPlugin;
@@ -0,0 +1,20 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { describe, test } from 'vitest';
6
+
7
+ import { ClientPlugin } from '@dxos/plugin-client/plugin';
8
+ import { createComposerTestApp } from '@dxos/plugin-testing/harness';
9
+
10
+ import { WnfsPlugin } from '#plugin';
11
+
12
+ describe('WnfsPlugin', () => {
13
+ test('activates without errors', async ({ expect }) => {
14
+ await using harness = await createComposerTestApp({
15
+ plugins: [ClientPlugin({}), WnfsPlugin()],
16
+ });
17
+
18
+ expect(harness.manager.getActive()).toBeInstanceOf(Array);
19
+ });
20
+ });
@@ -3,49 +3,20 @@
3
3
  //
4
4
 
5
5
  import * as Effect from 'effect/Effect';
6
- import * as Option from 'effect/Option';
7
6
 
8
7
  import { Capability, Plugin } from '@dxos/app-framework';
9
8
  import { AppPlugin } from '@dxos/app-toolkit';
10
- import { Annotation } from '@dxos/echo';
11
- import { Operation } from '@dxos/operation';
12
- import { ClientEvents } from '@dxos/plugin-client/types';
13
- import { MarkdownEvents } from '@dxos/plugin-markdown';
14
- import { SpaceOperation } from '@dxos/plugin-space/operations';
15
- import { type CreateObject } from '@dxos/plugin-space/types';
9
+ import { ClientEvents } from '@dxos/plugin-client';
16
10
 
17
- import { Blockstore, FileUploader, Markdown, OperationHandler, ReactSurface } from '#capabilities';
11
+ import { Backend, Blockstore, UrlResolver } from '#capabilities';
18
12
  import { meta } from '#meta';
19
- import { WnfsOperation } from '#operations';
20
- import { WnfsAction, WnfsCapabilities, WnfsFile } from '#types';
13
+ import { translations } from '#translations';
14
+ import { WnfsCapabilities } from '#types';
21
15
 
22
- import { translations } from './translations';
16
+ // eslint-disable-next-line import/no-relative-packages
17
+ import pluginSpec from '../PLUGIN.mdl?raw';
23
18
 
24
19
  export const WnfsPlugin = Plugin.define(meta).pipe(
25
- AppPlugin.addMetadataModule({
26
- metadata: {
27
- id: WnfsFile.File.typename,
28
- metadata: {
29
- // TODO(wittjosiah): Would be nice if icon could change based on the type of the file.
30
- icon: Annotation.IconAnnotation.get(WnfsFile.File).pipe(Option.getOrThrow).icon,
31
- iconHue: Annotation.IconAnnotation.get(WnfsFile.File).pipe(Option.getOrThrow).hue ?? 'white',
32
- inputSchema: WnfsAction.UploadFileSchema,
33
- createObject: ((props, options) =>
34
- Effect.gen(function* () {
35
- const { object } = yield* Operation.invoke(WnfsOperation.CreateFile, { ...props, db: options.db });
36
- return yield* Operation.invoke(SpaceOperation.AddObject, {
37
- object,
38
- target: options.target,
39
- hidden: true,
40
- targetNodeId: options.targetNodeId,
41
- });
42
- })) satisfies CreateObject,
43
- },
44
- },
45
- }),
46
- AppPlugin.addOperationHandlerModule({ activate: OperationHandler }),
47
- AppPlugin.addSchemaModule({ schema: [WnfsFile.File] }),
48
- AppPlugin.addSurfaceModule({ activate: ReactSurface }),
49
20
  AppPlugin.addTranslationsModule({ translations }),
50
21
  Plugin.addModule({
51
22
  id: 'blockstore',
@@ -62,14 +33,19 @@ export const WnfsPlugin = Plugin.define(meta).pipe(
62
33
  }),
63
34
  }),
64
35
  Plugin.addModule({
65
- id: 'file-uploader',
36
+ id: 'backend',
66
37
  activatesOn: ClientEvents.ClientReady,
67
- activate: FileUploader,
38
+ activate: Backend,
68
39
  }),
69
40
  Plugin.addModule({
70
- id: 'markdown',
71
- activatesOn: MarkdownEvents.SetupExtensions,
72
- activate: Markdown,
41
+ id: 'url-resolver',
42
+ activatesOn: ClientEvents.ClientReady,
43
+ activate: UrlResolver,
44
+ }),
45
+ AppPlugin.addPluginAssetModule({
46
+ asset: { pluginId: meta.id, path: 'PLUGIN.mdl', content: pluginSpec, mimeType: 'application/x-mdl' },
73
47
  }),
74
48
  Plugin.make,
75
49
  );
50
+
51
+ export default WnfsPlugin;
@@ -0,0 +1,11 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { Plugin } from '@dxos/app-framework';
6
+
7
+ import { meta } from '#meta';
8
+
9
+ export const WnfsPlugin = Plugin.define(meta).pipe(Plugin.make);
10
+
11
+ export default WnfsPlugin;
@@ -0,0 +1,16 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+
7
+ import { Annotation } from '@dxos/echo';
8
+
9
+ /** WNFS filesystem state stored on space properties meta. */
10
+ export const WnfsStateAnnotation = Annotation.make({
11
+ id: 'org.dxos.plugin.wnfs.state',
12
+ schema: Schema.Struct({
13
+ accessKey: Schema.String,
14
+ privateForestCid: Schema.String,
15
+ }),
16
+ });
@@ -0,0 +1,43 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { Capability } from '@dxos/app-framework';
8
+ import { invariant } from '@dxos/invariant';
9
+ import { ClientCapabilities } from '@dxos/plugin-client';
10
+ import { FileCapabilities } from '@dxos/plugin-file/types';
11
+ import { File } from '@dxos/types';
12
+
13
+ import { WnfsCapabilities } from '#types';
14
+
15
+ import { upload } from '../helpers';
16
+
17
+ export const WNFS_BACKEND_ID = 'wnfs';
18
+
19
+ export default Capability.makeModule(
20
+ Effect.fnUntraced(function* () {
21
+ const capabilities = yield* Capability.Service;
22
+
23
+ return Capability.contributes(FileCapabilities.Backend, {
24
+ id: WNFS_BACKEND_ID,
25
+ name: 'WNFS',
26
+ description: 'Decentralized, end-to-end encrypted storage via Web Native File System.',
27
+ upload: async (file, db) => {
28
+ const client = capabilities.get(ClientCapabilities.Client);
29
+ const blockstore = capabilities.get(WnfsCapabilities.Blockstore);
30
+ const instances = capabilities.get(WnfsCapabilities.Instances);
31
+ const space = client.spaces.get(db.spaceId);
32
+ invariant(space, 'Space not found');
33
+ const info = await upload({ file, blockstore, instances, space });
34
+ return {
35
+ name: info.name,
36
+ type: info.type,
37
+ size: file.size,
38
+ data: File.externalData(info.url, info.cid),
39
+ };
40
+ },
41
+ });
42
+ }),
43
+ );
@@ -5,7 +5,7 @@
5
5
  import * as Effect from 'effect/Effect';
6
6
 
7
7
  import { Capability } from '@dxos/app-framework';
8
- import { ClientCapabilities } from '@dxos/plugin-client/types';
8
+ import { ClientCapabilities } from '@dxos/plugin-client';
9
9
 
10
10
  import { WnfsCapabilities } from '#types';
11
11
 
@@ -3,13 +3,16 @@
3
3
  //
4
4
 
5
5
  import { Capability } from '@dxos/app-framework';
6
- import { OperationHandlerSet } from '@dxos/operation';
6
+ import { type FileCapabilities } from '@dxos/plugin-file/types';
7
+
8
+ export const Backend: Capability.LazyCapability<
9
+ void,
10
+ Capability.Capability<Capability.InterfaceDef<FileCapabilities.Backend>>
11
+ > = Capability.lazy('Backend', () => import('./backend'));
7
12
 
8
13
  export const Blockstore = Capability.lazy('Blockstore', () => import('./blockstore'));
9
- export const FileUploader = Capability.lazy('FileUploader', () => import('./file-uploader'));
10
- export const Markdown = Capability.lazy('Markdown', () => import('./markdown'));
11
- export const OperationHandler = Capability.lazy<OperationHandlerSet.OperationHandlerSet>(
12
- 'OperationHandler',
13
- () => import('./operation-handler'),
14
- );
15
- export const ReactSurface = Capability.lazy('ReactSurface', () => import('./react-surface'));
14
+
15
+ export const UrlResolver: Capability.LazyCapability<
16
+ void,
17
+ Capability.Capability<Capability.InterfaceDef<FileCapabilities.UrlResolver>>
18
+ > = Capability.lazy('UrlResolver', () => import('./url-resolver'));
@@ -0,0 +1,44 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { Capability } from '@dxos/app-framework';
8
+ import { FileCapabilities } from '@dxos/plugin-file/types';
9
+
10
+ import { WnfsCapabilities } from '#types';
11
+
12
+ import { getBlobUrl, loadWnfs } from '../helpers';
13
+
14
+ export const WNFS_URL_RESOLVER_ID = 'wnfs';
15
+
16
+ export default Capability.makeModule(
17
+ Effect.fnUntraced(function* () {
18
+ const capabilities = yield* Capability.Service;
19
+
20
+ return Capability.contributes(FileCapabilities.UrlResolver, {
21
+ id: WNFS_URL_RESOLVER_ID,
22
+ test: (url) => url.startsWith('wnfs://'),
23
+ resolve: async (wnfsUrl, file, space) => {
24
+ if (!space) {
25
+ return undefined;
26
+ }
27
+ try {
28
+ const blockstore = capabilities.get(WnfsCapabilities.Blockstore);
29
+ const instances = capabilities.get(WnfsCapabilities.Instances);
30
+ const { directory, forest } = await loadWnfs({ blockstore, instances, space });
31
+ return await getBlobUrl({
32
+ wnfsUrl,
33
+ blockstore,
34
+ directory,
35
+ forest,
36
+ type: file.type,
37
+ });
38
+ } catch {
39
+ return undefined;
40
+ }
41
+ },
42
+ });
43
+ }),
44
+ );
@@ -2,16 +2,18 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ import * as Option from 'effect/Option';
5
6
  import type { Blockstore } from 'interface-blockstore';
6
7
  import { CID } from 'multiformats';
7
8
  import * as Uint8Arrays from 'uint8arrays';
8
9
  import { AccessKey, PrivateDirectory, PrivateForest, PrivateNode } from 'wnfs';
9
10
 
10
- import { Obj } from '@dxos/echo';
11
+ import { Annotation, Obj } from '@dxos/echo';
11
12
  import { type Space } from '@dxos/react-client/echo';
12
13
 
13
14
  import { type WnfsCapabilities } from '#types';
14
15
 
16
+ import { WnfsStateAnnotation } from '../annotations';
15
17
  import { Rng, store } from './common';
16
18
 
17
19
  //
@@ -28,23 +30,37 @@ export const loadWnfs = async ({
28
30
  instances?: WnfsCapabilities.Instances;
29
31
  }) => {
30
32
  // TODO(wittjosiah): Remove.
31
- // Delete old properties if they exist.
32
- if (space.properties.wnfs_access_key !== undefined && space.properties.wnfs_private_forest_cid !== undefined) {
33
- Obj.change(space.properties, (obj) => {
34
- delete obj['wnfs_access_key'];
35
- delete obj['wnfs_private_forest_cid'];
33
+ // Delete old properties if they exist (pre-DX-971 migration cleanup).
34
+ const propsAny = space.properties as any;
35
+ if (propsAny.wnfs_access_key !== undefined && propsAny.wnfs_private_forest_cid !== undefined) {
36
+ Obj.update(space.properties, (obj) => {
37
+ delete (obj as any)['wnfs_access_key'];
38
+ delete (obj as any)['wnfs_private_forest_cid'];
39
+ });
40
+ }
41
+ // Migrate legacy wnfs data key to annotation.
42
+ if (propsAny.wnfs !== undefined && Option.isNone(Annotation.get(space.properties, WnfsStateAnnotation))) {
43
+ Obj.update(space.properties, (properties) => {
44
+ Annotation.set(properties, WnfsStateAnnotation, propsAny.wnfs);
45
+ delete (properties as any)['wnfs'];
36
46
  });
37
47
  }
38
48
 
39
- const cacheKey = space.properties.wnfs?.privateForestCid;
40
- if (instances?.[cacheKey]) {
49
+ const wnfsState = Annotation.get(space.properties, WnfsStateAnnotation).pipe(Option.getOrUndefined);
50
+ const cacheKey = wnfsState?.privateForestCid as any;
51
+ if (cacheKey && instances?.[cacheKey]) {
41
52
  return instances[cacheKey];
42
53
  }
43
54
 
44
- const exists = !!space.properties.wnfs;
55
+ const exists = !!wnfsState;
45
56
  const instance = exists ? await loadWnfsDir(blockstore, space) : await createWnfsDir(blockstore, space);
46
57
  if (instances) {
47
- instances[cacheKey] = instance;
58
+ // Re-read after createWnfsDir so newly created instances are cached under the real CID.
59
+ const newCacheKey = Annotation.get(space.properties, WnfsStateAnnotation).pipe(Option.getOrUndefined)
60
+ ?.privateForestCid as any;
61
+ if (newCacheKey) {
62
+ instances[newCacheKey] = instance;
63
+ }
48
64
  }
49
65
 
50
66
  return instance;
@@ -68,11 +84,11 @@ const createWnfsDir = async (blockstore: Blockstore, space: Space) => {
68
84
 
69
85
  const cidBytes = await newForest.store(wnfsStore);
70
86
 
71
- Obj.change(space.properties, (obj) => {
72
- obj.wnfs = {
87
+ Obj.update(space.properties, (properties) => {
88
+ Annotation.set(properties, WnfsStateAnnotation, {
73
89
  accessKey: Uint8Arrays.toString(accessKeyRaw.toBytes(), 'base64'),
74
90
  privateForestCid: CID.decode(cidBytes).toString(),
75
- };
91
+ });
76
92
  });
77
93
 
78
94
  return {
@@ -84,11 +100,9 @@ const createWnfsDir = async (blockstore: Blockstore, space: Space) => {
84
100
  const loadWnfsDir = async (blockstore: Blockstore, space: Space) => {
85
101
  const wnfsStore = store(blockstore);
86
102
 
87
- const accessKey = AccessKey.fromBytes(Uint8Arrays.fromString(space.properties.wnfs.accessKey, 'base64'));
88
- const forest: PrivateForest = await PrivateForest.load(
89
- CID.parse(space.properties.wnfs.privateForestCid).bytes,
90
- wnfsStore,
91
- );
103
+ const wnfsState = Annotation.get(space.properties, WnfsStateAnnotation).pipe(Option.getOrUndefined)!;
104
+ const accessKey = AccessKey.fromBytes(Uint8Arrays.fromString(wnfsState.accessKey, 'base64'));
105
+ const forest: PrivateForest = await PrivateForest.load(CID.parse(wnfsState.privateForestCid).bytes, wnfsStore);
92
106
  const node: PrivateNode = await PrivateNode.load(accessKey, forest, wnfsStore);
93
107
 
94
108
  return {
@@ -2,17 +2,19 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ import * as Option from 'effect/Option';
5
6
  import type { Blockstore } from 'interface-blockstore';
6
7
  import { CID } from 'multiformats';
7
8
  import * as Raw from 'multiformats/codecs/raw';
8
9
  import { sha256 } from 'multiformats/hashes/sha2';
9
10
 
10
11
  import type { Space } from '@dxos/client/echo';
11
- import { Obj } from '@dxos/echo';
12
+ import { Annotation, Obj } from '@dxos/echo';
12
13
  import { log } from '@dxos/log';
13
14
 
14
15
  import { type WnfsCapabilities } from '#types';
15
16
 
17
+ import { WnfsStateAnnotation } from '../annotations';
16
18
  import { Rng, filePath, store } from './common';
17
19
  import { loadWnfs } from './load';
18
20
  import { wnfsUrl } from './wnfs-url';
@@ -47,8 +49,15 @@ export const upload = async ({
47
49
  const cidBytes = await updatedForest.store(wnfsStore);
48
50
 
49
51
  // Update the forest pointer on the associated space.
50
- Obj.change(space.properties, (obj) => {
51
- obj.wnfs.privateForestCid = CID.decode(cidBytes).toString();
52
+ const currentState = Annotation.get(space.properties, WnfsStateAnnotation).pipe(Option.getOrUndefined);
53
+ if (!currentState) {
54
+ throw new Error('WnfsStateAnnotation missing after loadWnfs; cannot persist forest CID.');
55
+ }
56
+ Obj.update(space.properties, (properties) => {
57
+ Annotation.set(properties, WnfsStateAnnotation, {
58
+ ...currentState,
59
+ privateForestCid: CID.decode(cidBytes).toString(),
60
+ });
52
61
  });
53
62
 
54
63
  // Generate `wnfs://` URL & return the info.
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- export { WnfsCapabilities } from './types';
5
+ export * from './annotations';
6
+ export * from './helpers';
6
7
  export * from './meta';
7
- export * from './WnfsPlugin';
8
+ export * from './types';
package/src/meta.ts CHANGED
@@ -2,17 +2,33 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type Plugin } from '@dxos/app-framework';
5
+ import { Plugin } from '@dxos/app-framework';
6
+ import { DXN } from '@dxos/keys';
7
+ import { meta as fileMeta } from '@dxos/plugin-file';
6
8
  import { trim } from '@dxos/util';
7
9
 
8
- export const meta: Plugin.Meta = {
9
- id: 'org.dxos.plugin.wnfs',
10
+ export const meta = Plugin.makeMeta({
11
+ key: DXN.make('org.dxos.plugin.wnfs'),
10
12
  name: 'WNFS',
13
+ author: 'DXOS',
11
14
  description: trim`
12
- Decentralized file storage using the Web Native File System protocol.
13
- Store and sync files with end-to-end encryption across devices without central servers.
15
+ Decentralized, end-to-end encrypted file storage for DXOS Composer built on the Web Native File System (WNFS) protocol.
16
+
17
+ WNFS organizes files inside a cryptographic "dark forest" — a content-addressed private file system
18
+ where each write produces a new immutable root CID. Files are stored as IPLD blocks (CIDv1, sha2-256),
19
+ cached locally in IndexedDB, and asynchronously replicated to the DXOS edge blob service as CAR archives.
20
+ Uploads and reads are scoped to a DXOS Space; the forest root CID is persisted atomically on the
21
+ space's ECHO properties so the file system state survives across sessions and devices.
22
+
23
+ The plugin registers as a \`FileCapabilities.Backend\` and \`FileCapabilities.UrlResolver\` so any plugin
24
+ that uses \`plugin-file\` (e.g. \`plugin-gallery\`) can upload files and resolve \`wnfs://\` URLs without
25
+ coupling to the storage implementation. The blockstore automatically queues blocks while offline and
26
+ flushes them when connectivity is restored.
14
27
  `,
15
28
  icon: 'ph--file-cloud--regular',
16
29
  iconHue: 'teal',
17
30
  source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-wnfs',
18
- };
31
+ spec: 'PLUGIN.mdl',
32
+ tags: ['labs'],
33
+ dependsOn: [fileMeta.id],
34
+ });
package/src/plugin.ts ADDED
@@ -0,0 +1,9 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { Plugin } from '@dxos/app-framework';
6
+
7
+ import { meta } from './meta';
8
+
9
+ export const WnfsPlugin = Plugin.lazy(meta, () => import('#plugin'));