@dxos/plugin-crx 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/LICENSE +105 -0
  2. package/PLUGIN.mdl +599 -0
  3. package/README.md +25 -0
  4. package/dist/lib/CrxCapabilities.mjs +21 -0
  5. package/dist/lib/CrxCapabilities.mjs.map +1 -0
  6. package/dist/lib/CrxEvents.mjs +15 -0
  7. package/dist/lib/CrxEvents.mjs.map +1 -0
  8. package/dist/lib/CrxOperation.mjs +50 -0
  9. package/dist/lib/CrxOperation.mjs.map +1 -0
  10. package/dist/lib/CrxPlugin.mjs +16 -0
  11. package/dist/lib/CrxPlugin.mjs.map +1 -0
  12. package/dist/lib/PageAction.mjs +35 -0
  13. package/dist/lib/PageAction.mjs.map +1 -0
  14. package/dist/lib/Settings.mjs +84 -0
  15. package/dist/lib/Settings.mjs.map +1 -0
  16. package/dist/lib/capabilities.mjs +41 -0
  17. package/dist/lib/capabilities.mjs.map +1 -0
  18. package/dist/lib/capabilities.node.mjs +32 -0
  19. package/dist/lib/capabilities.node.mjs.map +1 -0
  20. package/dist/lib/capabilities.workerd.mjs +32 -0
  21. package/dist/lib/capabilities.workerd.mjs.map +1 -0
  22. package/dist/lib/chunk-add-note-from-snapshot.mjs +15 -0
  23. package/dist/lib/chunk-add-note-from-snapshot.mjs.map +1 -0
  24. package/dist/lib/chunk-add-organization-from-snapshot.mjs +15 -0
  25. package/dist/lib/chunk-add-organization-from-snapshot.mjs.map +1 -0
  26. package/dist/lib/chunk-add-person-from-snapshot.mjs +15 -0
  27. package/dist/lib/chunk-add-person-from-snapshot.mjs.map +1 -0
  28. package/dist/lib/chunk-install-page-actions.mjs +284 -0
  29. package/dist/lib/chunk-install-page-actions.mjs.map +1 -0
  30. package/dist/lib/chunk-mapping.mjs +81 -0
  31. package/dist/lib/chunk-mapping.mjs.map +1 -0
  32. package/dist/lib/chunk-operation-handler.mjs +12 -0
  33. package/dist/lib/chunk-operation-handler.mjs.map +1 -0
  34. package/dist/lib/chunk-page-action-provider.mjs +41 -0
  35. package/dist/lib/chunk-page-action-provider.mjs.map +1 -0
  36. package/dist/lib/chunk-react-surface.mjs +18 -0
  37. package/dist/lib/chunk-react-surface.mjs.map +1 -0
  38. package/dist/lib/chunk-rolldown-runtime.mjs +13 -0
  39. package/dist/lib/chunk-settings.mjs +28 -0
  40. package/dist/lib/chunk-settings.mjs.map +1 -0
  41. package/dist/lib/containers.mjs +80 -0
  42. package/dist/lib/containers.mjs.map +1 -0
  43. package/dist/lib/index.mjs +4 -0
  44. package/dist/lib/meta.mjs +34 -0
  45. package/dist/lib/meta.mjs.map +1 -0
  46. package/dist/lib/operations.mjs +13 -0
  47. package/dist/lib/operations.mjs.map +1 -0
  48. package/dist/lib/plugin.mjs +9 -0
  49. package/dist/lib/plugin.mjs.map +1 -0
  50. package/dist/lib/translations.mjs +22 -0
  51. package/dist/lib/translations.mjs.map +1 -0
  52. package/dist/lib/types.mjs +6 -0
  53. package/dist/lib/util.mjs +63 -0
  54. package/dist/lib/util.mjs.map +1 -0
  55. package/dist/types/dx.config.d.ts +28 -0
  56. package/dist/types/dx.config.d.ts.map +1 -0
  57. package/dist/types/src/CrxPlugin.d.ts +37 -0
  58. package/dist/types/src/CrxPlugin.d.ts.map +1 -0
  59. package/dist/types/src/capabilities/gen/node.d.ts +9 -0
  60. package/dist/types/src/capabilities/gen/node.d.ts.map +1 -0
  61. package/dist/types/src/capabilities/gen/workerd.d.ts +9 -0
  62. package/dist/types/src/capabilities/gen/workerd.d.ts.map +1 -0
  63. package/dist/types/src/capabilities/index.d.ts +9 -0
  64. package/dist/types/src/capabilities/index.d.ts.map +1 -0
  65. package/dist/types/src/capabilities/install-page-actions.d.ts +5 -0
  66. package/dist/types/src/capabilities/install-page-actions.d.ts.map +1 -0
  67. package/dist/types/src/capabilities/operation-handler.d.ts +5 -0
  68. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  69. package/dist/types/src/capabilities/page-action-provider.d.ts +5 -0
  70. package/dist/types/src/capabilities/page-action-provider.d.ts.map +1 -0
  71. package/dist/types/src/capabilities/react-surface.d.ts +5 -0
  72. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  73. package/dist/types/src/capabilities/settings.d.ts +10 -0
  74. package/dist/types/src/capabilities/settings.d.ts.map +1 -0
  75. package/dist/types/src/containers/CrxSettings/CrxSettings.d.ts +10 -0
  76. package/dist/types/src/containers/CrxSettings/CrxSettings.d.ts.map +1 -0
  77. package/dist/types/src/containers/CrxSettings/CrxSettings.stories.d.ts +25 -0
  78. package/dist/types/src/containers/CrxSettings/CrxSettings.stories.d.ts.map +1 -0
  79. package/dist/types/src/containers/CrxSettings/index.d.ts +2 -0
  80. package/dist/types/src/containers/CrxSettings/index.d.ts.map +1 -0
  81. package/dist/types/src/containers/index.d.ts +2 -0
  82. package/dist/types/src/containers/index.d.ts.map +1 -0
  83. package/dist/types/src/index.d.ts +4 -0
  84. package/dist/types/src/index.d.ts.map +1 -0
  85. package/dist/types/src/mapping.d.ts +24 -0
  86. package/dist/types/src/mapping.d.ts.map +1 -0
  87. package/dist/types/src/mapping.test.d.ts +2 -0
  88. package/dist/types/src/mapping.test.d.ts.map +1 -0
  89. package/dist/types/src/meta.d.ts +33 -0
  90. package/dist/types/src/meta.d.ts.map +1 -0
  91. package/dist/types/src/operations/add-note-from-snapshot.d.ts +5 -0
  92. package/dist/types/src/operations/add-note-from-snapshot.d.ts.map +1 -0
  93. package/dist/types/src/operations/add-organization-from-snapshot.d.ts +5 -0
  94. package/dist/types/src/operations/add-organization-from-snapshot.d.ts.map +1 -0
  95. package/dist/types/src/operations/add-person-from-snapshot.d.ts +5 -0
  96. package/dist/types/src/operations/add-person-from-snapshot.d.ts.map +1 -0
  97. package/dist/types/src/operations/index.d.ts +3 -0
  98. package/dist/types/src/operations/index.d.ts.map +1 -0
  99. package/dist/types/src/page-actions.d.ts +39 -0
  100. package/dist/types/src/page-actions.d.ts.map +1 -0
  101. package/dist/types/src/page-actions.test.d.ts +2 -0
  102. package/dist/types/src/page-actions.test.d.ts.map +1 -0
  103. package/dist/types/src/plugin.d.ts +4 -0
  104. package/dist/types/src/plugin.d.ts.map +1 -0
  105. package/dist/types/src/stories/Testbench.stories.d.ts +8 -0
  106. package/dist/types/src/stories/Testbench.stories.d.ts.map +1 -0
  107. package/dist/types/src/translations.d.ts +22 -0
  108. package/dist/types/src/translations.d.ts.map +1 -0
  109. package/dist/types/src/types/CrxCapabilities.d.ts +12 -0
  110. package/dist/types/src/types/CrxCapabilities.d.ts.map +1 -0
  111. package/dist/types/src/types/CrxEvents.d.ts +8 -0
  112. package/dist/types/src/types/CrxEvents.d.ts.map +1 -0
  113. package/dist/types/src/types/CrxOperation.d.ts +108 -0
  114. package/dist/types/src/types/CrxOperation.d.ts.map +1 -0
  115. package/dist/types/src/types/PageAction.d.ts +153 -0
  116. package/dist/types/src/types/PageAction.d.ts.map +1 -0
  117. package/dist/types/src/types/Settings.d.ts +25 -0
  118. package/dist/types/src/types/Settings.d.ts.map +1 -0
  119. package/dist/types/src/types/Settings.test.d.ts +2 -0
  120. package/dist/types/src/types/Settings.test.d.ts.map +1 -0
  121. package/dist/types/src/types/index.d.ts +6 -0
  122. package/dist/types/src/types/index.d.ts.map +1 -0
  123. package/dist/types/src/util/index.d.ts +2 -0
  124. package/dist/types/src/util/index.d.ts.map +1 -0
  125. package/dist/types/src/util/pingExtension.d.ts +15 -0
  126. package/dist/types/src/util/pingExtension.d.ts.map +1 -0
  127. package/dist/types/src/util/pingExtension.test.d.ts +2 -0
  128. package/dist/types/src/util/pingExtension.test.d.ts.map +1 -0
  129. package/dist/types/tsconfig.tsbuildinfo +1 -0
  130. package/dx.config.ts +32 -0
  131. package/package.json +162 -0
  132. package/src/CrxPlugin.ts +15 -0
  133. package/src/capabilities/gen/node.ts +43 -0
  134. package/src/capabilities/gen/workerd.ts +43 -0
  135. package/src/capabilities/index.ts +47 -0
  136. package/src/capabilities/install-page-actions.ts +64 -0
  137. package/src/capabilities/operation-handler.ts +16 -0
  138. package/src/capabilities/page-action-provider.ts +47 -0
  139. package/src/capabilities/react-surface.ts +26 -0
  140. package/src/capabilities/settings.ts +36 -0
  141. package/src/containers/CrxSettings/CrxSettings.stories.tsx +99 -0
  142. package/src/containers/CrxSettings/CrxSettings.tsx +100 -0
  143. package/src/containers/CrxSettings/index.ts +5 -0
  144. package/src/containers/index.ts +5 -0
  145. package/src/index.ts +7 -0
  146. package/src/mapping.test.ts +87 -0
  147. package/src/mapping.ts +101 -0
  148. package/src/meta.ts +9 -0
  149. package/src/operations/add-note-from-snapshot.ts +24 -0
  150. package/src/operations/add-organization-from-snapshot.ts +29 -0
  151. package/src/operations/add-person-from-snapshot.ts +29 -0
  152. package/src/operations/index.ts +16 -0
  153. package/src/page-actions.test.ts +164 -0
  154. package/src/page-actions.ts +171 -0
  155. package/src/plugin.tsx +29 -0
  156. package/src/stories/Testbench.stories.tsx +45 -0
  157. package/src/translations.ts +31 -0
  158. package/src/types/CrxCapabilities.ts +26 -0
  159. package/src/types/CrxEvents.ts +16 -0
  160. package/src/types/CrxOperation.ts +54 -0
  161. package/src/types/PageAction.ts +57 -0
  162. package/src/types/Settings.test.ts +30 -0
  163. package/src/types/Settings.ts +101 -0
  164. package/src/types/index.ts +9 -0
  165. package/src/util/index.ts +5 -0
  166. package/src/util/pingExtension.test.ts +69 -0
  167. package/src/util/pingExtension.ts +83 -0
  168. package/src/vite-env.d.ts +10 -0
