@dxos/plugin-wnfs 0.8.4-main.c4373fc → 0.8.4-main.d9fc60f731

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 (163) 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-D6VTEQIE.mjs → neutral/chunk-L33MOD23.mjs} +85 -25
  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 +3 -1
  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 +3 -2
  52. package/dist/types/src/capabilities/blockstore.d.ts.map +1 -1
  53. package/dist/types/src/capabilities/index.d.ts +5 -6
  54. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  55. package/dist/types/src/capabilities/url-resolver.d.ts +7 -0
  56. package/dist/types/src/capabilities/url-resolver.d.ts.map +1 -0
  57. package/dist/types/src/helpers/common.d.ts.map +1 -1
  58. package/dist/types/src/helpers/load.d.ts +1 -1
  59. package/dist/types/src/helpers/load.d.ts.map +1 -1
  60. package/dist/types/src/helpers/upload.d.ts +1 -1
  61. package/dist/types/src/helpers/upload.d.ts.map +1 -1
  62. package/dist/types/src/helpers/wnfs-url.d.ts.map +1 -1
  63. package/dist/types/src/index.d.ts +3 -2
  64. package/dist/types/src/index.d.ts.map +1 -1
  65. package/dist/types/src/meta.d.ts +2 -2
  66. package/dist/types/src/meta.d.ts.map +1 -1
  67. package/dist/types/src/plugin.d.ts +3 -0
  68. package/dist/types/src/plugin.d.ts.map +1 -0
  69. package/dist/types/src/translations.d.ts +2 -12
  70. package/dist/types/src/translations.d.ts.map +1 -1
  71. package/dist/types/src/types/WnfsCapabilities.d.ts +11 -0
  72. package/dist/types/src/types/WnfsCapabilities.d.ts.map +1 -0
  73. package/dist/types/src/types/index.d.ts +1 -2
  74. package/dist/types/src/types/index.d.ts.map +1 -1
  75. package/dist/types/tsconfig.tsbuildinfo +1 -1
  76. package/package.json +86 -50
  77. package/src/WnfsPlugin.node.ts +11 -0
  78. package/src/WnfsPlugin.test.ts +20 -0
  79. package/src/WnfsPlugin.tsx +32 -76
  80. package/src/WnfsPlugin.workerd.ts +11 -0
  81. package/src/annotations.ts +16 -0
  82. package/src/blockstore.ts +1 -1
  83. package/src/capabilities/backend.ts +43 -0
  84. package/src/capabilities/blockstore.ts +14 -10
  85. package/src/capabilities/index.ts +12 -7
  86. package/src/capabilities/url-resolver.ts +44 -0
  87. package/src/helpers/load.ts +37 -18
  88. package/src/helpers/upload.ts +14 -2
  89. package/src/index.ts +3 -2
  90. package/src/meta.ts +26 -5
  91. package/src/plugin.ts +9 -0
  92. package/src/translations.ts +2 -11
  93. package/src/types/WnfsCapabilities.ts +18 -0
  94. package/src/types/index.ts +1 -2
  95. package/src/vite-env.d.ts +10 -0
  96. package/dist/lib/browser/FileContainer-A4OJVMVS.mjs +0 -103
  97. package/dist/lib/browser/FileContainer-A4OJVMVS.mjs.map +0 -7
  98. package/dist/lib/browser/blockstore-HK4IYHJJ.mjs +0 -273
  99. package/dist/lib/browser/blockstore-HK4IYHJJ.mjs.map +0 -7
  100. package/dist/lib/browser/chunk-D6VTEQIE.mjs.map +0 -7
  101. package/dist/lib/browser/chunk-FYRZOKHG.mjs +0 -13
  102. package/dist/lib/browser/chunk-FYRZOKHG.mjs.map +0 -7
  103. package/dist/lib/browser/chunk-PAIK4SJ3.mjs +0 -16
  104. package/dist/lib/browser/chunk-PAIK4SJ3.mjs.map +0 -7
  105. package/dist/lib/browser/chunk-QQB5IBX7.mjs +0 -64
  106. package/dist/lib/browser/chunk-QQB5IBX7.mjs.map +0 -7
  107. package/dist/lib/browser/chunk-Y5JMTQ74.mjs +0 -16
  108. package/dist/lib/browser/chunk-Y5JMTQ74.mjs.map +0 -7
  109. package/dist/lib/browser/file-uploader-5S37ZZCW.mjs +0 -30
  110. package/dist/lib/browser/file-uploader-5S37ZZCW.mjs.map +0 -7
  111. package/dist/lib/browser/index.mjs +0 -116
  112. package/dist/lib/browser/index.mjs.map +0 -7
  113. package/dist/lib/browser/intent-resolver-3KMIEDBO.mjs +0 -49
  114. package/dist/lib/browser/intent-resolver-3KMIEDBO.mjs.map +0 -7
  115. package/dist/lib/browser/markdown-5XD3I2NQ.mjs +0 -209
  116. package/dist/lib/browser/markdown-5XD3I2NQ.mjs.map +0 -7
  117. package/dist/lib/browser/meta.json +0 -1
  118. package/dist/lib/browser/react-surface-5D7M3Y4W.mjs +0 -88
  119. package/dist/lib/browser/react-surface-5D7M3Y4W.mjs.map +0 -7
  120. package/dist/lib/browser/types/index.mjs +0 -10
  121. package/dist/types/src/capabilities/capabilities.d.ts +0 -12
  122. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  123. package/dist/types/src/capabilities/file-uploader.d.ts +0 -4
  124. package/dist/types/src/capabilities/file-uploader.d.ts.map +0 -1
  125. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  126. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  127. package/dist/types/src/capabilities/markdown.d.ts +0 -4
  128. package/dist/types/src/capabilities/markdown.d.ts.map +0 -1
  129. package/dist/types/src/capabilities/react-surface.d.ts +0 -4
  130. package/dist/types/src/capabilities/react-surface.d.ts.map +0 -1
  131. package/dist/types/src/components/FileContainer.d.ts +0 -9
  132. package/dist/types/src/components/FileContainer.d.ts.map +0 -1
  133. package/dist/types/src/components/FileInput.d.ts +0 -8
  134. package/dist/types/src/components/FileInput.d.ts.map +0 -1
  135. package/dist/types/src/components/FilePreview.d.ts +0 -11
  136. package/dist/types/src/components/FilePreview.d.ts.map +0 -1
  137. package/dist/types/src/components/index.d.ts +0 -3
  138. package/dist/types/src/components/index.d.ts.map +0 -1
  139. package/dist/types/src/extensions/image.d.ts +0 -14
  140. package/dist/types/src/extensions/image.d.ts.map +0 -1
  141. package/dist/types/src/extensions/image.stories.d.ts +0 -11
  142. package/dist/types/src/extensions/image.stories.d.ts.map +0 -1
  143. package/dist/types/src/extensions/index.d.ts +0 -2
  144. package/dist/types/src/extensions/index.d.ts.map +0 -1
  145. package/dist/types/src/types/file.d.ts +0 -16
  146. package/dist/types/src/types/file.d.ts.map +0 -1
  147. package/dist/types/src/types/types.d.ts +0 -51
  148. package/dist/types/src/types/types.d.ts.map +0 -1
  149. package/src/capabilities/capabilities.ts +0 -18
  150. package/src/capabilities/file-uploader.ts +0 -27
  151. package/src/capabilities/intent-resolver.ts +0 -33
  152. package/src/capabilities/markdown.ts +0 -26
  153. package/src/capabilities/react-surface.tsx +0 -45
  154. package/src/components/FileContainer.tsx +0 -49
  155. package/src/components/FileInput.tsx +0 -47
  156. package/src/components/FilePreview.tsx +0 -23
  157. package/src/components/index.ts +0 -9
  158. package/src/extensions/image.stories.tsx +0 -104
  159. package/src/extensions/image.tsx +0 -203
  160. package/src/extensions/index.ts +0 -5
  161. package/src/types/file.ts +0 -17
  162. package/src/types/types.ts +0 -41
  163. /package/dist/lib/{browser/types/index.mjs.map → neutral/chunk-J5LGTIGS.mjs.map} +0 -0
