@dxos/app-framework 0.14.0 → 0.16.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 (129) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/dist/lib/App.mjs +1 -2
  3. package/dist/lib/Hooks.mjs +1 -2
  4. package/dist/lib/chunk-App.mjs +11 -0
  5. package/dist/lib/chunk-App.mjs.map +1 -0
  6. package/dist/lib/chunk-Cli.mjs +8 -0
  7. package/dist/lib/chunk-Cli.mjs.map +1 -0
  8. package/dist/lib/chunk-Devtools.mjs +112 -0
  9. package/dist/lib/chunk-Devtools.mjs.map +1 -0
  10. package/dist/lib/chunk-Hooks2.mjs +35 -0
  11. package/dist/lib/chunk-Hooks2.mjs.map +1 -0
  12. package/dist/lib/chunk-PluginManagerProvider.mjs +12 -0
  13. package/dist/lib/chunk-PluginManagerProvider.mjs.map +1 -0
  14. package/dist/lib/chunk-ProcessManagerPlugin.mjs +3 -3
  15. package/dist/lib/chunk-ProcessManagerPlugin.mjs.map +1 -1
  16. package/dist/lib/chunk-Role.mjs +19 -0
  17. package/dist/lib/chunk-Role.mjs.map +1 -0
  18. package/dist/lib/chunk-SharedPackages.mjs +11 -0
  19. package/dist/lib/chunk-SharedPackages.mjs.map +1 -0
  20. package/dist/lib/chunk-Surface.mjs.map +1 -1
  21. package/dist/lib/chunk-Surface2.mjs +37 -0
  22. package/dist/lib/chunk-Surface2.mjs.map +1 -0
  23. package/dist/lib/chunk-SurfaceManager.mjs +3 -3
  24. package/dist/lib/chunk-SurfaceManager.mjs.map +1 -1
  25. package/dist/lib/chunk-activation-event.mjs +86 -0
  26. package/dist/lib/chunk-activation-event.mjs.map +1 -0
  27. package/dist/lib/chunk-activation-events.mjs +66 -0
  28. package/dist/lib/chunk-activation-events.mjs.map +1 -0
  29. package/dist/lib/chunk-capabilities.mjs +202 -0
  30. package/dist/lib/chunk-capabilities.mjs.map +1 -0
  31. package/dist/lib/chunk-capability-manager.mjs +203 -0
  32. package/dist/lib/chunk-capability-manager.mjs.map +1 -0
  33. package/dist/lib/chunk-capability2.mjs +2 -2
  34. package/dist/lib/chunk-capability2.mjs.map +1 -1
  35. package/dist/lib/chunk-history-tracker.mjs +1 -1
  36. package/dist/lib/chunk-hooks.mjs +5 -5
  37. package/dist/lib/chunk-hooks.mjs.map +1 -1
  38. package/dist/lib/chunk-plugin-asset-cache.mjs +28 -0
  39. package/dist/lib/chunk-plugin-asset-cache.mjs.map +1 -0
  40. package/dist/lib/chunk-plugin-manager.mjs +68 -35
  41. package/dist/lib/chunk-plugin-manager.mjs.map +1 -1
  42. package/dist/lib/chunk-plugin-manager2.mjs +22 -0
  43. package/dist/lib/chunk-plugin-manager2.mjs.map +1 -0
  44. package/dist/lib/chunk-plugin-manifest.mjs +126 -0
  45. package/dist/lib/chunk-plugin-manifest.mjs.map +1 -0
  46. package/dist/lib/chunk-plugin.mjs +354 -0
  47. package/dist/lib/chunk-plugin.mjs.map +1 -0
  48. package/dist/lib/chunk-process-manager-capability.mjs +11 -10
  49. package/dist/lib/chunk-process-manager-capability.mjs.map +1 -1
  50. package/dist/lib/chunk-registry.mjs.map +1 -1
  51. package/dist/lib/chunk-undo-mapping.mjs +47 -0
  52. package/dist/lib/{plugin-process-manager/history/undo-mapping.mjs.map → chunk-undo-mapping.mjs.map} +1 -1
  53. package/dist/lib/chunk-undo-registry.mjs +22 -0
  54. package/dist/lib/{plugin-process-manager/history/undo-registry.mjs.map → chunk-undo-registry.mjs.map} +1 -1
  55. package/dist/lib/chunk-url-loader.mjs +345 -0
  56. package/dist/lib/chunk-url-loader.mjs.map +1 -0
  57. package/dist/lib/cli.mjs +3 -3
  58. package/dist/lib/cli.mjs.map +1 -1
  59. package/dist/lib/common/Role.mjs +1 -19
  60. package/dist/lib/common/activation-events.mjs +1 -57
  61. package/dist/lib/common/capabilities.mjs +1 -202
  62. package/dist/lib/config.mjs +1 -2
  63. package/dist/lib/core/activation-event.mjs +1 -86
  64. package/dist/lib/core/capability-manager.mjs +1 -203
  65. package/dist/lib/core/capability.mjs +1 -2
  66. package/dist/lib/core/plugin-asset-cache.mjs +1 -28
  67. package/dist/lib/core/plugin-manager.mjs +2 -19
  68. package/dist/lib/core/plugin-manifest.mjs +1 -126
  69. package/dist/lib/core/plugin.mjs +1 -354
  70. package/dist/lib/core/registry.mjs +1 -2
  71. package/dist/lib/core/url-loader.mjs +1 -345
  72. package/dist/lib/index.mjs +19 -19
  73. package/dist/lib/ns/App.mjs +2 -11
  74. package/dist/lib/ns/Cli.mjs +2 -8
  75. package/dist/lib/ns/Devtools.mjs +1 -112
  76. package/dist/lib/ns/Hooks.mjs +2 -35
  77. package/dist/lib/ns/PluginManagerProvider.mjs +2 -12
  78. package/dist/lib/ns/SharedPackages.mjs +2 -11
  79. package/dist/lib/ns/Surface.mjs +2 -35
  80. package/dist/lib/ns/Translations.mjs +1 -2
  81. package/dist/lib/plugin-cli.mjs +2 -4
  82. package/dist/lib/plugin-cli.mjs.map +1 -1
  83. package/dist/lib/plugin-process-manager/ProcessManagerPlugin.mjs +1 -2
  84. package/dist/lib/plugin-process-manager/history/history-tracker.mjs +1 -2
  85. package/dist/lib/plugin-process-manager/history/undo-mapping.mjs +1 -47
  86. package/dist/lib/plugin-process-manager/history/undo-registry.mjs +1 -22
  87. package/dist/lib/testing/react.mjs +1 -1
  88. package/dist/lib/testing/react.mjs.map +1 -1
  89. package/dist/lib/testing.mjs +5 -5
  90. package/dist/lib/testing.mjs.map +1 -1
  91. package/dist/lib/vite-plugin.mjs +3 -3
  92. package/dist/lib/vite-plugin.mjs.map +1 -1
  93. package/dist/types/src/common/activation-events.d.ts +8 -0
  94. package/dist/types/src/common/activation-events.d.ts.map +1 -1
  95. package/dist/types/src/core/plugin-manager/manager-state.d.ts.map +1 -1
  96. package/dist/types/src/core/plugin-manager/module-loader.d.ts +0 -10
  97. package/dist/types/src/core/plugin-manager/module-loader.d.ts.map +1 -1
  98. package/dist/types/src/core/plugin-manager/plugin-manager.d.ts.map +1 -1
  99. package/dist/types/src/plugin-process-manager/process-manager-capability.d.ts.map +1 -1
  100. package/dist/types/src/ui/components/Surface/SurfaceComponent.stories.d.ts.map +1 -1
  101. package/dist/types/src/ui/hooks/useApp.d.ts.map +1 -1
  102. package/dist/types/tsconfig.tsbuildinfo +1 -1
  103. package/package.json +32 -32
  104. package/src/common/activation-events.ts +9 -0
  105. package/src/core/plugin-manager/manager-state.ts +14 -12
  106. package/src/core/plugin-manager/module-loader.ts +43 -7
  107. package/src/core/plugin-manager/plugin-manager.ts +2 -1
  108. package/src/plugin-process-manager/process-manager-capability.test.ts +66 -1
  109. package/src/plugin-process-manager/process-manager-capability.ts +22 -2
  110. package/src/ui/components/Surface/SurfaceComponent.stories.tsx +9 -7
  111. package/src/ui/hooks/useApp.tsx +2 -1
  112. package/src/vite-plugin/boot-loader/loader-app/boot-loader.css +19 -1
  113. package/dist/lib/common/Role.mjs.map +0 -1
  114. package/dist/lib/common/activation-events.mjs.map +0 -1
  115. package/dist/lib/common/capabilities.mjs.map +0 -1
  116. package/dist/lib/core/activation-event.mjs.map +0 -1
  117. package/dist/lib/core/capability-manager.mjs.map +0 -1
  118. package/dist/lib/core/plugin-asset-cache.mjs.map +0 -1
  119. package/dist/lib/core/plugin-manager.mjs.map +0 -1
  120. package/dist/lib/core/plugin-manifest.mjs.map +0 -1
  121. package/dist/lib/core/plugin.mjs.map +0 -1
  122. package/dist/lib/core/url-loader.mjs.map +0 -1
  123. package/dist/lib/ns/App.mjs.map +0 -1
  124. package/dist/lib/ns/Cli.mjs.map +0 -1
  125. package/dist/lib/ns/Devtools.mjs.map +0 -1
  126. package/dist/lib/ns/Hooks.mjs.map +0 -1
  127. package/dist/lib/ns/PluginManagerProvider.mjs.map +0 -1
  128. package/dist/lib/ns/SharedPackages.mjs.map +0 -1
  129. package/dist/lib/ns/Surface.mjs.map +0 -1
