@dxos/plugin-wnfs 0.8.4-main.e8ec1fe → 0.8.4-main.effb148878

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 (157) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +2 -2
  3. package/dist/lib/neutral/WnfsPlugin.mjs +39 -0
  4. package/dist/lib/neutral/WnfsPlugin.mjs.map +7 -0
  5. package/dist/lib/neutral/WnfsPlugin.node.mjs +12 -0
  6. package/dist/lib/neutral/WnfsPlugin.node.mjs.map +7 -0
  7. package/dist/lib/neutral/WnfsPlugin.workerd.mjs +12 -0
  8. package/dist/lib/neutral/WnfsPlugin.workerd.mjs.map +7 -0
  9. package/dist/lib/neutral/backend-DHBQUTPC.mjs +47 -0
  10. package/dist/lib/neutral/backend-DHBQUTPC.mjs.map +7 -0
  11. package/dist/lib/{browser/blockstore-2JFU4NBU.mjs → neutral/blockstore-3NLSWC7Z.mjs} +12 -13
  12. package/dist/lib/neutral/blockstore-3NLSWC7Z.mjs.map +7 -0
  13. package/dist/lib/neutral/capabilities/index.mjs +13 -0
  14. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  15. package/dist/lib/{browser/chunk-D6VTEQIE.mjs → neutral/chunk-7KFJ6LYH.mjs} +43 -18
  16. package/dist/lib/neutral/chunk-7KFJ6LYH.mjs.map +7 -0
  17. package/dist/lib/neutral/chunk-IY6VOJSQ.mjs +37 -0
  18. package/dist/lib/neutral/chunk-IY6VOJSQ.mjs.map +7 -0
  19. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
  20. package/dist/lib/neutral/chunk-QODCKFTY.mjs +19 -0
  21. package/dist/lib/neutral/chunk-QODCKFTY.mjs.map +7 -0
  22. package/dist/lib/neutral/helpers/index.mjs +26 -0
  23. package/dist/lib/neutral/helpers/index.mjs.map +7 -0
  24. package/dist/lib/neutral/index.mjs +34 -0
  25. package/dist/lib/neutral/index.mjs.map +7 -0
  26. package/dist/lib/neutral/meta.json +1 -0
  27. package/dist/lib/neutral/meta.mjs +8 -0
  28. package/dist/lib/neutral/meta.mjs.map +7 -0
  29. package/dist/lib/neutral/plugin.mjs +12 -0
  30. package/dist/lib/neutral/plugin.mjs.map +7 -0
  31. package/dist/lib/neutral/translations.mjs +17 -0
  32. package/dist/lib/neutral/translations.mjs.map +7 -0
  33. package/dist/lib/neutral/types/index.mjs +8 -0
  34. package/dist/lib/neutral/types/index.mjs.map +7 -0
  35. package/dist/lib/neutral/url-resolver-UD3ZP77Y.mjs +47 -0
  36. package/dist/lib/neutral/url-resolver-UD3ZP77Y.mjs.map +7 -0
  37. package/dist/types/src/WnfsPlugin.d.ts +3 -1
  38. package/dist/types/src/WnfsPlugin.d.ts.map +1 -1
  39. package/dist/types/src/WnfsPlugin.node.d.ts +4 -0
  40. package/dist/types/src/WnfsPlugin.node.d.ts.map +1 -0
  41. package/dist/types/src/WnfsPlugin.test.d.ts +2 -0
  42. package/dist/types/src/WnfsPlugin.test.d.ts.map +1 -0
  43. package/dist/types/src/WnfsPlugin.workerd.d.ts +4 -0
  44. package/dist/types/src/WnfsPlugin.workerd.d.ts.map +1 -0
  45. package/dist/types/src/blockstore.d.ts.map +1 -1
  46. package/dist/types/src/capabilities/backend.d.ts +7 -0
  47. package/dist/types/src/capabilities/backend.d.ts.map +1 -0
  48. package/dist/types/src/capabilities/blockstore.d.ts +3 -2
  49. package/dist/types/src/capabilities/blockstore.d.ts.map +1 -1
  50. package/dist/types/src/capabilities/index.d.ts +5 -6
  51. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  52. package/dist/types/src/capabilities/url-resolver.d.ts +7 -0
  53. package/dist/types/src/capabilities/url-resolver.d.ts.map +1 -0
  54. package/dist/types/src/helpers/common.d.ts.map +1 -1
  55. package/dist/types/src/helpers/load.d.ts +1 -1
  56. package/dist/types/src/helpers/load.d.ts.map +1 -1
  57. package/dist/types/src/helpers/upload.d.ts +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 +2 -2
  61. package/dist/types/src/index.d.ts.map +1 -1
  62. package/dist/types/src/meta.d.ts +2 -2
  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 -12
  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 -2
  71. package/dist/types/src/types/index.d.ts.map +1 -1
  72. package/dist/types/tsconfig.tsbuildinfo +1 -1
  73. package/package.json +95 -48
  74. package/src/WnfsPlugin.node.ts +11 -0
  75. package/src/WnfsPlugin.test.ts +20 -0
  76. package/src/WnfsPlugin.tsx +27 -77
  77. package/src/WnfsPlugin.workerd.ts +11 -0
  78. package/src/blockstore.ts +1 -1
  79. package/src/capabilities/backend.ts +43 -0
  80. package/src/capabilities/blockstore.ts +14 -10
  81. package/src/capabilities/index.ts +12 -7
  82. package/src/capabilities/url-resolver.ts +44 -0
  83. package/src/helpers/load.ts +12 -7
  84. package/src/helpers/upload.ts +5 -2
  85. package/src/index.ts +2 -2
  86. package/src/meta.ts +20 -5
  87. package/src/plugin.ts +9 -0
  88. package/src/translations.ts +2 -11
  89. package/src/types/WnfsCapabilities.ts +18 -0
  90. package/src/types/index.ts +1 -2
  91. package/dist/lib/browser/FileContainer-LLNI7WXR.mjs +0 -103
  92. package/dist/lib/browser/FileContainer-LLNI7WXR.mjs.map +0 -7
  93. package/dist/lib/browser/blockstore-2JFU4NBU.mjs.map +0 -7
  94. package/dist/lib/browser/chunk-CWMKN2F6.mjs +0 -71
  95. package/dist/lib/browser/chunk-CWMKN2F6.mjs.map +0 -7
  96. package/dist/lib/browser/chunk-D6VTEQIE.mjs.map +0 -7
  97. package/dist/lib/browser/chunk-F4QHZWQD.mjs +0 -16
  98. package/dist/lib/browser/chunk-F4QHZWQD.mjs.map +0 -7
  99. package/dist/lib/browser/chunk-OGPGLJCV.mjs +0 -25
  100. package/dist/lib/browser/chunk-OGPGLJCV.mjs.map +0 -7
  101. package/dist/lib/browser/chunk-ZFPJA5F4.mjs +0 -16
  102. package/dist/lib/browser/chunk-ZFPJA5F4.mjs.map +0 -7
  103. package/dist/lib/browser/file-uploader-W6TJLAAK.mjs +0 -30
  104. package/dist/lib/browser/file-uploader-W6TJLAAK.mjs.map +0 -7
  105. package/dist/lib/browser/index.mjs +0 -116
  106. package/dist/lib/browser/index.mjs.map +0 -7
  107. package/dist/lib/browser/intent-resolver-FSW2EQF4.mjs +0 -48
  108. package/dist/lib/browser/intent-resolver-FSW2EQF4.mjs.map +0 -7
  109. package/dist/lib/browser/markdown-WYQDCVFQ.mjs +0 -198
  110. package/dist/lib/browser/markdown-WYQDCVFQ.mjs.map +0 -7
  111. package/dist/lib/browser/meta.json +0 -1
  112. package/dist/lib/browser/react-surface-DMU47U3X.mjs +0 -88
  113. package/dist/lib/browser/react-surface-DMU47U3X.mjs.map +0 -7
  114. package/dist/lib/browser/types/index.mjs +0 -10
  115. package/dist/types/src/capabilities/capabilities.d.ts +0 -12
  116. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  117. package/dist/types/src/capabilities/file-uploader.d.ts +0 -4
  118. package/dist/types/src/capabilities/file-uploader.d.ts.map +0 -1
  119. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  120. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  121. package/dist/types/src/capabilities/markdown.d.ts +0 -4
  122. package/dist/types/src/capabilities/markdown.d.ts.map +0 -1
  123. package/dist/types/src/capabilities/react-surface.d.ts +0 -4
  124. package/dist/types/src/capabilities/react-surface.d.ts.map +0 -1
  125. package/dist/types/src/components/FileContainer.d.ts +0 -9
  126. package/dist/types/src/components/FileContainer.d.ts.map +0 -1
  127. package/dist/types/src/components/FileInput.d.ts +0 -8
  128. package/dist/types/src/components/FileInput.d.ts.map +0 -1
  129. package/dist/types/src/components/FilePreview.d.ts +0 -11
  130. package/dist/types/src/components/FilePreview.d.ts.map +0 -1
  131. package/dist/types/src/components/index.d.ts +0 -3
  132. package/dist/types/src/components/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/types/File.d.ts +0 -16
  140. package/dist/types/src/types/File.d.ts.map +0 -1
  141. package/dist/types/src/types/types.d.ts +0 -55
  142. package/dist/types/src/types/types.d.ts.map +0 -1
  143. package/src/capabilities/capabilities.ts +0 -18
  144. package/src/capabilities/file-uploader.ts +0 -27
  145. package/src/capabilities/intent-resolver.ts +0 -32
  146. package/src/capabilities/markdown.ts +0 -26
  147. package/src/capabilities/react-surface.tsx +0 -45
  148. package/src/components/FileContainer.tsx +0 -59
  149. package/src/components/FileInput.tsx +0 -47
  150. package/src/components/FilePreview.tsx +0 -23
  151. package/src/components/index.ts +0 -9
  152. package/src/extensions/image.stories.tsx +0 -104
  153. package/src/extensions/image.tsx +0 -203
  154. package/src/extensions/index.ts +0 -5
  155. package/src/types/File.ts +0 -24
  156. package/src/types/types.ts +0 -41
  157. /package/dist/lib/{browser/types/index.mjs.map → neutral/chunk-J5LGTIGS.mjs.map} +0 -0