package/package.json CHANGED
@@ -1,86 +1,122 @@
1
1
  {
2
2
  "name": "@dxos/plugin-wnfs",
3
- "version": "0.8.4-main.c4373fc",
3
+ "version": "0.8.4-main.d9fc60f731",
4
4
  "description": "WNFS file management plugin",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
7
- "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/dxos/dxos"
10
+ },
11
+ "license": "FSL-1.1-Apache-2.0",
8
12
  "author": "DXOS.org",
13
+ "sideEffects": true,
9
14
  "type": "module",
15
+ "imports": {
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
+ }
52
+ },
10
53
  "exports": {
11
54
  ".": {
12
55
  "source": "./src/index.ts",
13
56
  "types": "./dist/types/src/index.d.ts",
14
- "browser": "./dist/lib/browser/index.mjs"
57
+ "default": "./dist/lib/neutral/index.mjs"
15
58
  },
16
- "./types": {
17
- "source": "./src/types/index.ts",
18
- "types": "./dist/types/src/types/index.d.ts",
19
- "browser": "./dist/lib/browser/types/index.mjs"
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"
64
+ },
65
+ "./translations": {
66
+ "source": "./src/translations.ts",
67
+ "types": "./dist/types/src/translations.d.ts",
68
+ "default": "./dist/lib/neutral/translations.mjs"
20
69
  }
21
70
  },