@@ -0,0 +1,345 @@
1
+ import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
2
+ import { h as isPlugin } from "./chunk-plugin.mjs";
3
+ import { n as noop } from "./chunk-plugin-asset-cache.mjs";
4
+ import { i as fetchManifest } from "./chunk-plugin-manifest.mjs";
5
+ import * as Effect from "effect/Effect";
6
+ import { log } from "@dxos/log";
7
+ import * as Option from "effect/Option";
8
+ import { BaseError } from "@dxos/errors";
9
+ //#region src/core/url-loader.ts
10
+ var url_loader_exports = /* @__PURE__ */ __exportAll({
11
+ RemotePluginLoadError: () => RemotePluginLoadError,
12
+ getInstalledVersion: () => getInstalledVersion,
13
+ getRemoteEntries: () => getRemoteEntries,
14
+ isLocalUrl: () => isLocalUrl,
15
+ make: () => make,
16
+ preload: () => preload,
17
+ setInstalledVersion: () => setInstalledVersion,
18
+ setRemoteEntries: () => setRemoteEntries,
19
+ uninstall: () => uninstall
20
+ });
21
+ var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-framework/src/core/url-loader.ts";
22
+ var DEFAULT_KEY = "org.dxos.composer.remote-plugins";
23
+ /**
24
+ * Tagged error for any failure during remote plugin loading. Construction sites
25
+ * set `context.locator` and `context.reason` (one of `'invalid-locator' |
26
+ * 'manifest-error' | 'cache-error' | 'import-failed' | 'meta-missing' |
27
+ * 'meta-mismatch' | 'duplicate-id'`) so handlers can route on the failure mode.
28
+ */
29
+ var RemotePluginLoadError = class extends BaseError.extend("RemotePluginLoadError", "Failed to load remote plugin") {};
30
+ var defaultStorage = () => ({
31
+ get: (key) => localStorage.getItem(key),
32
+ set: (key, value) => localStorage.setItem(key, value)
33
+ });
34
+ var getPersistedRemotePlugins = (storage, key) => {
35
+ try {
36
+ const parsed = JSON.parse(storage.get(key) ?? "[]");
37
+ if (!Array.isArray(parsed)) return [];
38
+ return parsed.filter((entry) => typeof entry === "object" && entry !== null && typeof entry.id === "string" && typeof entry.url === "string" && (entry.version === void 0 || typeof entry.version === "string"));
39
+ } catch {
40
+ return [];
41
+ }
42
+ };
43
+ var persistRemotePlugin = (storage, key, entry) => {
44
+ try {
45
+ const entries = getPersistedRemotePlugins(storage, key).filter((existing) => existing.id !== entry.id);
46
+ entries.push(entry);
47
+ storage.set(key, JSON.stringify(entries));
48
+ } catch (error) {
49
+ log.warn("failed to persist remote plugin entry", {
50
+ entry,
51
+ error
52
+ }, {
53
+ "~LogMeta": "~LogMeta",
54
+ F: __dxlog_file,
55
+ L: 99,
56
+ S: void 0
57
+ });
58
+ }
59
+ };
60
+ var removePersistedRemotePlugin = (storage, key, pluginId) => {
61
+ try {
62
+ const entries = getPersistedRemotePlugins(storage, key).filter((existing) => existing.id !== pluginId);
63
+ storage.set(key, JSON.stringify(entries));
64
+ } catch (error) {
65
+ log.warn("failed to remove remote plugin entry", {
66
+ pluginId,
67
+ error
68
+ }, {
69
+ "~LogMeta": "~LogMeta",
70
+ F: __dxlog_file,
71
+ L: 108,
72
+ S: void 0
73
+ });
74
+ }
75
+ };
76
+ var isUrl = (locator) => {
77
+ try {
78
+ const url = new URL(locator);
79
+ return url.protocol === "http:" || url.protocol === "https:";
80
+ } catch {
81
+ return false;
82
+ }
83
+ };
84
+ /**
85
+ * Returns true when the URL's hostname is the local host (localhost, 127.0.0.1, or ::1).
86
+ */
87
+ var isLocalUrl = (locator) => {
88
+ try {
89
+ const hostname = new URL(locator).hostname.toLowerCase();
90
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]";
91
+ } catch {
92
+ return false;
93
+ }
94
+ };
95
+ /**
96
+ * Returns the list of remote plugin entries previously persisted by {@link make}.
97
+ * Useful for UI code that needs to know which loaded plugins were installed from a URL
98
+ * (e.g. to surface a tag on remote or localhost-hosted plugins).
99
+ */
100
+ var getRemoteEntries = (options = {}) => {
101
+ return getPersistedRemotePlugins(options.storage ?? defaultStorage(), options.key ?? DEFAULT_KEY);
102
+ };
103
+ /**
104
+ * Replaces the persisted remote plugin entries wholesale. Entries are read during {@link preload},
105
+ * so a replacement takes effect on the next reload.
106
+ */
107
+ var setRemoteEntries = (entries, options = {}) => {
108
+ const storage = options.storage ?? defaultStorage();
109
+ const key = options.key ?? DEFAULT_KEY;
110
+ try {
111
+ storage.set(key, JSON.stringify(entries));
112
+ } catch (error) {
113
+ log.warn("failed to replace remote plugin entries", { error }, {
114
+ "~LogMeta": "~LogMeta",
115
+ F: __dxlog_file,
116
+ L: 155,
117
+ S: void 0
118
+ });
119
+ }
120
+ };
121
+ /**
122
+ * Updates the persisted installed version for an already-stored remote plugin entry.
123
+ * Does nothing if the plugin has not been persisted yet.
124
+ */
125
+ var setInstalledVersion = (id, version, options = {}) => {
126
+ const storage = options.storage ?? defaultStorage();
127
+ const key = options.key ?? DEFAULT_KEY;
128
+ const entries = getPersistedRemotePlugins(storage, key);
129
+ const index = entries.findIndex((entry) => entry.id === id);
130
+ if (index === -1) return;
131
+ entries[index] = {
132
+ ...entries[index],
133
+ version
134
+ };
135
+ try {
136
+ storage.set(key, JSON.stringify(entries));
137
+ } catch (error) {
138
+ log.warn("failed to update installed version for remote plugin", {
139
+ id,
140
+ version,
141
+ error
142
+ }, {
143
+ "~LogMeta": "~LogMeta",
144
+ F: __dxlog_file,
145
+ L: 175,
146
+ S: void 0
147
+ });
148
+ }
149
+ };
150
+ /**
151
+ * Returns the installed version string for the given plugin id, or `undefined` if
152
+ * the plugin was installed without version tracking (legacy install) or is not found.
153
+ */
154
+ var getInstalledVersion = (id, options = {}) => {
155
+ return getPersistedRemotePlugins(options.storage ?? defaultStorage(), options.key ?? DEFAULT_KEY).find((entry) => entry.id === id)?.version;
156
+ };
157
+ var normalizePluginExport = (mod) => {
158
+ const exported = mod.default;
159
+ if (isPlugin(exported)) return exported;
160
+ if (typeof exported === "function") {
161
+ const result = exported();
162
+ if (isPlugin(result)) return result;
163
+ }
164
+ throw new Error("Remote module default export is not a Plugin or a zero-arg plugin factory.");
165
+ };
166
+ /**
167
+ * Loads stylesheets declared in the manifest by appending `<link rel="stylesheet">` elements to the host document.
168
+ * Each link is tagged with `data-dxos-plugin-id` so `uninstall` can clean them up.
169
+ */
170
+ var loadStylesheets = (manifest, cache) => Effect.gen(function* () {
171
+ if (typeof document === "undefined") return;
172
+ const cssUrls = manifest.assetUrls.filter((url) => url.endsWith(".css"));
173
+ for (const url of cssUrls) {
174
+ const resolved = yield* cache.resolve(manifest.key, url);
175
+ if (document.querySelector(`link[data-dxos-plugin-id="${manifest.key}"][href="${resolved}"]`)) continue;
176
+ const link = document.createElement("link");
177
+ link.rel = "stylesheet";
178
+ link.href = resolved;
179
+ link.dataset.dxosPluginId = manifest.key;
180
+ document.head.appendChild(link);
181
+ }
182
+ });
183
+ var loadFromManifest = (manifestUrl, cache) => Effect.gen(function* () {
184
+ log.info("loading remote plugin", { manifestUrl }, {
185
+ "~LogMeta": "~LogMeta",
186
+ F: __dxlog_file,
187
+ L: 234,
188
+ S: this
189
+ });
190
+ const manifest = yield* fetchManifest(manifestUrl).pipe(Effect.mapError((cause) => new RemotePluginLoadError({
191
+ context: {
192
+ locator: manifestUrl,
193
+ reason: "manifest-error"
194
+ },
195
+ cause
196
+ })));
197
+ const wrapCacheError = Effect.mapError((cause) => new RemotePluginLoadError({
198
+ context: {
199
+ locator: manifestUrl,
200
+ reason: "cache-error"
201
+ },
202
+ cause
203
+ }));
204
+ if (!manifest.dev) {
205
+ const cachedUrls = manifest.assetUrls.indexOf(manifestUrl) === -1 ? [manifestUrl, ...manifest.assetUrls] : manifest.assetUrls;
206
+ yield* cache.cache(manifest.key, cachedUrls).pipe(wrapCacheError);
207
+ }
208
+ const entryUrl = manifest.dev ? manifest.entryUrl : yield* cache.resolve(manifest.key, manifest.entryUrl).pipe(wrapCacheError);
209
+ const plugin = normalizePluginExport(yield* Effect.tryPromise({
210
+ try: () => import(
211
+ /* @vite-ignore */
212
+ entryUrl
213
+ ),
214
+ catch: (cause) => new RemotePluginLoadError({
215
+ context: {
216
+ locator: manifestUrl,
217
+ reason: "import-failed"
218
+ },
219
+ cause
220
+ })
221
+ }));
222
+ if (!plugin.meta.profile.key || !plugin.meta.profile.name) return yield* Effect.fail(new RemotePluginLoadError({ context: {
223
+ locator: manifestUrl,
224
+ reason: "meta-missing"
225
+ } }));
226
+ if (plugin.meta.profile.key !== manifest.key) return yield* Effect.fail(new RemotePluginLoadError({ context: {
227
+ locator: manifestUrl,
228
+ reason: "meta-mismatch",
229
+ metaId: plugin.meta.profile.key,
230
+ manifestId: manifest.key
231
+ } }));
232
+ if (!manifest.dev) yield* loadStylesheets(manifest, cache).pipe(wrapCacheError);
233
+ return {
234
+ plugin,
235
+ manifest
236
+ };
237
+ });
238
+ /**
239
+ * Preloads previously persisted remote plugins from storage. Per-entry failures
240
+ * are logged and swallowed — the returned effect always succeeds with whichever
241
+ * plugins loaded cleanly, so a single bad entry can't block the host's startup.
242
+ */
243
+ var preload = (options = {}) => Effect.gen(function* () {
244
+ const storage = options.storage ?? defaultStorage();
245
+ const key = options.key ?? DEFAULT_KEY;
246
+ const cache = options.cache ?? noop();
247
+ const onPluginLoaded = options.onPluginLoaded;
248
+ const entries = getPersistedRemotePlugins(storage, key);
249
+ if (entries.length === 0) return [];
250
+ log.info("preloading remote plugins", { count: entries.length }, {
251
+ "~LogMeta": "~LogMeta",
252
+ F: __dxlog_file,
253
+ L: 310,
254
+ S: this
255
+ });
256
+ const total = entries.length;
257
+ let loaded = 0;
258
+ return (yield* Effect.all(entries.map((entry) => loadFromManifest(entry.url, cache).pipe(Effect.tapError((error) => Effect.sync(() => log.warn("failed to preload remote plugin", {
259
+ entry,
260
+ error
261
+ }, {
262
+ "~LogMeta": "~LogMeta",
263
+ F: __dxlog_file,
264
+ L: 316,
265
+ S: this
266
+ }))), Effect.option, Effect.tap(() => Effect.sync(() => {
267
+ loaded += 1;
268
+ }).pipe(Effect.andThen(Effect.try(() => onPluginLoaded?.(loaded, total))), Effect.tapError((error) => Effect.sync(() => log.warn("onPluginLoaded threw", {
269
+ loaded,
270
+ total,
271
+ error
272
+ }, {
273
+ "~LogMeta": "~LogMeta",
274
+ F: __dxlog_file,
275
+ L: 328,
276
+ S: this
277
+ }))), Effect.ignore)))), { concurrency: "unbounded" })).flatMap((result) => Option.match(result, {
278
+ onNone: () => [],
279
+ onSome: ({ plugin }) => [plugin]
280
+ }));
281
+ });
282
+ /**
283
+ * Creates a plugin loader that resolves built-in plugins by ID or loads remote plugins from URLs.
284
+ *
285
+ * Remote URLs must point at a plugin manifest (`plugin.json`). The loader fetches the manifest,
286
+ * eagerly persists every declared asset via the configured `PluginAssetCache`, then dynamic-imports
287
+ * the entry module.
288
+ */
289
+ var make = (builtinPlugins, options = {}) => {
290
+ const storage = options.storage ?? defaultStorage();
291
+ const key = options.key ?? DEFAULT_KEY;
292
+ const cache = options.cache ?? noop();
293
+ return (locator) => Effect.gen(function* () {
294
+ const builtin = builtinPlugins.find((plugin) => plugin.meta.profile.key === locator);
295
+ if (builtin) return { plugin: builtin };
296
+ if (!isUrl(locator)) return yield* Effect.fail(new RemotePluginLoadError({ context: {
297
+ locator,
298
+ reason: "invalid-locator"
299
+ } }));
300
+ const { plugin, manifest } = yield* loadFromManifest(locator, cache);
301
+ if (!manifest.dev) {
302
+ if (builtinPlugins.find((existing) => existing.meta.profile.key === plugin.meta.profile.key)) return yield* Effect.fail(new RemotePluginLoadError({ context: {
303
+ locator,
304
+ reason: "duplicate-id",
305
+ id: plugin.meta.profile.key
306
+ } }));
307
+ persistRemotePlugin(storage, key, {
308
+ id: plugin.meta.profile.key,
309
+ url: locator
310
+ });
311
+ }
312
+ return {
313
+ plugin,
314
+ dev: manifest.dev
315
+ };
316
+ });
317
+ };
318
+ /**
319
+ * Removes a previously installed remote plugin: drops the persisted entry, evicts cached
320
+ * assets, and removes any stylesheet `<link>` tags that {@link loadFromManifest} appended.
321
+ *
322
+ * Cache eviction failures are logged and swallowed — the persisted entry has already been
323
+ * dropped so the user-visible state is consistent regardless of whether the platform
324
+ * cache cooperated.
325
+ */
326
+ var uninstall = (pluginId, options = {}) => Effect.gen(function* () {
327
+ const storage = options.storage ?? defaultStorage();
328
+ const key = options.key ?? DEFAULT_KEY;
329
+ const cache = options.cache ?? noop();
330
+ removePersistedRemotePlugin(storage, key, pluginId);
331
+ if (typeof document !== "undefined") document.querySelectorAll(`link[data-dxos-plugin-id="${pluginId}"]`).forEach((node) => node.remove());
332
+ yield* cache.evict(pluginId).pipe(Effect.tapError((error) => Effect.sync(() => log.warn("failed to evict plugin assets", {
333
+ pluginId,
334
+ error
335
+ }, {
336
+ "~LogMeta": "~LogMeta",
337
+ F: __dxlog_file,
338
+ L: 403,
339
+ S: this
340
+ }))), Effect.ignore);
341
+ });
342
+ //#endregion
343
+ export { make as a, setRemoteEntries as c, isLocalUrl as i, uninstall as l, getInstalledVersion as n, preload as o, getRemoteEntries as r, setInstalledVersion as s, RemotePluginLoadError as t, url_loader_exports as u };
344
+
345
+ //# sourceMappingURL=chunk-url-loader.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-url-loader.mjs","names":["Plugin.isPlugin","PluginManifest.fetchManifest","PluginAssetCache.noop"],"sources":["../../src/core/url-loader.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\n\nimport { BaseError } from '@dxos/errors';\nimport { log } from '@dxos/log';\n\nimport * as PluginAssetCache from './plugin-asset-cache.ts';\nimport * as PluginManifest from './plugin-manifest.ts';\nimport * as Plugin from './plugin.ts';\n\nconst DEFAULT_KEY = 'org.dxos.composer.remote-plugins';\n\n/**\n * Tagged error for any failure during remote plugin loading. Construction sites\n * set `context.locator` and `context.reason` (one of `'invalid-locator' |\n * 'manifest-error' | 'cache-error' | 'import-failed' | 'meta-missing' |\n * 'meta-mismatch' | 'duplicate-id'`) so handlers can route on the failure mode.\n */\nexport class RemotePluginLoadError extends BaseError.extend('RemotePluginLoadError', 'Failed to load remote plugin') {}\n\n/**\n * Abstraction over key-value storage (defaults to localStorage).\n */\nexport type Storage = {\n get(key: string): string | null;\n set(key: string, value: string): void;\n};\n\n/**\n * Options for configuring the URL loader.\n */\nexport type Options = {\n storage?: Storage;\n key?: string;\n /**\n * Per-platform offline asset cache. Defaults to a no-op cache (no offline support).\n */\n cache?: PluginAssetCache.Cache;\n};\n\n/**\n * Options for the preload entry point. Adds an optional progress hook so hosts\n * can drive a boot-loader counter (`Loading plugins (3/12)…`) as remote plugin\n * manifests resolve. Resolution order is *not* deterministic — each entry races\n * its own network fetch — so callers should treat `loaded` as a count, not an\n * index. Failures are still swallowed; `loaded` advances on both success and\n * recoverable failure so the counter always reaches `total`.\n */\nexport type PreloadOptions = Options & {\n onPluginLoaded?: (loaded: number, total: number) => void;\n};\n\n/**\n * Persisted record of a remote plugin that has been loaded previously.\n *\n * `url` is the URL of the plugin manifest (`plugin.json`), not the entry module.\n */\nexport type RemotePluginView = {\n id: string;\n url: string;\n /** Installed version string, e.g. `v1.0.0`. Populated after install from a community catalog entry. */\n version?: string;\n};\n\nconst defaultStorage = (): Storage => ({\n get: (key) => localStorage.getItem(key),\n set: (key, value) => localStorage.setItem(key, value),\n});\n\nconst getPersistedRemotePlugins = (storage: Storage, key: string): RemotePluginView[] => {\n try {\n const parsed: unknown = JSON.parse(storage.get(key) ?? '[]');\n if (!Array.isArray(parsed)) {\n return [];\n }\n return parsed.filter(\n (entry): entry is RemotePluginView =>\n typeof entry === 'object' &&\n entry !== null &&\n typeof entry.id === 'string' &&\n typeof entry.url === 'string' &&\n (entry.version === undefined || typeof entry.version === 'string'),\n );\n } catch {\n return [];\n }\n};\n\nconst persistRemotePlugin = (storage: Storage, key: string, entry: RemotePluginView): void => {\n try {\n const entries = getPersistedRemotePlugins(storage, key).filter((existing) => existing.id !== entry.id);\n entries.push(entry);\n storage.set(key, JSON.stringify(entries));\n } catch (error) {\n log.warn('failed to persist remote plugin entry', { entry, error });\n }\n};\n\nconst removePersistedRemotePlugin = (storage: Storage, key: string, pluginId: string): void => {\n try {\n const entries = getPersistedRemotePlugins(storage, key).filter((existing) => existing.id !== pluginId);\n storage.set(key, JSON.stringify(entries));\n } catch (error) {\n log.warn('failed to remove remote plugin entry', { pluginId, error });\n }\n};\n\nconst isUrl = (locator: string): boolean => {\n try {\n const url = new URL(locator);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n};\n\n/**\n * Returns true when the URL's hostname is the local host (localhost, 127.0.0.1, or ::1).\n */\nexport const isLocalUrl = (locator: string): boolean => {\n try {\n const hostname = new URL(locator).hostname.toLowerCase();\n // WHATWG URL returns '::1' without brackets in Node; some browsers return '[::1]'.\n return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1' || hostname === '[::1]';\n } catch {\n return false;\n }\n};\n\n/**\n * Returns the list of remote plugin entries previously persisted by {@link make}.\n * Useful for UI code that needs to know which loaded plugins were installed from a URL\n * (e.g. to surface a tag on remote or localhost-hosted plugins).\n */\nexport const getRemoteEntries = (options: Options = {}): readonly RemotePluginView[] => {\n const storage = options.storage ?? defaultStorage();\n const key = options.key ?? DEFAULT_KEY;\n return getPersistedRemotePlugins(storage, key);\n};\n\n/**\n * Replaces the persisted remote plugin entries wholesale. Entries are read during {@link preload},\n * so a replacement takes effect on the next reload.\n */\nexport const setRemoteEntries = (entries: readonly RemotePluginView[], options: Options = {}): void => {\n const storage = options.storage ?? defaultStorage();\n const key = options.key ?? DEFAULT_KEY;\n try {\n storage.set(key, JSON.stringify(entries));\n } catch (error) {\n log.warn('failed to replace remote plugin entries', { error });\n }\n};\n\n/**\n * Updates the persisted installed version for an already-stored remote plugin entry.\n * Does nothing if the plugin has not been persisted yet.\n */\nexport const setInstalledVersion = (id: string, version: string, options: Options = {}): void => {\n const storage = options.storage ?? defaultStorage();\n const key = options.key ?? DEFAULT_KEY;\n const entries = getPersistedRemotePlugins(storage, key);\n const index = entries.findIndex((entry) => entry.id === id);\n if (index === -1) {\n return;\n }\n entries[index] = { ...entries[index], version };\n try {\n storage.set(key, JSON.stringify(entries));\n } catch (error) {\n log.warn('failed to update installed version for remote plugin', { id, version, error });\n }\n};\n\n/**\n * Returns the installed version string for the given plugin id, or `undefined` if\n * the plugin was installed without version tracking (legacy install) or is not found.\n */\nexport const getInstalledVersion = (id: string, options: Options = {}): string | undefined => {\n const storage = options.storage ?? defaultStorage();\n const key = options.key ?? DEFAULT_KEY;\n return getPersistedRemotePlugins(storage, key).find((entry) => entry.id === id)?.version;\n};\n\nconst normalizePluginExport = (mod: Record<string, unknown>): Plugin.Plugin => {\n const exported = mod.default;\n if (Plugin.isPlugin(exported)) {\n return exported;\n }\n if (typeof exported === 'function') {\n const result = (exported as () => unknown)();\n if (Plugin.isPlugin(result)) {\n return result;\n }\n }\n throw new Error('Remote module default export is not a Plugin or a zero-arg plugin factory.');\n};\n\n/**\n * Loads stylesheets declared in the manifest by appending `<link rel=\"stylesheet\">` elements to the host document.\n * Each link is tagged with `data-dxos-plugin-id` so `uninstall` can clean them up.\n */\nconst loadStylesheets = (\n manifest: PluginManifest.ResolvedManifest,\n cache: PluginAssetCache.Cache,\n): Effect.Effect<void, PluginAssetCache.PluginAssetCacheError> =>\n Effect.gen(function* () {\n if (typeof document === 'undefined') {\n return;\n }\n const cssUrls = manifest.assetUrls.filter((url) => url.endsWith('.css'));\n for (const url of cssUrls) {\n const resolved = yield* cache.resolve(manifest.key, url);\n if (document.querySelector(`link[data-dxos-plugin-id=\"${manifest.key}\"][href=\"${resolved}\"]`)) {\n continue;\n }\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = resolved;\n link.dataset.dxosPluginId = manifest.key;\n document.head.appendChild(link);\n }\n });\n\nconst loadFromManifest = (\n manifestUrl: string,\n cache: PluginAssetCache.Cache,\n): Effect.Effect<{ plugin: Plugin.Plugin; manifest: PluginManifest.ResolvedManifest }, RemotePluginLoadError> =>\n Effect.gen(function* () {\n log.info('loading remote plugin', { manifestUrl });\n const manifest = yield* PluginManifest.fetchManifest(manifestUrl).pipe(\n Effect.mapError(\n (cause) => new RemotePluginLoadError({ context: { locator: manifestUrl, reason: 'manifest-error' }, cause }),\n ),\n );\n const wrapCacheError = Effect.mapError(\n (cause: PluginAssetCache.PluginAssetCacheError) =>\n new RemotePluginLoadError({ context: { locator: manifestUrl, reason: 'cache-error' }, cause }),\n );\n // Dev-mode manifests (served by `vite dev` via composerPlugin) skip the offline\n // cache: chunks resolve on demand through the dev server, the asset list isn't\n // enumerable up-front, and CSS arrives via runtime <style> injection rather than\n // static <link> tags.\n if (!manifest.dev) {\n // Cache the manifest URL alongside its declared assets. Without it, `preload` on a\n // subsequent reload would fetch the manifest from the network — and fail when the\n // plugin's host is offline, dropping the plugin from the runtime.\n const cachedUrls =\n manifest.assetUrls.indexOf(manifestUrl) === -1 ? [manifestUrl, ...manifest.assetUrls] : manifest.assetUrls;\n yield* cache.cache(manifest.key, cachedUrls).pipe(wrapCacheError);\n }\n const entryUrl = manifest.dev\n ? manifest.entryUrl\n : yield* cache.resolve(manifest.key, manifest.entryUrl).pipe(wrapCacheError);\n const mod = yield* Effect.tryPromise({\n try: () => import(/* @vite-ignore */ entryUrl),\n catch: (cause) =>\n new RemotePluginLoadError({ context: { locator: manifestUrl, reason: 'import-failed' }, cause }),\n });\n const plugin = normalizePluginExport(mod);\n if (!plugin.meta.profile.key || !plugin.meta.profile.name) {\n return yield* Effect.fail(\n new RemotePluginLoadError({ context: { locator: manifestUrl, reason: 'meta-missing' } }),\n );\n }\n if (plugin.meta.profile.key !== manifest.key) {\n return yield* Effect.fail(\n new RemotePluginLoadError({\n context: {\n locator: manifestUrl,\n reason: 'meta-mismatch',\n metaId: plugin.meta.profile.key,\n manifestId: manifest.key,\n },\n }),\n );\n }\n // Append stylesheets only after the entry imports cleanly and meta validation\n // passes. If we did this earlier and the import or meta checks failed, the\n // `<link>` tags would leak into the host DOM with no plugin to own their\n // teardown — `uninstall` only runs for plugins the manager actually accepted.\n // In dev mode, Vite injects styles at runtime via the module graph, so static\n // <link> tags would duplicate (or 404, since CSS chunks aren't pre-built).\n if (!manifest.dev) {\n yield* loadStylesheets(manifest, cache).pipe(wrapCacheError);\n }\n return { plugin, manifest };\n });\n\n/**\n * Preloads previously persisted remote plugins from storage. Per-entry failures\n * are logged and swallowed — the returned effect always succeeds with whichever\n * plugins loaded cleanly, so a single bad entry can't block the host's startup.\n */\nexport const preload = (options: PreloadOptions = {}): Effect.Effect<Plugin.Plugin[], never> =>\n Effect.gen(function* () {\n const storage = options.storage ?? defaultStorage();\n const key = options.key ?? DEFAULT_KEY;\n const cache = options.cache ?? PluginAssetCache.noop();\n const onPluginLoaded = options.onPluginLoaded;\n\n const entries = getPersistedRemotePlugins(storage, key);\n if (entries.length === 0) {\n return [];\n }\n log.info('preloading remote plugins', { count: entries.length });\n const total = entries.length;\n let loaded = 0;\n const results = yield* Effect.all(\n entries.map((entry) =>\n loadFromManifest(entry.url, cache).pipe(\n Effect.tapError((error) => Effect.sync(() => log.warn('failed to preload remote plugin', { entry, error }))),\n Effect.option,\n // Tick the progress hook on both success and recoverable failure so\n // the counter monotonically reaches `total`. The host-supplied\n // callback is best-effort: any synchronous throw flows through\n // `Effect.try` and gets logged + ignored so a buggy hook can't\n // derail the preload.\n Effect.tap(() =>\n Effect.sync(() => {\n loaded += 1;\n }).pipe(\n Effect.andThen(Effect.try(() => onPluginLoaded?.(loaded, total))),\n Effect.tapError((error) => Effect.sync(() => log.warn('onPluginLoaded threw', { loaded, total, error }))),\n Effect.ignore,\n ),\n ),\n ),\n ),\n { concurrency: 'unbounded' },\n );\n return results.flatMap((result) =>\n Option.match(result, {\n onNone: () => [],\n onSome: ({ plugin }) => [plugin],\n }),\n );\n });\n\n/**\n * Creates a plugin loader that resolves built-in plugins by ID or loads remote plugins from URLs.\n *\n * Remote URLs must point at a plugin manifest (`plugin.json`). The loader fetches the manifest,\n * eagerly persists every declared asset via the configured `PluginAssetCache`, then dynamic-imports\n * the entry module.\n */\nexport const make = (builtinPlugins: Plugin.Plugin[], options: Options = {}) => {\n const storage = options.storage ?? defaultStorage();\n const key = options.key ?? DEFAULT_KEY;\n const cache = options.cache ?? PluginAssetCache.noop();\n\n return (locator: string): Effect.Effect<{ plugin: Plugin.Plugin; dev?: boolean }, RemotePluginLoadError> =>\n Effect.gen(function* () {\n const builtin = builtinPlugins.find((plugin) => plugin.meta.profile.key === locator);\n if (builtin) {\n return { plugin: builtin };\n }\n if (!isUrl(locator)) {\n return yield* Effect.fail(new RemotePluginLoadError({ context: { locator, reason: 'invalid-locator' } }));\n }\n const { plugin, manifest } = yield* loadFromManifest(locator, cache);\n // Production manifests can't collide with a builtin id — that would make\n // the registered plugin permanently inaccessible. Dev manifests are\n // allowed to collide because the manager shadow primitive handles the\n // overlap (dev plugin takes the id slot for the session, original is\n // restored on uninstall or page reload).\n if (!manifest.dev) {\n const duplicate = builtinPlugins.find((existing) => existing.meta.profile.key === plugin.meta.profile.key);\n if (duplicate) {\n return yield* Effect.fail(\n new RemotePluginLoadError({ context: { locator, reason: 'duplicate-id', id: plugin.meta.profile.key } }),\n );\n }\n persistRemotePlugin(storage, key, { id: plugin.meta.profile.key, url: locator });\n }\n return { plugin, dev: manifest.dev };\n });\n};\n\n/**\n * Removes a previously installed remote plugin: drops the persisted entry, evicts cached\n * assets, and removes any stylesheet `<link>` tags that {@link loadFromManifest} appended.\n *\n * Cache eviction failures are logged and swallowed — the persisted entry has already been\n * dropped so the user-visible state is consistent regardless of whether the platform\n * cache cooperated.\n */\nexport const uninstall = (pluginId: string, options: Options = {}): Effect.Effect<void, never> =>\n Effect.gen(function* () {\n const storage = options.storage ?? defaultStorage();\n const key = options.key ?? DEFAULT_KEY;\n const cache = options.cache ?? PluginAssetCache.noop();\n\n removePersistedRemotePlugin(storage, key, pluginId);\n if (typeof document !== 'undefined') {\n document.querySelectorAll(`link[data-dxos-plugin-id=\"${pluginId}\"]`).forEach((node) => node.remove());\n }\n yield* cache.evict(pluginId).pipe(\n Effect.tapError((error) => Effect.sync(() => log.warn('failed to evict plugin assets', { pluginId, error }))),\n Effect.ignore,\n );\n });\n"],"mappings":"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"}
package/dist/lib/cli.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import { a as Service } from "./chunk-capability.mjs";
2
- import { Service as Service$1 } from "./core/plugin.mjs";
2
+ import { c as Service$1 } from "./chunk-plugin.mjs";
3
3
  import { r as make } from "./chunk-plugin-manager.mjs";