package/package.json CHANGED
@@ -1,46 +1,86 @@
1
1
  {
2
2
  "name": "@dxos/plugin-wnfs",
3
- "version": "0.8.4-main.e8ec1fe",
3
+ "version": "0.8.4-main.effb148878",
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
+ "./plugin": {
60
+ "source": "./src/plugin.ts",
61
+ "types": "./dist/types/src/plugin.d.ts",
62
+ "default": "./dist/lib/neutral/plugin.mjs"
63
+ },
64
+ "./translations": {
65
+ "source": "./src/translations.ts",
66
+ "types": "./dist/types/src/translations.d.ts",
67
+ "default": "./dist/lib/neutral/translations.mjs"
20
68
  }
21
69
  },
22
70
  "types": "dist/types/src/index.d.ts",
23
- "typesVersions": {
24
- "*": {
25
- "types": [
26
- "dist/types/src/types/index.d.ts"
27
- ]
28
- }
29
- },
30
71
  "files": [
31
72
  "dist",
32
73
  "src"
33
74
  ],
34
75
  "dependencies": {
35
- "@codemirror/language": "^6.11.3",
36
- "@codemirror/state": "^6.5.2",
37
- "@codemirror/view": "^6.38.4",
76
+ "@codemirror/language": "^6.12.3",
77
+ "@codemirror/state": "^6.6.0",
78
+ "@codemirror/view": "^6.43.0",
38
79
  "@ipld/car": "^5.3.3",
39
- "@preact-signals/safe-react": "^0.9.0",
40
80
  "blockstore-core": "^5.0.1",
41
81
  "blockstore-idb": "^2.0.0",
42
82
  "debounce": "^2.2.0",
43
- "effect": "3.18.3",
83
+ "effect": "3.20.0",
44
84
  "idb-keyval": "^6.2.1",
45
85
  "interface-blockstore": "^5.2.10",
46
86
  "it-all": "^3.0.6",
@@ -48,39 +88,46 @@
48
88
  "react-dropzone": "^14.2.3",
49
89
  "uint8arrays": "^5.1.0",
50
90
  "wnfs": "0.2.2",
51
- "@dxos/app-framework": "0.8.4-main.e8ec1fe",
52
- "@dxos/crypto": "0.8.4-main.e8ec1fe",
53
- "@dxos/echo": "0.8.4-main.e8ec1fe",
54
- "@dxos/effect": "0.8.4-main.e8ec1fe",
55
- "@dxos/local-storage": "0.8.4-main.e8ec1fe",
56
- "@dxos/invariant": "0.8.4-main.e8ec1fe",
57
- "@dxos/log": "0.8.4-main.e8ec1fe",
58
- "@dxos/plugin-client": "0.8.4-main.e8ec1fe",
59
- "@dxos/plugin-markdown": "0.8.4-main.e8ec1fe",
60
- "@dxos/react-client": "0.8.4-main.e8ec1fe",
61
- "@dxos/react-ui": "0.8.4-main.e8ec1fe",
62
- "@dxos/plugin-space": "0.8.4-main.e8ec1fe",
63
- "@dxos/react-ui-stack": "0.8.4-main.e8ec1fe",
64
- "@dxos/util": "0.8.4-main.e8ec1fe",
65
- "@dxos/react-ui-form": "0.8.4-main.e8ec1fe",
66
- "@dxos/react-ui-editor": "0.8.4-main.e8ec1fe"
91
+ "@dxos/app-framework": "0.8.4-main.effb148878",
92
+ "@dxos/compute": "0.8.4-main.effb148878",
93
+ "@dxos/crypto": "0.8.4-main.effb148878",
94
+ "@dxos/app-toolkit": "0.8.4-main.effb148878",
95
+ "@dxos/echo": "0.8.4-main.effb148878",
96
+ "@dxos/effect": "0.8.4-main.effb148878",
97
+ "@dxos/invariant": "0.8.4-main.effb148878",
98
+ "@dxos/keys": "0.8.4-main.effb148878",
99
+ "@dxos/log": "0.8.4-main.effb148878",
100
+ "@dxos/plugin-client": "0.8.4-main.effb148878",
101
+ "@dxos/plugin-file": "0.8.4-main.effb148878",
102
+ "@dxos/plugin-space": "0.8.4-main.effb148878",
103
+ "@dxos/react-client": "0.8.4-main.effb148878",
104
+ "@dxos/react-ui-editor": "0.8.4-main.effb148878",
105
+ "@dxos/react-ui": "0.8.4-main.effb148878",
106
+ "@dxos/react-ui-mosaic": "0.8.4-main.effb148878",
107
+ "@dxos/react-ui-stack": "0.8.4-main.effb148878",
108
+ "@dxos/react-ui-form": "0.8.4-main.effb148878",
109
+ "@dxos/schema": "0.8.4-main.effb148878",
110
+ "@dxos/types": "0.8.4-main.effb148878",
111
+ "@dxos/ui-editor": "0.8.4-main.effb148878",
112
+ "@dxos/util": "0.8.4-main.effb148878"
67
113
  },