package/dx.config.ts ADDED
@@ -0,0 +1,32 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { Config2 } from '@dxos/app-framework/config';
6
+ import { trim } from '@dxos/util';
7
+
8
+ export default Config2.make({
9
+ plugin: {
10
+ key: 'org.dxos.plugin.crx',
11
+ name: 'Browser Extension',
12
+ author: 'DXOS',
13
+ description: trim`
14
+ Capture content from any web page into your workspace with the Composer browser extension.
15
+ Highlight a section of a page and save it as a contact, an organization, or a bookmark —
16
+ the page's title, images, and details are picked up automatically, so a profile page
17
+ becomes a ready-made Person card and an article becomes a note with its source and text already filled in.
18
+
19
+ Saved items land in your active space alongside everything else you're working on,
20
+ complete with a link back to the original page.
21
+
22
+ Install the browser extension from the [Chrome Web Store](https://chromewebstore.google.com/detail/composer/ahkmmpagcinoehpnmdhoiohmmbikhnmj?pli=1).
23
+ `,
24
+ source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-crx',
25
+ icon: { key: 'ph--puzzle-piece--regular', hue: 'orange' },
26
+ // screenshots: [
27
+ // { dark: 'https://raw.githubusercontent.com/dxos/dxos/refs/heads/main/packages/plugins/plugin-crx/assets/images/' },
28
+ // ],
29
+ spec: 'PLUGIN.mdl',
30
+ tags: ['labs'],
31
+ },
32
+ });
package/package.json ADDED
@@ -0,0 +1,162 @@
1
+ {
2
+ "name": "@dxos/plugin-crx",
3
+ "version": "0.0.0",
4
+ "description": "Composer plugin for coordinating with the composer-crx browser extension.",
5
+ "homepage": "https://dxos.org",
6
+ "bugs": "https://github.com/dxos/dxos/issues",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/dxos/dxos"
10
+ },
11
+ "license": "FSL-1.1-Apache-2.0",
12
+ "author": "DXOS.org",
13
+ "sideEffects": true,
14
+ "type": "module",
15
+ "imports": {
16
+ "#capabilities": {
17
+ "source": {
18
+ "workerd": "./src/capabilities/gen/workerd.ts",
19
+ "node": "./src/capabilities/gen/node.ts",
20
+ "default": "./src/capabilities/index.ts"
21
+ },
22
+ "types": "./dist/types/src/capabilities/index.d.ts",
23
+ "workerd": "./dist/lib/capabilities.workerd.mjs",
24
+ "node": "./dist/lib/capabilities.node.mjs",
25
+ "default": "./dist/lib/capabilities.mjs"
26
+ },
27
+ "#containers": {
28
+ "source": "./src/containers/index.ts",
29
+ "types": "./dist/types/src/containers/index.d.ts",
30
+ "default": "./dist/lib/containers.mjs"
31
+ },
32
+ "#meta": {
33
+ "source": "./src/meta.ts",
34
+ "types": "./dist/types/src/meta.d.ts",
35
+ "default": "./dist/lib/meta.mjs"
36
+ },
37
+ "#operations": {
38
+ "source": "./src/operations/index.ts",
39
+ "types": "./dist/types/src/operations/index.d.ts",
40
+ "default": "./dist/lib/operations.mjs"
41
+ },
42
+ "#plugin": {
43
+ "source": "./src/plugin.tsx",
44
+ "types": "./dist/types/src/plugin.d.ts",
45
+ "default": "./dist/lib/plugin.mjs"
46
+ },
47
+ "#translations": {
48
+ "source": "./src/translations.ts",
49
+ "types": "./dist/types/src/translations.d.ts",
50
+ "default": "./dist/lib/translations.mjs"
51
+ },
52
+ "#types": {
53
+ "source": "./src/types/index.ts",
54
+ "types": "./dist/types/src/types/index.d.ts",
55
+ "default": "./dist/lib/types.mjs"
56
+ }
57
+ },
58
+ "exports": {
59
+ ".": {
60
+ "source": "./src/index.ts",
61
+ "types": "./dist/types/src/index.d.ts",
62
+ "import": "./dist/lib/index.mjs"
63
+ },
64
+ "./assets/PLUGIN.mdl": "./PLUGIN.mdl",
65
+ "./translations": {
66
+ "source": "./src/translations.ts",
67
+ "types": "./dist/types/src/translations.d.ts",
68
+ "import": "./dist/lib/translations.mjs"
69
+ },
70
+ "./package.json": "./package.json",
71
+ "./CrxCapabilities": {
72
+ "source": "./src/types/CrxCapabilities.ts",
73
+ "types": "./dist/types/src/types/CrxCapabilities.d.ts",
74
+ "import": "./dist/lib/CrxCapabilities.mjs"
75
+ },
76
+ "./CrxEvents": {
77
+ "source": "./src/types/CrxEvents.ts",
78
+ "types": "./dist/types/src/types/CrxEvents.d.ts",
79
+ "import": "./dist/lib/CrxEvents.mjs"
80
+ },
81
+ "./CrxOperation": {
82
+ "source": "./src/types/CrxOperation.ts",
83
+ "types": "./dist/types/src/types/CrxOperation.d.ts",
84
+ "import": "./dist/lib/CrxOperation.mjs"
85
+ },
86
+ "./CrxPlugin": {
87
+ "source": "./src/CrxPlugin.ts",
88
+ "types": "./dist/types/src/CrxPlugin.d.ts",
89
+ "import": "./dist/lib/CrxPlugin.mjs"
90
+ },
91
+ "./PageAction": {
92
+ "source": "./src/types/PageAction.ts",
93
+ "types": "./dist/types/src/types/PageAction.d.ts",
94
+ "import": "./dist/lib/PageAction.mjs"
95
+ },
96
+ "./Settings": {
97
+ "source": "./src/types/Settings.ts",
98
+ "types": "./dist/types/src/types/Settings.d.ts",
99
+ "import": "./dist/lib/Settings.mjs"
100
+ }
101
+ },
102
+ "types": "dist/types/src/index.d.ts",
103
+ "typesVersions": {
104
+ "*": {
105
+ "CrxCapabilities": [
106
+ "dist/types/src/types/CrxCapabilities.d.ts"
107
+ ],
108
+ "CrxEvents": [
109
+ "dist/types/src/types/CrxEvents.d.ts"
110
+ ],
111
+ "CrxOperation": [
112
+ "dist/types/src/types/CrxOperation.d.ts"
113
+ ],
114
+ "PageAction": [
115
+ "dist/types/src/types/PageAction.d.ts"
116
+ ],
117
+ "Settings": [
118
+ "dist/types/src/types/Settings.d.ts"
119
+ ]
120
+ }
121
+ },
122
+ "files": [
123
+ "dist",
124
+ "dx.config.ts",
125
+ "src",
126
+ "PLUGIN.mdl"
127
+ ],
128
+ "dependencies": {
129
+ "effect": "4.0.0-rc.117",
130
+ "@dxos/app-framework": "0.11.1",
131
+ "@dxos/compute": "0.11.1",
132
+ "@dxos/app-toolkit": "0.11.1",
133
+ "@dxos/crx-protocol": "0.0.0",
134
+ "@dxos/echo": "0.11.1",
135
+ "@dxos/effect": "0.11.1",
136
+ "@dxos/plugin-client": "0.11.1",
137
+ "@dxos/keys": "0.11.1",
138
+ "@dxos/log": "0.11.1",
139
+ "@dxos/plugin-space": "0.11.1",
140
+ "@dxos/react-ui": "0.11.1",
141
+ "@dxos/react-ui-form": "0.11.1",
142
+ "@dxos/plugin-markdown": "0.11.1",
143
+ "@dxos/util": "0.11.1",
144
+ "@dxos/types": "0.11.1"
145
+ },
146
+ "devDependencies": {
147
+ "@effect/atom-react": "4.0.0-rc.117",
148
+ "@storybook/react-vite": "^10.5.8",
149
+ "@types/react": "~19.2.17",
150
+ "react": "~19.2.7",
151
+ "vite": "^8.2.1",
152
+ "vitest": "4.1.10",
153
+ "@dxos/random": "0.11.1"
154
+ },
155
+ "peerDependencies": {
156
+ "react": "~19.2.7",
157
+ "@dxos/react-ui": "^0.11.1"
158
+ },
159
+ "publishConfig": {
160
+ "access": "public"
161
+ }
162
+ }
@@ -0,0 +1,15 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ // @import-as-namespace
6
+
7
+ import * as Plugin from '@dxos/app-framework/Plugin';
8
+
9
+ import { meta as pluginMeta } from '#meta';
10
+
11
+ /** Plugin metadata, available without loading the plugin body. */
12
+ export const meta = pluginMeta;
13
+
14
+ /** Constructs the plugin; the body loads on first enable. */
15
+ export const make = Plugin.lazy(meta, () => import('#plugin'));
@@ -0,0 +1,43 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ // GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'node' condition.
6
+
7
+ import * as ActivationEvents from '@dxos/app-framework/ActivationEvents';
8
+ import * as Capabilities from '@dxos/app-framework/Capabilities';
9
+ import * as Capability from '@dxos/app-framework/Capability';
10
+ import * as AppCapability from '@dxos/app-toolkit/AppCapability';
11
+
12
+ import { translations } from '#translations';
13
+ import { CrxCapabilities, CrxEvents } from '#types';
14
+
15
+ export const CrxSettings = AppCapability.settings(() => import('../settings.ts'), {
16
+ activatesOn: ActivationEvents.Idle,
17
+ provides: [CrxCapabilities.Settings],
18
+ });
19
+
20
+ export const InstallPageActions = Capability.lazyModule(
21
+ 'InstallPageActions',
22
+ {
23
+ requires: [Capabilities.OperationInvoker, Capabilities.AtomRegistry, CrxCapabilities.Settings],
24
+ provides: [],
25
+ activatesOn: CrxEvents.Start,
26
+ },
27
+ () => import('../install-page-actions.ts'),
28
+ );
29
+
30
+ export const OperationHandler = AppCapability.operationHandler(() => import('../operation-handler.ts'), {
31
+ activatesOn: ActivationEvents.Idle,
32
+ });
33
+
34
+ export const PageActionProvider = Capability.lazyModule(
35
+ 'PageActionProvider',
36
+ { provides: [CrxCapabilities.PageAction], activatesOn: CrxEvents.Start },
37
+ () => import('../page-action-provider.ts'),
38
+ );
39
+
40
+ export const Translations = AppCapability.translations(translations);
41
+
42
+ export const PluginAsset = undefined;
43
+ export const ReactSurface = undefined;
@@ -0,0 +1,43 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ // GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'workerd' condition.
6
+
7
+ import * as ActivationEvents from '@dxos/app-framework/ActivationEvents';
8
+ import * as Capabilities from '@dxos/app-framework/Capabilities';
9
+ import * as Capability from '@dxos/app-framework/Capability';
10
+ import * as AppCapability from '@dxos/app-toolkit/AppCapability';
11
+
12
+ import { translations } from '#translations';
13
+ import { CrxCapabilities, CrxEvents } from '#types';
14
+
15
+ export const CrxSettings = AppCapability.settings(() => import('../settings.ts'), {
16
+ activatesOn: ActivationEvents.Idle,
17
+ provides: [CrxCapabilities.Settings],
18
+ });
19
+
20
+ export const InstallPageActions = Capability.lazyModule(
21
+ 'InstallPageActions',
22
+ {
23
+ requires: [Capabilities.OperationInvoker, Capabilities.AtomRegistry, CrxCapabilities.Settings],
24
+ provides: [],
25
+ activatesOn: CrxEvents.Start,
26
+ },
27
+ () => import('../install-page-actions.ts'),
28
+ );
29
+
30
+ export const OperationHandler = AppCapability.operationHandler(() => import('../operation-handler.ts'), {
31
+ activatesOn: ActivationEvents.Idle,
32
+ });
33
+
34
+ export const PageActionProvider = Capability.lazyModule(
35
+ 'PageActionProvider',
36
+ { provides: [CrxCapabilities.PageAction], activatesOn: CrxEvents.Start },
37
+ () => import('../page-action-provider.ts'),
38
+ );
39
+
40
+ export const Translations = AppCapability.translations(translations);
41
+
42
+ export const PluginAsset = undefined;
43
+ export const ReactSurface = undefined;
@@ -0,0 +1,47 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as ActivationEvents from '@dxos/app-framework/ActivationEvents';
6
+ import * as Capabilities from '@dxos/app-framework/Capabilities';
7
+ import * as Capability from '@dxos/app-framework/Capability';
8
+ import * as AppCapability from '@dxos/app-toolkit/AppCapability';
9
+
10
+ import { meta } from '#meta';
11
+ import { translations } from '#translations';
12
+ import { CrxCapabilities, CrxEvents } from '#types';
13
+
14
+ // eslint-disable-next-line import/no-relative-packages
15
+ import pluginSpec from '../../PLUGIN.mdl?raw';
16
+
17
+ export const CrxSettings = AppCapability.settings(() => import('./settings.ts'), {
18
+ activatesOn: ActivationEvents.Idle,
19
+ provides: [CrxCapabilities.Settings],
20
+ });
21
+ export const InstallPageActions = Capability.lazyModule(
22
+ 'InstallPageActions',
23
+ {
24
+ requires: [Capabilities.OperationInvoker, Capabilities.AtomRegistry, CrxCapabilities.Settings],
25
+ provides: [],
26
+ activatesOn: CrxEvents.Start,
27
+ },
28
+ () => import('./install-page-actions.ts'),
29
+ );
30
+ export const OperationHandler = AppCapability.operationHandler(() => import('./operation-handler.ts'), {
31
+ activatesOn: ActivationEvents.Idle,
32
+ });
33
+ export const PageActionProvider = Capability.lazyModule(
34
+ 'PageActionProvider',
35
+ { provides: [CrxCapabilities.PageAction], activatesOn: CrxEvents.Start },
36
+ () => import('./page-action-provider.ts'),
37
+ );
38
+ export const PluginAsset = AppCapability.pluginAsset({
39
+ pluginId: meta.profile.key,
40
+ path: 'PLUGIN.mdl',
41
+ content: pluginSpec,
42
+ mimeType: 'application/x-mdl',
43
+ });
44
+ export const ReactSurface = AppCapability.surface(() => import('./react-surface.ts'), {
45
+ roles: ['org.dxos.role.article'],
46
+ });
47
+ export const Translations = AppCapability.translations(translations);
@@ -0,0 +1,64 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import * as Capabilities from '@dxos/app-framework/Capabilities';
8
+ import * as Capability from '@dxos/app-framework/Capability';
9
+ import * as LayoutOperation from '@dxos/app-toolkit/LayoutOperation';
10
+ import * as NavigationOperation from '@dxos/app-toolkit/NavigationOperation';
11
+ import { EID, EntityId } from '@dxos/keys';
12
+ import { log } from '@dxos/log';
13
+
14
+ import { meta } from '#meta';
15
+ import { CrxCapabilities, Settings } from '#types';
16
+
17
+ import { installPageActionListeners } from '../page-actions.ts';
18
+
19
+ const openObject = async (invoker: Capabilities.OperationInvoker, uri: EID.EID) => {
20
+ const { data } = await invoker.invokePromise(NavigationOperation.ResolveNavigationTargets, { query: { uri } });
21
+ const path = data?.targets[0]?.path;
22
+ if (path) {
23
+ await invoker.invokePromise(LayoutOperation.Open, { subject: [path] });
24
+ }
25
+ };
26
+
27
+ export default Capability.makeModule(
28
+ Effect.fnUntraced(function* () {
29
+ const capabilityManager = yield* Capability.Service;
30
+ const invoker = yield* Capabilities.OperationInvoker;
31
+ const registry = yield* Capabilities.AtomRegistry;
32
+ const settingsAtom = yield* CrxCapabilities.Settings;
33
+
34
+ // NOTE: The `Label` tuple only supports `ns`/`count`/`defaultValue`, so the
35
+ // success toast uses a plain key rather than interpolating the action label.
36
+ installPageActionListeners(capabilityManager, invoker, (ack, _label, spaceId) => {
37
+ if (ack.ok) {
38
+ void invoker.invokePromise(LayoutOperation.AddToast, {
39
+ id: `${meta.profile.key}.page-action-${ack.objectId ?? ack.id}`,
40
+ title: ['toast.page-action.success.title', { ns: meta.profile.key }],
41
+ });
42
+ const entityId = ack.objectId;
43
+ if (
44
+ spaceId &&
45
+ entityId &&
46
+ EntityId.isValid(entityId) &&
47
+ Settings.withDefaults(registry.get(settingsAtom)).autoOpenAfterClip
48
+ ) {
49
+ void openObject(invoker, EID.make({ spaceId, entityId }));
50
+ }
51
+ } else {
52
+ void invoker.invokePromise(LayoutOperation.AddToast, {
53
+ id: `${meta.profile.key}.page-action-error-${Date.now()}`,
54
+ title: ['toast.page-action.error.title', { ns: meta.profile.key }],
55
+ description: [`toast.error.${ack.error}.message`, { ns: meta.profile.key }],
56
+ });
57
+ }
58
+ });
59
+
60
+ log.info('CRX page-actions bridge installed');
61
+
62
+ return [];
63
+ }),
64
+ );
@@ -0,0 +1,16 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import * as Capabilities from '@dxos/app-framework/Capabilities';
8
+ import * as Capability from '@dxos/app-framework/Capability';
9
+
10
+ import { CrxOperationHandlerSet } from '#operations';
11
+
12
+ export default Capability.makeModule(
13
+ Effect.fnUntraced(function* () {
14
+ return Capability.contribute(Capabilities.OperationHandler, CrxOperationHandlerSet);
15
+ }),
16
+ );
@@ -0,0 +1,47 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import * as Capability from '@dxos/app-framework/Capability';
8
+
9
+ import { meta } from '#meta';
10
+ import { CrxCapabilities, CrxOperation, PageAction } from '#types';
11
+
12
+ export default Capability.makeModule(() =>
13
+ Effect.sync(() => {
14
+ // Picker-only: these actions back the extension's DOM-picker toolbar and
15
+ // are not surfaced in the popup or context menu.
16
+ const actions: PageAction.PageAction[] = [
17
+ {
18
+ id: `${meta.profile.key}/page-action/add-person`,
19
+ label: 'Person',
20
+ icon: 'ph--user--regular',
21
+ urlPatterns: ['http://*/*', 'https://*/*'],
22
+ extractor: { name: 'snapshot' },
23
+ contexts: ['picker'],
24
+ operation: CrxOperation.AddPersonFromSnapshot,
25
+ },
26
+ {
27
+ id: `${meta.profile.key}/page-action/add-organization`,
28
+ label: 'Organization',
29
+ icon: 'ph--building-office--regular',
30
+ urlPatterns: ['http://*/*', 'https://*/*'],
31
+ extractor: { name: 'snapshot' },
32
+ contexts: ['picker'],
33
+ operation: CrxOperation.AddOrganizationFromSnapshot,
34
+ },
35
+ {
36
+ id: `${meta.profile.key}/page-action/add-note`,
37
+ label: 'Note',
38
+ icon: 'ph--note--regular',
39
+ urlPatterns: ['http://*/*', 'https://*/*'],
40
+ extractor: { name: 'snapshot' },
41
+ contexts: ['picker'],
42
+ operation: CrxOperation.AddNoteFromSnapshot,
43
+ },
44
+ ];
45
+ return Capability.contribute(CrxCapabilities.PageAction, actions);
46
+ }),
47
+ );
@@ -0,0 +1,26 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import * as Capabilities from '@dxos/app-framework/Capabilities';
8
+ import * as Capability from '@dxos/app-framework/Capability';
9
+ import { Surface } from '@dxos/app-framework/ui';
10
+ import { AppSurface } from '@dxos/app-toolkit/ui';
11
+
12
+ import { CrxSettings } from '#containers';
13
+ import { meta } from '#meta';
14
+
15
+ export default Capability.makeModule(() =>
16
+ Effect.succeed(
17
+ Capability.contribute(Capabilities.ReactSurface, [
18
+ Surface.create({
19
+ id: 'pluginSettings',
20
+ filter: AppSurface.settings(AppSurface.Article, meta.profile.key),
21
+ component: CrxSettings,
22
+ props: ({ data: { subject } }) => ({ subject }),
23
+ }),
24
+ ]),
25
+ ),
26
+ );
@@ -0,0 +1,36 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import * as Capability from '@dxos/app-framework/Capability';
8
+ import * as AppCapabilities from '@dxos/app-toolkit/AppCapabilities';
9
+ import { createKvsStore } from '@dxos/effect';
10
+
11
+ import { meta } from '#meta';
12
+ import { CrxCapabilities, Settings } from '#types';
13
+
14
+ /**
15
+ * Contributes the Settings atom both under the plugin-scoped capability (so
16
+ * other plugins can read it) and under `AppCapabilities.Settings` (so the
17
+ * standard settings panel surfaces it).
18
+ */
19
+ export default Capability.makeModule(() =>
20
+ Effect.sync(() => {
21
+ const settingsAtom = createKvsStore({
22
+ key: meta.profile.key,
23
+ schema: Settings.Settings,
24
+ defaultValue: () => Settings.defaults,
25
+ });
26
+
27
+ return [
28
+ Capability.contribute(CrxCapabilities.Settings, settingsAtom),
29
+ Capability.contribute(AppCapabilities.Settings, {
30
+ prefix: meta.profile.key,
31
+ schema: Settings.Settings,
32
+ atom: settingsAtom,
33
+ }),
34
+ ];
35
+ }),
36
+ );
@@ -0,0 +1,99 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type Decorator, type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import * as Atom from 'effect/unstable/reactivity/Atom';
7
+ import React, { useEffect, useMemo } from 'react';
8
+
9
+ import { withPluginManager } from '@dxos/app-framework/testing';
10
+ import { Proxy } from '@dxos/crx-protocol';
11
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
12
+
13
+ import { meta as pluginMeta } from '#meta';
14
+ import { translations } from '#translations';
15
+ import { Settings } from '#types';
16
+
17
+ import { CrxSettings } from './CrxSettings.tsx';
18
+
19
+ /**
20
+ * Stand in for the extension's content relay so the connection test succeeds: set the readiness
21
+ * dataset marker and ack each ping with a fake identity. Without this the test button always
22
+ * reports "Extension not detected" — storybook is not a Composer origin with the extension relay.
23
+ */
24
+ const withFakeExtension: Decorator = (Story) => {
25
+ useEffect(() => {
26
+ document.documentElement.dataset[Proxy.RENDER_READY_DATASET_KEY] = '1';
27
+ const listener = (event: Event) => {
28
+ const detail = (event as CustomEvent).detail as { id: string };
29
+ window.dispatchEvent(
30
+ new CustomEvent(Proxy.PING_ACK_EVENT, {
31
+ detail: {
32
+ version: 1,
33
+ id: detail.id,
34
+ ok: true,
35
+ extensionVersion: '0.0.0-story',
36
+ extensionName: 'Fake',
37
+ },
38
+ }),
39
+ );
40
+ };
41
+ window.addEventListener(Proxy.PING_EVENT, listener);
42
+ return () => {
43
+ delete document.documentElement.dataset[Proxy.RENDER_READY_DATASET_KEY];
44
+ window.removeEventListener(Proxy.PING_EVENT, listener);
45
+ };
46
+ }, []);
47
+ return <Story />;
48
+ };
49
+
50
+ // The container reads and writes the contributed settings entry, so the story owns one per render.
51
+ const DefaultStory = ({ initial, readonly }: { initial?: Settings.Settings; readonly?: boolean }) => {
52
+ const subject = useMemo(
53
+ () => ({
54
+ prefix: pluginMeta.profile.key,
55
+ schema: Settings.Settings,
56
+ atom: Atom.make<Settings.Settings>(initial ?? Settings.defaults).pipe(Atom.keepAlive),
57
+ }),
58
+ [initial],
59
+ );
60
+
61
+ return <CrxSettings subject={subject} readonly={readonly} />;
62
+ };
63
+
64
+ const meta: Meta<typeof DefaultStory> = {
65
+ title: 'plugins/plugin-crx/containers/CrxSettings',
66
+ component: DefaultStory,
67
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' }), withPluginManager()],
68
+ parameters: {
69
+ translations,
70
+ },
71
+ };
72
+
73
+ export default meta;
74
+
75
+ type Story = StoryObj<typeof meta>;
76
+
77
+ export const Default: Story = {
78
+ decorators: [withFakeExtension],
79
+ };
80
+
81
+ export const Readonly: Story = {
82
+ decorators: [withFakeExtension],
83
+ args: {
84
+ readonly: true,
85
+ },
86
+ };
87
+
88
+ /**
89
+ * No fake relay — the connection test talks to the real composer-crx extension. For development:
90
+ * load the dev extension (`moon run composer-crx:build`, load unpacked from `out/composer-crx`),
91
+ * then add this storybook's origin (e.g. `http://localhost:9009/*`) to the extension's Composer
92
+ * URLs in its options page so the content relay installs here.
93
+ *
94
+ * NOTE: The extension's content script runs only in the top frame,
95
+ * so the story must be opened OUTSIDE the storybook manager's preview iframe:
96
+ * `http://localhost:9009/iframe.html?id=plugins-plugin-crx-crxsettings--live`.
97
+ * Without that setup the test reports "Extension not detected".
98
+ */
99
+ export const Live: Story = {};