4
- import { AtomRegistry, Command as Command$1, Layer as Layer$1, PluginManager } from "./common/capabilities.mjs";
5
- import { CommandsRequested, Startup } from "./common/activation-events.mjs";
4
+ import { i as Layer$1, n as Command$1, t as AtomRegistry, u as PluginManager } from "./chunk-capabilities.mjs";
5
+ import { a as Startup, t as CommandsRequested } from "./chunk-activation-events.mjs";
6
6
  import * as Effect from "effect/Effect";
7
7
  import * as Layer from "effect/Layer";
8
8
  import { invariant } from "@dxos/invariant";
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":[],"sources":["../../src/cli/cli.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Command from 'effect/cli/Command';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\n\nimport { invariant } from '@dxos/invariant';\n\nimport { ActivationEvents, Capabilities } from '../common/index.ts';\nimport { Capability, Plugin, PluginManager } from '../core/index.ts';\n\nconst defaultPluginLoader =\n (plugins: Plugin.Plugin[]): PluginManager.ManagerOptions['pluginLoader'] =>\n (id: string) =>\n Effect.sync(() => {\n const plugin = plugins.find((plugin) => plugin.meta.profile.key === id);\n invariant(plugin, `Plugin not found: ${id}`);\n return { plugin };\n });\n\ntype SubCommands = [Command.Command<any, any, any, any, any>, ...Array<Command.Command<any, any, any, any, any>>];\n\nexport type CreateCliAppOptions = {\n rootCommand: Command.Command<any, any, any, any, any>;\n subCommands?: SubCommands;\n pluginManager?: PluginManager.PluginManager;\n pluginLoader?: PluginManager.ManagerOptions['pluginLoader'];\n plugins?: Plugin.Plugin[];\n enabled?: string[];\n core?: string[];\n safeMode?: boolean;\n};\n\n/**\n * Creates a CLI application with plugin support.\n * Similar to useApp but for CLI environments.\n *\n * @example\n * const plugins = [ClientPluginCLI()];\n * const manager = await createCliApp({ plugins });\n * const commands = manager.capabilities.getAll(Capabilities.Command);\n *\n * @param options.pluginManager Optional existing PluginManager instance.\n * @param options.pluginLoader Function to load plugins by ID.\n * @param options.plugins All plugins available to the application.\n * @param options.enabled Enabled plugins.\n * @param options.core Plugins the CLI pins on (always enabled, never disableable). Defaults to those whose `meta.profile.tags` includes `'system'`.\n * @param options.safeMode Whether to enable safe mode, which disables optional plugins.\n */\nexport const createCliApp = Effect.fn(function* ({\n rootCommand,\n subCommands: subCommandsProp,\n pluginManager: pluginManagerProp,\n pluginLoader: pluginLoaderProp,\n plugins: pluginsProp = [],\n enabled: enabledProp = [],\n core,\n safeMode = false,\n}: CreateCliAppOptions) {\n const plugins = pluginsProp;\n const pluginLoader = pluginLoaderProp ?? defaultPluginLoader(plugins);\n const enabled = safeMode ? [] : enabledProp;\n const manager =\n pluginManagerProp ??\n PluginManager.make({\n pluginLoader,\n plugins,\n enabled,\n core,\n });\n\n manager.capabilities.contribute({\n interface: Capabilities.PluginManager,\n implementation: manager,\n module: 'org.dxos.app-framework.plugin-manager',\n });\n\n manager.capabilities.contribute({\n interface: Capabilities.AtomRegistry,\n implementation: manager.registry,\n module: 'org.dxos.app-framework.atom-registry',\n });\n\n // Activate startup event to load Effect layers.\n yield* manager.activate(ActivationEvents.Startup);\n\n // Awaited, not forked: the command tree below is built from one read of the capability, so a\n // command still activating when that read happens would be missing from the binary's help.\n yield* manager.activate(ActivationEvents.CommandsRequested);\n\n // Gather all layers and merge them into a single layer.\n const layers = manager.capabilities.getAll(Capabilities.Layer);\n const capabilityServiceLayer = Layer.succeed(Capability.Service, manager.capabilities);\n const pluginServiceLayer = Layer.succeed(Plugin.Service, manager);\n const layer = Layer.mergeAll(capabilityServiceLayer, pluginServiceLayer, ...layers);\n\n // Gather all commands and provide them to the root command.\n const pluginCommands = manager.capabilities.getAll(Capabilities.Command);\n const subCommands = subCommandsProp ? [...subCommandsProp, ...pluginCommands] : pluginCommands;\n invariant(subCommands.length > 0, 'No subcommands provided');\n const command = rootCommand.pipe(Command.withSubcommands(subCommands as SubCommands));\n\n return { command, layer };\n});\n"],"mappings":";;;;;;;;;;;AAaA,IAAM,uBACH,aACA,OACC,OAAO,WAAW;CAChB,MAAM,SAAS,QAAQ,MAAM,WAAW,OAAO,KAAK,QAAQ,QAAQ,EAAE;CACtE,UAAU,QAAQ,qBAAqB,MAAG;EAAA,YAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA,KAAA;EAAA,GAAA,CAAA,UAAA,2BAAA;CAAA,CAAC;CAC3C,OAAO,EAAE,OAAO;AAClB,CAAC;;;;;;;;;;;;;;;;;AA+BL,IAAa,eAAe,OAAO,GAAG,WAAW,EAC/C,aACA,aAAa,iBACb,eAAe,mBACf,cAAc,kBACd,SAAS,cAAc,CAAC,GACxB,SAAS,cAAc,CAAC,GACxB,MACA,WAAW,SACW;CACtB,MAAM,UAAU;CAChB,MAAM,eAAe,oBAAoB,oBAAoB,OAAO;CAEpE,MAAM,UACJ,qBACA,KAAmB;EACjB;EACA;EACA,SANY,WAAW,CAAC,IAAI;EAO5B;CACF,CAAC;CAEH,QAAQ,aAAa,WAAW;EAC9B,WAAW;EACX,gBAAgB;EAChB,QAAQ;CACV,CAAC;CAED,QAAQ,aAAa,WAAW;EAC9B,WAAW;EACX,gBAAgB,QAAQ;EACxB,QAAQ;CACV,CAAC;CAGD,OAAO,QAAQ,SAAS,OAAwB;CAIhD,OAAO,QAAQ,SAAS,iBAAkC;CAG1D,MAAM,SAAS,QAAQ,aAAa,OAAO,OAAkB;CAC7D,MAAM,yBAAyB,MAAM,QAAQ,SAAoB,QAAQ,YAAY;CACrF,MAAM,qBAAqB,MAAM,QAAQ,WAAgB,OAAO;CAChE,MAAM,QAAQ,MAAM,SAAS,wBAAwB,oBAAoB,GAAG,MAAM;CAGlF,MAAM,iBAAiB,QAAQ,aAAa,OAAO,SAAoB;CACvE,MAAM,cAAc,kBAAkB,CAAC,GAAG,iBAAiB,GAAG,cAAc,IAAI;CAChF,UAAU,YAAY,SAAS,GAAG,2BAAwB;EAAA,YAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA,CAAA,0BAAA,2BAAA;CAAA,CAAC;CAG3D,OAAO;EAAE,SAFO,YAAY,KAAK,QAAQ,gBAAgB,WAA0B,CAE1E;EAAS;CAAM;AAC1B,CAAC"}
1
+ {"version":3,"file":"cli.mjs","names":["PluginManager.make","Capabilities.PluginManager","Capabilities.AtomRegistry","ActivationEvents.Startup","ActivationEvents.CommandsRequested","Capabilities.Layer","Capability.Service","Plugin.Service","Capabilities.Command"],"sources":["../../src/cli/cli.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Command from 'effect/cli/Command';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\n\nimport { invariant } from '@dxos/invariant';\n\nimport { ActivationEvents, Capabilities } from '../common/index.ts';\nimport { Capability, Plugin, PluginManager } from '../core/index.ts';\n\nconst defaultPluginLoader =\n (plugins: Plugin.Plugin[]): PluginManager.ManagerOptions['pluginLoader'] =>\n (id: string) =>\n Effect.sync(() => {\n const plugin = plugins.find((plugin) => plugin.meta.profile.key === id);\n invariant(plugin, `Plugin not found: ${id}`);\n return { plugin };\n });\n\ntype SubCommands = [Command.Command<any, any, any, any, any>, ...Array<Command.Command<any, any, any, any, any>>];\n\nexport type CreateCliAppOptions = {\n rootCommand: Command.Command<any, any, any, any, any>;\n subCommands?: SubCommands;\n pluginManager?: PluginManager.PluginManager;\n pluginLoader?: PluginManager.ManagerOptions['pluginLoader'];\n plugins?: Plugin.Plugin[];\n enabled?: string[];\n core?: string[];\n safeMode?: boolean;\n};\n\n/**\n * Creates a CLI application with plugin support.\n * Similar to useApp but for CLI environments.\n *\n * @example\n * const plugins = [ClientPluginCLI()];\n * const manager = await createCliApp({ plugins });\n * const commands = manager.capabilities.getAll(Capabilities.Command);\n *\n * @param options.pluginManager Optional existing PluginManager instance.\n * @param options.pluginLoader Function to load plugins by ID.\n * @param options.plugins All plugins available to the application.\n * @param options.enabled Enabled plugins.\n * @param options.core Plugins the CLI pins on (always enabled, never disableable). Defaults to those whose `meta.profile.tags` includes `'system'`.\n * @param options.safeMode Whether to enable safe mode, which disables optional plugins.\n */\nexport const createCliApp = Effect.fn(function* ({\n rootCommand,\n subCommands: subCommandsProp,\n pluginManager: pluginManagerProp,\n pluginLoader: pluginLoaderProp,\n plugins: pluginsProp = [],\n enabled: enabledProp = [],\n core,\n safeMode = false,\n}: CreateCliAppOptions) {\n const plugins = pluginsProp;\n const pluginLoader = pluginLoaderProp ?? defaultPluginLoader(plugins);\n const enabled = safeMode ? [] : enabledProp;\n const manager =\n pluginManagerProp ??\n PluginManager.make({\n pluginLoader,\n plugins,\n enabled,\n core,\n });\n\n manager.capabilities.contribute({\n interface: Capabilities.PluginManager,\n implementation: manager,\n module: 'org.dxos.app-framework.plugin-manager',\n });\n\n manager.capabilities.contribute({\n interface: Capabilities.AtomRegistry,\n implementation: manager.registry,\n module: 'org.dxos.app-framework.atom-registry',\n });\n\n // Activate startup event to load Effect layers.\n yield* manager.activate(ActivationEvents.Startup);\n\n // Awaited, not forked: the command tree below is built from one read of the capability, so a\n // command still activating when that read happens would be missing from the binary's help.\n yield* manager.activate(ActivationEvents.CommandsRequested);\n\n // Gather all layers and merge them into a single layer.\n const layers = manager.capabilities.getAll(Capabilities.Layer);\n const capabilityServiceLayer = Layer.succeed(Capability.Service, manager.capabilities);\n const pluginServiceLayer = Layer.succeed(Plugin.Service, manager);\n const layer = Layer.mergeAll(capabilityServiceLayer, pluginServiceLayer, ...layers);\n\n // Gather all commands and provide them to the root command.\n const pluginCommands = manager.capabilities.getAll(Capabilities.Command);\n const subCommands = subCommandsProp ? [...subCommandsProp, ...pluginCommands] : pluginCommands;\n invariant(subCommands.length > 0, 'No subcommands provided');\n const command = rootCommand.pipe(Command.withSubcommands(subCommands as SubCommands));\n\n return { command, layer };\n});\n"],"mappings":";;;;;;;;;;;AAaA,IAAM,uBACH,aACA,OACC,OAAO,WAAW;CAChB,MAAM,SAAS,QAAQ,MAAM,WAAW,OAAO,KAAK,QAAQ,QAAQ,EAAE;CACtE,UAAU,QAAQ,qBAAqB,MAAG;EAAA,YAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA,KAAA;EAAA,GAAA,CAAA,UAAA,2BAAA;CAAA,CAAC;CAC3C,OAAO,EAAE,OAAO;AAClB,CAAC;;;;;;;;;;;;;;;;;AA+BL,IAAa,eAAe,OAAO,GAAG,WAAW,EAC/C,aACA,aAAa,iBACb,eAAe,mBACf,cAAc,kBACd,SAAS,cAAc,CAAC,GACxB,SAAS,cAAc,CAAC,GACxB,MACA,WAAW,SACW;CACtB,MAAM,UAAU;CAChB,MAAM,eAAe,oBAAoB,oBAAoB,OAAO;CAEpE,MAAM,UACJ,qBACAA,KAAmB;EACjB;EACA;EACA,SANY,WAAW,CAAC,IAAI;EAO5B;CACF,CAAC;CAEH,QAAQ,aAAa,WAAW;EAC9B,WAAWC;EACX,gBAAgB;EAChB,QAAQ;CACV,CAAC;CAED,QAAQ,aAAa,WAAW;EAC9B,WAAWC;EACX,gBAAgB,QAAQ;EACxB,QAAQ;CACV,CAAC;CAGD,OAAO,QAAQ,SAASC,OAAwB;CAIhD,OAAO,QAAQ,SAASC,iBAAkC;CAG1D,MAAM,SAAS,QAAQ,aAAa,OAAOC,OAAkB;CAC7D,MAAM,yBAAyB,MAAM,QAAQC,SAAoB,QAAQ,YAAY;CACrF,MAAM,qBAAqB,MAAM,QAAQC,WAAgB,OAAO;CAChE,MAAM,QAAQ,MAAM,SAAS,wBAAwB,oBAAoB,GAAG,MAAM;CAGlF,MAAM,iBAAiB,QAAQ,aAAa,OAAOC,SAAoB;CACvE,MAAM,cAAc,kBAAkB,CAAC,GAAG,iBAAiB,GAAG,cAAc,IAAI;CAChF,UAAU,YAAY,SAAS,GAAG,2BAAwB;EAAA,YAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA,CAAA,0BAAA,2BAAA;CAAA,CAAC;CAG3D,OAAO;EAAE,SAFO,YAAY,KAAK,QAAQ,gBAAgB,WAA0B,CAE1E;EAAS;CAAM;AAC1B,CAAC"}
@@ -1,19 +1 @@
1
- import { t as __exportAll } from "../chunk-rolldown-runtime.mjs";
2
- //#region src/common/Role.ts
3
- var Role_exports = /* @__PURE__ */ __exportAll({ make: () => make });
4
- /**
5
- * Mints a typed role token. The NSID is validated at compile time via
6
- * {@link DXN.Name}: the final segment must be camelCase (no hyphens).
7
- * Dynamic NSIDs (template-literal / runtime strings) are validated at runtime.
8
- *
9
- * Identity is structural; all tokens with the same `role` string are
10
- * interchangeable at runtime.
11
- */
12
- var make = (nsid) => {
13
- if (typeof nsid !== "string" || !/^[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\.[a-zA-Z][a-zA-Z0-9]{0,62})$/.test(nsid)) throw new Error(`Invalid role NSID: "${nsid}". Must be a dotted name with a camelCase final segment (no hyphens in the last segment).`);
14
- return { role: nsid };
15
- };
16
- //#endregion
17
- export { make, Role_exports as t };
18
-
19
- //# sourceMappingURL=Role.mjs.map
1
+ export { n as make } from "../chunk-Role.mjs";
@@ -1,57 +1 @@
1
- import { t as __exportAll } from "../chunk-rolldown-runtime.mjs";
2
- import { Idle as Idle$1, Startup as Startup$1, make } from "../core/activation-event.mjs";
3
- //#region src/common/activation-events.ts
4
- var activation_events_exports = /* @__PURE__ */ __exportAll({
5
- CommandsRequested: () => CommandsRequested,
6
- Idle: () => Idle,
7
- SpaceTemplatesRequested: () => SpaceTemplatesRequested,
8
- Startup: () => Startup,
9
- SurfacesRequested: () => SurfacesRequested
10
- });
11
- /**
12
- * Fired when the app is started.
13
- * Defined in core; see {@link ActivationEvent$.Startup}.
14
- */
15
- var Startup = Startup$1;
16
- /**
17
- * Demand signal for React surfaces, keyed by role NSID. Fired when a `Surface` for the role
18
- * first renders (and by availability checks that miss), so surface modules gated on their bound
19
- * roles load exactly when a screen region that can host them appears.
20
- */
21
- var SurfacesRequested = (role) => make("org.dxos.app-framework.event.surfacesRequested", role);
22
- /**
23
- * Demand signal for CLI commands. Fired by whoever is about to build a command tree — the `dx`
24
- * binary through {@link createCliApp}, the devtools terminal when its panel mounts — so command
25
- * modules load when someone can actually run a command.
26
- *
27
- * A command tree is read ONCE, so this must be fired and awaited before the read: a command
28
- * registered afterwards is simply absent, and `dx space list` falls through to the root help
29
- * rather than failing anywhere near the cause.
30
- */
31
- var CommandsRequested = make("org.dxos.app-framework.event.commandsRequested");
32
- /**
33
- * Demand signal for space templates. Fired by whoever is about to offer a list of them — the create
34
- * space dialog, and the debug plugin's space generator when its panel mounts.
35
- *
36
- * Template content is bulky, so the modules carrying it are gated here rather than contributing at
37
- * startup. Like a command tree, the list is read once: fire and await this before reading it.
38
- */
39
- var SpaceTemplatesRequested = make("org.dxos.app-framework.event.spaceTemplatesRequested");
40
- /**
41
- * Fired once by the host at main-thread idle after the app is interactive.
42
- *
43
- * For REGISTRATION contributions only — graph builders, operation handler sets, settings: the
44
- * app-wide indexes a user can reach from anywhere (the navtree, the operation registry, a
45
- * settings read) and which therefore no single surface can gate. A feature's own modules ride
46
- * its plugin start event, fired when its surface renders; putting a feature body here instead
47
- * is what turned the former `DeferredStartup` into a second startup pass.
48
- *
49
- * This is also what omitting `activatesOn` normalizes to, so a module that must run at boot has
50
- * to say `activatesOn: ActivationEvents.Startup` explicitly. Defined in core; see
51
- * {@link ActivationEvent$.Idle}.
52
- */
53
- var Idle = Idle$1;
54
- //#endregion
55
- export { CommandsRequested, Idle, SpaceTemplatesRequested, Startup, SurfacesRequested, activation_events_exports as t };
56
-
57
- //# sourceMappingURL=activation-events.mjs.map
1
+ export { t as CommandsRequested, n as Idle, r as PluginAssetsRequested, i as SpaceTemplatesRequested, a as Startup, o as SurfacesRequested } from "../chunk-activation-events.mjs";