68
114
  "devDependencies": {
69
- "@types/react": "~19.2.2",
70
- "@types/react-dom": "~19.2.2",
71
- "react": "~19.2.0",
72
- "react-dom": "~19.2.0",
73
- "vite": "7.1.9",
74
- "@dxos/random": "0.8.4-main.e8ec1fe",
75
- "@dxos/react-ui-theme": "0.8.4-main.e8ec1fe",
76
- "@dxos/storybook-utils": "0.8.4-main.e8ec1fe"
115
+ "@types/react": "~19.2.7",
116
+ "@types/react-dom": "~19.2.3",
117
+ "react": "~19.2.3",
118
+ "react-dom": "~19.2.3",
119
+ "vite": "^8.0.14",
120
+ "@dxos/plugin-testing": "0.8.4-main.effb148878",
121
+ "@dxos/random": "0.8.4-main.effb148878",
122
+ "@dxos/storybook-utils": "0.8.4-main.effb148878",
123
+ "@dxos/ui-theme": "0.8.4-main.effb148878"
77
124
  },
78
125
  "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.e8ec1fe",
83
- "@dxos/react-ui-theme": "0.8.4-main.e8ec1fe"
126
+ "effect": "3.20.0",
127
+ "react": "~19.2.3",
128
+ "react-dom": "~19.2.3",
129
+ "@dxos/ui-theme": "0.8.4-main.effb148878",
130
+ "@dxos/react-ui": "0.8.4-main.effb148878"
84
131
  },