22
71
  "types": "dist/types/src/index.d.ts",
23
- "typesVersions": {
24
- "*": {
25
- "types": [
26
- "dist/types/src/types/index.d.ts"
27
- ]
28
- }
29
- },
30
72
  "files": [
31
73
  "dist",
32
- "src"
74
+ "src",
75
+ "PLUGIN.mdl"
33
76
  ],
34
77
  "dependencies": {
35
- "@codemirror/language": "^6.11.3",
36
- "@codemirror/state": "^6.5.2",
37
- "@codemirror/view": "^6.38.4",
38
78
  "@ipld/car": "^5.3.3",
39
- "@preact-signals/safe-react": "^0.9.0",
40
79
  "blockstore-core": "^5.0.1",
41
80
  "blockstore-idb": "^2.0.0",
42
81
  "debounce": "^2.2.0",
43
- "effect": "3.18.3",
82
+ "effect": "3.21.2",
44
83
  "idb-keyval": "^6.2.1",
45
84
  "interface-blockstore": "^5.2.10",
46
85
  "it-all": "^3.0.6",
47
86
  "multiformats": "^13.2.2",
48
- "react-dropzone": "^14.2.3",
49
87
  "uint8arrays": "^5.1.0",
50
88
  "wnfs": "0.2.2",
51
- "@dxos/app-framework": "0.8.4-main.c4373fc",
52
- "@dxos/crypto": "0.8.4-main.c4373fc",
53
- "@dxos/echo": "0.8.4-main.c4373fc",
54
- "@dxos/effect": "0.8.4-main.c4373fc",
55
- "@dxos/invariant": "0.8.4-main.c4373fc",
56
- "@dxos/log": "0.8.4-main.c4373fc",
57
- "@dxos/local-storage": "0.8.4-main.c4373fc",
58
- "@dxos/plugin-client": "0.8.4-main.c4373fc",
59
- "@dxos/plugin-space": "0.8.4-main.c4373fc",
60
- "@dxos/plugin-markdown": "0.8.4-main.c4373fc",
61
- "@dxos/react-ui-editor": "0.8.4-main.c4373fc",
62
- "@dxos/react-ui-form": "0.8.4-main.c4373fc",
63
- "@dxos/react-ui": "0.8.4-main.c4373fc",
64
- "@dxos/react-ui-stack": "0.8.4-main.c4373fc",
65
- "@dxos/util": "0.8.4-main.c4373fc",
66
- "@dxos/react-client": "0.8.4-main.c4373fc"
89
+ "@dxos/app-toolkit": "0.8.4-main.d9fc60f731",
90
+ "@dxos/app-framework": "0.8.4-main.d9fc60f731",
91
+ "@dxos/crypto": "0.8.4-main.d9fc60f731",
92
+ "@dxos/echo": "0.8.4-main.d9fc60f731",
93
+ "@dxos/invariant": "0.8.4-main.d9fc60f731",
94
+ "@dxos/keys": "0.8.4-main.d9fc60f731",
95
+ "@dxos/log": "0.8.4-main.d9fc60f731",
96
+ "@dxos/plugin-file": "0.8.4-main.d9fc60f731",
97
+ "@dxos/plugin-client": "0.8.4-main.d9fc60f731",
98
+ "@dxos/react-client": "0.8.4-main.d9fc60f731",
99
+ "@dxos/react-ui": "0.8.4-main.d9fc60f731",
100
+ "@dxos/types": "0.8.4-main.d9fc60f731",
101
+ "@dxos/util": "0.8.4-main.d9fc60f731"
67
102
  },