85
132
  "publishConfig": {
86
133
  "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,44 @@
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 { WnfsAction, WnfsFile } 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
+ export const WnfsPlugin = Plugin.define(meta).pipe(
17
+ AppPlugin.addTranslationsModule({ translations }),
18
+ Plugin.addModule({
19
+ id: 'blockstore',
29
20
  activatesOn: ClientEvents.ClientReady,
30
21
  activate: Blockstore,
31
22
  }),
32
- defineModule({
33
- id: `${meta.id}/module/instances`,
23
+ Plugin.addModule({
24
+ id: 'instances',
34
25
  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
26
  activate: () =>
49
- contributes(Capabilities.Metadata, {
50
- id: WnfsFile.File.typename,
51
- metadata: {
52
- // TODO(wittjosiah): Would be nice if icon could change based on the type of the file.
53
- icon: 'ph--file--regular',
54
- iconHue: 'teal',
55
- },
27
+ Effect.sync(() => {
28
+ const instances: WnfsCapabilities.Instances = {};
29
+ return Capability.contributes(WnfsCapabilities.Instances, instances);
56
30
  }),
57
31
  }),
58
- defineModule({
59
- id: `${meta.id}/module/object-form`,
60
- activatesOn: ClientEvents.SetupSchema,
61
- activate: () =>
62
- contributes(
63
- SpaceCapabilities.ObjectForm,
64
- defineObjectForm({
65
- objectSchema: WnfsFile.File,
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`,
32
+ Plugin.addModule({
33
+ id: 'backend',
77
34
  activatesOn: ClientEvents.ClientReady,
78
- activate: FileUploader,
35
+ activate: Backend,
79
36
  }),
80
- defineModule({
81
- id: `${meta.id}/module/markdown`,
82
- activatesOn: MarkdownEvents.SetupExtensions,
83
- activate: Markdown,
84
- }),
85
- defineModule({
86
- id: `${meta.id}/module/react-surface`,
87
- activatesOn: Events.SetupReactSurface,
88
- activate: ReactSurface,
89
- }),
90
- defineModule({
91
- id: `${meta.id}/module/intent-resolver`,
92
- activatesOn: Events.SetupIntentResolver,
93
- activate: IntentResolver,
37
+ Plugin.addModule({
38
+ id: 'url-resolver',
39
+ activatesOn: ClientEvents.ClientReady,
40
+ activate: UrlResolver,
94
41
  }),
95
- ]);
42
+ Plugin.make,
43
+ );
44
+
45
+ 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;
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
+ );
@@ -7,9 +7,10 @@ import { CID } from 'multiformats';
7
7
  import * as Uint8Arrays from 'uint8arrays';
8
8
  import { AccessKey, PrivateDirectory, PrivateForest, PrivateNode } from 'wnfs';
9
9
 
10
+ import { Obj } from '@dxos/echo';
10
11
  import { type Space } from '@dxos/react-client/echo';
11
12
 
12
- import { type WnfsCapabilities } from '../capabilities';
13
+ import { type WnfsCapabilities } from '#types';
13
14
 
14
15
  import { Rng, store } from './common';
15
16
 
@@ -29,8 +30,10 @@ export const loadWnfs = async ({
29
30
  // TODO(wittjosiah): Remove.
30
31
  // Delete old properties if they exist.
31
32
  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
+ Obj.update(space.properties, (obj) => {
34
+ delete obj['wnfs_access_key'];
35
+ delete obj['wnfs_private_forest_cid'];
36
+ });
34
37
  }
35
38
 
36
39
  const cacheKey = space.properties.wnfs?.privateForestCid;
@@ -65,10 +68,12 @@ const createWnfsDir = async (blockstore: Blockstore, space: Space) => {
65
68
 
66
69
  const cidBytes = await newForest.store(wnfsStore);
67
70
 
68
- space.properties.wnfs = {
69
- accessKey: Uint8Arrays.toString(accessKeyRaw.toBytes(), 'base64'),
70
- privateForestCid: CID.decode(cidBytes).toString(),
71
- };
71
+ Obj.update(space.properties, (obj) => {
72
+ obj.wnfs = {
73
+ accessKey: Uint8Arrays.toString(accessKeyRaw.toBytes(), 'base64'),
74
+ privateForestCid: CID.decode(cidBytes).toString(),
75
+ };
76
+ });
72
77
 
73
78
  return {
74
79
  directory: dir,
@@ -8,9 +8,10 @@ import * as Raw from 'multiformats/codecs/raw';
8
8
  import { sha256 } from 'multiformats/hashes/sha2';
9
9
 
10
10
  import type { Space } from '@dxos/client/echo';
11
+ import { Obj } from '@dxos/echo';
11
12
  import { log } from '@dxos/log';
12
13
 
13
- import { type WnfsCapabilities } from '../capabilities';
14
+ import { type WnfsCapabilities } from '#types';
14
15
 
15
16
  import { Rng, filePath, store } from './common';
16
17
  import { loadWnfs } from './load';
@@ -46,7 +47,9 @@ export const upload = async ({
46
47
  const cidBytes = await updatedForest.store(wnfsStore);
47
48
 
48
49
  // Update the forest pointer on the associated space.
49
- space.properties.wnfs.privateForestCid = CID.decode(cidBytes).toString();
50
+ Obj.update(space.properties, (obj) => {
51
+ obj.wnfs.privateForestCid = CID.decode(cidBytes).toString();
52
+ });
50
53
 
51
54
  // Generate `wnfs://` URL & return the info.
52
55
  const info = {
package/src/index.ts CHANGED
@@ -2,6 +2,6 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- export { WnfsCapabilities } from './capabilities';
5
+ export * from './helpers';
6
6
  export * from './meta';
7
- export * from './WnfsPlugin';
7
+ export * from './types';
package/src/meta.ts CHANGED
@@ -2,17 +2,32 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type PluginMeta } from '@dxos/app-framework';
5
+ import { type Plugin } from '@dxos/app-framework';
6
+ import { meta as fileMeta } from '@dxos/plugin-file';
6
7
  import { trim } from '@dxos/util';
7
8
 
8
- export const meta: PluginMeta = {
9
- id: 'dxos.org/plugin/wnfs',
9
+ export const meta: Plugin.Meta = {
10
+ id: 'org.dxos.plugin.wnfs',
10
11
  name: 'WNFS',
12
+ author: 'DXOS',
11
13
  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.
14
+ Decentralized, end-to-end encrypted file storage for DXOS Composer built on the Web Native File System (WNFS) protocol.
15
+
16
+ WNFS organizes files inside a cryptographic "dark forest" — a content-addressed private file system
17
+ where each write produces a new immutable root CID. Files are stored as IPLD blocks (CIDv1, sha2-256),
18
+ cached locally in IndexedDB, and asynchronously replicated to the DXOS edge blob service as CAR archives.
19
+ Uploads and reads are scoped to a DXOS Space; the forest root CID is persisted atomically on the
20
+ space's ECHO properties so the file system state survives across sessions and devices.
21
+
22
+ The plugin registers as a \`FileCapabilities.Backend\` and \`FileCapabilities.UrlResolver\` so any plugin
23
+ that uses \`plugin-file\` (e.g. \`plugin-gallery\`) can upload files and resolve \`wnfs://\` URLs without
24
+ coupling to the storage implementation. The blockstore automatically queues blocks while offline and
25
+ flushes them when connectivity is restored.
14
26
  `,
15
27
  icon: 'ph--file-cloud--regular',
16
28
  iconHue: 'teal',
17
29
  source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-wnfs',
30
+ spec: 'PLUGIN.mdl',
31
+ tags: ['labs'],
32
+ dependsOn: [fileMeta.id],
18
33
  };
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'));