68
103
  "devDependencies": {
69
- "@types/react": "~19.2.2",
70
- "@types/react-dom": "~19.2.1",
71
- "react": "~19.2.0",
72
- "react-dom": "~19.2.0",
73
- "vite": "7.1.9",
74
- "@dxos/random": "0.8.4-main.c4373fc",
75
- "@dxos/react-ui-theme": "0.8.4-main.c4373fc",
76
- "@dxos/storybook-utils": "0.8.4-main.c4373fc"
104
+ "@types/react": "~19.2.7",
105
+ "@types/react-dom": "~19.2.3",
106
+ "react": "~19.2.3",
107
+ "react-dom": "~19.2.3",
108
+ "vite": "^8.0.14",
109
+ "@dxos/plugin-testing": "0.8.4-main.d9fc60f731",
110
+ "@dxos/random": "0.8.4-main.d9fc60f731",
111
+ "@dxos/storybook-utils": "0.8.4-main.d9fc60f731",
112
+ "@dxos/ui-theme": "0.8.4-main.d9fc60f731"
77
113
  },
78
114
  "peerDependencies": {
79
- "effect": "^3.13.3",
80
- "react": "^19.0.0",
81
- "react-dom": "^19.0.0",
82
- "@dxos/react-ui": "0.8.4-main.c4373fc",
83
- "@dxos/react-ui-theme": "0.8.4-main.c4373fc"
115
+ "effect": "3.21.2",
116
+ "react": "~19.2.3",
117
+ "react-dom": "~19.2.3",
118
+ "@dxos/react-ui": "0.8.4-main.d9fc60f731",
119
+ "@dxos/ui-theme": "0.8.4-main.d9fc60f731"
84
120
  },
85
121
  "publishConfig": {
86
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
+ });
@@ -2,94 +2,50 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import * as Function from 'effect/Function';
5
+ import * as Effect from 'effect/Effect';
6
6
 
7
- import {
8
- Capabilities,
9
- Events,
10
- chain,
11
- contributes,
12
- createIntent,
13
- defineModule,
14
- definePlugin,
15
- } from '@dxos/app-framework';
7
+ import { Capability, Plugin } from '@dxos/app-framework';
8
+ import { AppPlugin } from '@dxos/app-toolkit';
16
9
  import { ClientEvents } from '@dxos/plugin-client';
17
- import { MarkdownEvents } from '@dxos/plugin-markdown';
18
- import { SpaceCapabilities } from '@dxos/plugin-space';
19
- import { defineObjectForm } from '@dxos/plugin-space/types';
20
10
 
21
- import { Blockstore, FileUploader, IntentResolver, Markdown, ReactSurface, WnfsCapabilities } from './capabilities';
22
- import { meta } from './meta';
23
- import { translations } from './translations';
24
- import { FileType, WnfsAction } from './types';
11
+ import { Backend, Blockstore, UrlResolver } from '#capabilities';
12
+ import { meta } from '#meta';
13
+ import { translations } from '#translations';
14
+ import { WnfsCapabilities } from '#types';
25
15
 
26
- export const WnfsPlugin = definePlugin(meta, () => [
27
- defineModule({
28
- id: `${meta.id}/module/blockstore`,
16
+ // eslint-disable-next-line import/no-relative-packages
17
+ import pluginSpec from '../PLUGIN.mdl?raw';
18
+
19
+ export const WnfsPlugin = Plugin.define(meta).pipe(
20
+ AppPlugin.addTranslationsModule({ translations }),
21
+ Plugin.addModule({
22
+ id: 'blockstore',
29
23
  activatesOn: ClientEvents.ClientReady,
30
24
  activate: Blockstore,
31
25
  }),
32
- defineModule({
33
- id: `${meta.id}/module/instances`,
26
+ Plugin.addModule({
27
+ id: 'instances',
34
28
  activatesOn: ClientEvents.ClientReady,
35
- activate: () => {
36
- const instances: WnfsCapabilities.Instances = {};
37
- return contributes(WnfsCapabilities.Instances, instances);
38
- },
39
- }),
40
- defineModule({
41
- id: `${meta.id}/module/translations`,
42
- activatesOn: Events.SetupTranslations,
43
- activate: () => contributes(Capabilities.Translations, translations),
44
- }),
45
- defineModule({
46
- id: `${meta.id}/module/metadata`,
47
- activatesOn: Events.SetupMetadata,
48
29
  activate: () =>
49
- contributes(Capabilities.Metadata, {
50
- id: FileType.typename,
51
- metadata: {
52
- label: (object: any) => (object instanceof FileType ? object.name : undefined),
53
- // TODO(wittjosiah): Would be nice if icon could change based on the type of the file.
54
- icon: 'ph--file--regular',
55
- },
30
+ Effect.sync(() => {
31
+ const instances: WnfsCapabilities.Instances = {};
32
+ return Capability.contributes(WnfsCapabilities.Instances, instances);
56
33
  }),
57
34
  }),
58
- defineModule({
59
- id: `${meta.id}/module/object-form`,
60
- activatesOn: ClientEvents.SetupSchema,
61
- activate: () =>
62
- contributes(
63
- SpaceCapabilities.ObjectForm,
64
- defineObjectForm({
65
- objectSchema: FileType,
66
- formSchema: WnfsAction.UploadFileSchema,
67
- getIntent: (props, options) =>
68
- Function.pipe(
69
- createIntent(WnfsAction.Upload, { ...props, space: options.space }),
70
- chain(WnfsAction.Create, {}),
71
- ),
72
- }),
73
- ),
74
- }),
75
- defineModule({
76
- id: `${meta.id}/module/file-uploader`,
35
+ Plugin.addModule({
36
+ id: 'backend',
77
37
  activatesOn: ClientEvents.ClientReady,
78
- activate: FileUploader,
79
- }),
80
- defineModule({
81
- id: `${meta.id}/module/markdown`,
82
- activatesOn: MarkdownEvents.SetupExtensions,
83
- activate: Markdown,
38
+ activate: Backend,
84
39
  }),
85
- defineModule({
86
- id: `${meta.id}/module/react-surface`,
87
- activatesOn: Events.SetupReactSurface,
88
- activate: ReactSurface,
40
+ Plugin.addModule({
41
+ id: 'url-resolver',
42
+ activatesOn: ClientEvents.ClientReady,
43
+ activate: UrlResolver,
89
44
  }),
90
- defineModule({
91
- id: `${meta.id}/module/intent-resolver`,
92
- activatesOn: Events.SetupIntentResolver,
93
- activate: IntentResolver,
45
+ AppPlugin.addPluginAssetModule({
46
+ asset: { pluginId: meta.id, path: 'PLUGIN.mdl', content: pluginSpec, mimeType: 'application/x-mdl' },
94
47
  }),
95
- ]);
48
+ Plugin.make,
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
+ });
package/src/blockstore.ts CHANGED
@@ -145,7 +145,7 @@ export class MixedBlockstore extends BaseBlockstore {
145
145
 
146
146
  // QUEUE
147
147
 
148
- readonly queueCacheName = `${storeName()}/state/queue`;
148
+ readonly queueCacheName = `${storeName()}.state.queue`;
149
149
 
150
150
  async #addToQueue(key: CID): Promise<void> {
151
151
  await this.#saveQueue([...this.#queue, key.toString()]);
@@ -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
+ );
@@ -2,18 +2,22 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type PluginContext, contributes } from '@dxos/app-framework';
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { Capability } from '@dxos/app-framework';
6
8
  import { ClientCapabilities } from '@dxos/plugin-client';
7
9
 
8
- import * as Blockstore from '../blockstore';
10
+ import { WnfsCapabilities } from '#types';
9
11
 
10
- import { WnfsCapabilities } from './capabilities';
12
+ import * as Blockstore from '../blockstore';
11
13
 
12
- export default async (context: PluginContext) => {
13
- const client = context.getCapability(ClientCapabilities.Client);
14
- const apiHost = client.config.values.runtime?.services?.edge?.url || 'http://localhost:8787';
15
- const blockstore = Blockstore.create(apiHost);
16
- await blockstore.open();
14
+ export default Capability.makeModule(
15
+ Effect.fnUntraced(function* () {
16
+ const client = yield* Capability.get(ClientCapabilities.Client);
17
+ const apiHost = client.config.values.runtime?.services?.edge?.url || 'http://localhost:8787';
18
+ const blockstore = Blockstore.create(apiHost);
19
+ yield* Effect.tryPromise(() => blockstore.open());
17
20
 
18
- return contributes(WnfsCapabilities.Blockstore, blockstore);
19
- };
21
+ return Capability.contributes(WnfsCapabilities.Blockstore, blockstore);
22
+ }),
23
+ );
@@ -2,12 +2,17 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { lazy } from '@dxos/app-framework';
5
+ import { Capability } from '@dxos/app-framework';
6
+ import { type FileCapabilities } from '@dxos/plugin-file/types';
6
7
 
7
- export const Blockstore = lazy(() => import('./blockstore'));
8
- export const FileUploader = lazy(() => import('./file-uploader'));
9
- export const IntentResolver = lazy(() => import('./intent-resolver'));
10
- export const Markdown = lazy(() => import('./markdown'));
11
- export const ReactSurface = lazy(() => import('./react-surface'));
8
+ export const Backend: Capability.LazyCapability<
9
+ void,
10
+ Capability.Capability<Capability.InterfaceDef<FileCapabilities.Backend>>
11
+ > = Capability.lazy('Backend', () => import('./backend'));
12
12
 
13
- export * from './capabilities';
13
+ export const Blockstore = Capability.lazy('Blockstore', () => import('./blockstore'));
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,15 +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
 
11
+ import { Annotation, Obj } from '@dxos/echo';
10
12
  import { type Space } from '@dxos/react-client/echo';
11
13
 
12
- import { type WnfsCapabilities } from '../capabilities';
14
+ import { type WnfsCapabilities } from '#types';
13
15
 
16
+ import { WnfsStateAnnotation } from '../annotations';
14
17
  import { Rng, store } from './common';
15
18
 
16
19
  //
@@ -27,21 +30,37 @@ export const loadWnfs = async ({
27
30
  instances?: WnfsCapabilities.Instances;
28
31
  }) => {
29
32
  // TODO(wittjosiah): Remove.
30
- // Delete old properties if they exist.
31
- if (space.properties.wnfs_access_key !== undefined && space.properties.wnfs_private_forest_cid !== undefined) {
32
- delete space.properties.wnfs_access_key;
33
- delete space.properties.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'];
46
+ });
34
47
  }
35
48
 
36
- const cacheKey = space.properties.wnfs?.privateForestCid;
37
- 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]) {
38
52
  return instances[cacheKey];
39
53
  }
40
54
 
41
- const exists = !!space.properties.wnfs;
55
+ const exists = !!wnfsState;
42
56
  const instance = exists ? await loadWnfsDir(blockstore, space) : await createWnfsDir(blockstore, space);
43
57
  if (instances) {
44
- 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
+ }
45
64
  }
46
65
 
47
66
  return instance;
@@ -65,10 +84,12 @@ const createWnfsDir = async (blockstore: Blockstore, space: Space) => {
65
84
 
66
85
  const cidBytes = await newForest.store(wnfsStore);
67
86
 
68
- space.properties.wnfs = {
69
- accessKey: Uint8Arrays.toString(accessKeyRaw.toBytes(), 'base64'),
70
- privateForestCid: CID.decode(cidBytes).toString(),
71
- };
87
+ Obj.update(space.properties, (properties) => {
88
+ Annotation.set(properties, WnfsStateAnnotation, {
89
+ accessKey: Uint8Arrays.toString(accessKeyRaw.toBytes(), 'base64'),
90
+ privateForestCid: CID.decode(cidBytes).toString(),
91
+ });
92
+ });
72
93
 
73
94
  return {
74
95
  directory: dir,
@@ -79,11 +100,9 @@ const createWnfsDir = async (blockstore: Blockstore, space: Space) => {
79
100
  const loadWnfsDir = async (blockstore: Blockstore, space: Space) => {
80
101
  const wnfsStore = store(blockstore);
81
102
 
82
- const accessKey = AccessKey.fromBytes(Uint8Arrays.fromString(space.properties.wnfs.accessKey, 'base64'));
83
- const forest: PrivateForest = await PrivateForest.load(
84
- CID.parse(space.properties.wnfs.privateForestCid).bytes,
85
- wnfsStore,
86
- );
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);
87
106
  const node: PrivateNode = await PrivateNode.load(accessKey, forest, wnfsStore);
88
107
 
89
108
  return {
@@ -2,16 +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';
12
+ import { Annotation, Obj } from '@dxos/echo';
11
13
  import { log } from '@dxos/log';
12
14
 
13
- import { type WnfsCapabilities } from '../capabilities';
15
+ import { type WnfsCapabilities } from '#types';
14
16
 
17
+ import { WnfsStateAnnotation } from '../annotations';
15
18
  import { Rng, filePath, store } from './common';
16
19
  import { loadWnfs } from './load';
17
20
  import { wnfsUrl } from './wnfs-url';
@@ -46,7 +49,16 @@ export const upload = async ({
46
49
  const cidBytes = await updatedForest.store(wnfsStore);
47
50
 
48
51
  // Update the forest pointer on the associated space.
49
- space.properties.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
+ });
61
+ });
50
62
 
51
63
  // Generate `wnfs://` URL & return the info.
52
64
  const info = {