@dxos/plugin-debug 0.7.5-main.9d26e3a → 0.7.5-main.9d2a38b

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 (64) hide show
  1. package/dist/lib/browser/{DebugApp-HCHR6GKO.mjs → DebugApp-LQHFFK3Y.mjs} +4 -2
  2. package/dist/lib/browser/{DebugApp-HCHR6GKO.mjs.map → DebugApp-LQHFFK3Y.mjs.map} +3 -3
  3. package/dist/lib/browser/{DebugSpace-V3K3PQP6.mjs → DebugSpace-4JHYA7FG.mjs} +7 -5
  4. package/dist/lib/browser/{DebugSpace-V3K3PQP6.mjs.map → DebugSpace-4JHYA7FG.mjs.map} +3 -3
  5. package/dist/lib/browser/{SpaceGenerator-Y2NXBQVR.mjs → SpaceGenerator-NJCG57CU.mjs} +7 -5
  6. package/dist/lib/browser/{SpaceGenerator-Y2NXBQVR.mjs.map → SpaceGenerator-NJCG57CU.mjs.map} +3 -3
  7. package/dist/lib/browser/app-graph-builder-FXELWOFS.mjs +177 -0
  8. package/dist/lib/browser/app-graph-builder-FXELWOFS.mjs.map +7 -0
  9. package/dist/lib/browser/{chunk-CAENAAHY.mjs → chunk-I3ON45JK.mjs} +3 -3
  10. package/dist/lib/browser/chunk-I3ON45JK.mjs.map +7 -0
  11. package/dist/lib/browser/{chunk-6CGQHKET.mjs → chunk-P7GHHMDB.mjs} +1 -1
  12. package/dist/lib/browser/chunk-P7GHHMDB.mjs.map +7 -0
  13. package/dist/lib/browser/index.mjs +66 -712
  14. package/dist/lib/browser/index.mjs.map +4 -4
  15. package/dist/lib/browser/meta.json +1 -1
  16. package/dist/lib/browser/react-context-OZU6J7G3.mjs +37 -0
  17. package/dist/lib/browser/react-context-OZU6J7G3.mjs.map +7 -0
  18. package/dist/lib/browser/react-surface-5GNO6NWP.mjs +468 -0
  19. package/dist/lib/browser/react-surface-5GNO6NWP.mjs.map +7 -0
  20. package/dist/lib/browser/settings-JCZUA643.mjs +25 -0
  21. package/dist/lib/browser/settings-JCZUA643.mjs.map +7 -0
  22. package/dist/types/src/DebugPlugin.d.ts +1 -2
  23. package/dist/types/src/DebugPlugin.d.ts.map +1 -1
  24. package/dist/types/src/capabilities/app-graph-builder.d.ts +181 -0
  25. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  26. package/dist/types/src/capabilities/index.d.ts +185 -0
  27. package/dist/types/src/capabilities/index.d.ts.map +1 -0
  28. package/dist/types/src/capabilities/react-context.d.ts +8 -0
  29. package/dist/types/src/capabilities/react-context.d.ts.map +1 -0
  30. package/dist/types/src/capabilities/react-surface.d.ts +4 -0
  31. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  32. package/dist/types/src/capabilities/settings.d.ts +4 -0
  33. package/dist/types/src/capabilities/settings.d.ts.map +1 -0
  34. package/dist/types/src/components/DebugStatus.d.ts.map +1 -1
  35. package/dist/types/src/index.d.ts +1 -2
  36. package/dist/types/src/index.d.ts.map +1 -1
  37. package/dist/types/src/meta.d.ts +1 -2
  38. package/dist/types/src/meta.d.ts.map +1 -1
  39. package/dist/types/src/types.d.ts +0 -3
  40. package/dist/types/src/types.d.ts.map +1 -1
  41. package/dist/types/tsconfig.tsbuildinfo +1 -1
  42. package/package.json +43 -51
  43. package/src/DebugPlugin.tsx +58 -345
  44. package/src/capabilities/app-graph-builder.ts +177 -0
  45. package/src/capabilities/index.ts +10 -0
  46. package/src/capabilities/react-context.tsx +38 -0
  47. package/src/capabilities/react-surface.tsx +138 -0
  48. package/src/capabilities/settings.ts +18 -0
  49. package/src/components/DebugApp/DebugApp.tsx +1 -1
  50. package/src/components/DebugSettings.tsx +4 -4
  51. package/src/components/DebugSpace/DebugSpace.tsx +1 -1
  52. package/src/components/DebugStatus.tsx +3 -9
  53. package/src/components/SpaceGenerator/ObjectGenerator.tsx +3 -3
  54. package/src/components/SpaceGenerator/SpaceGenerator.tsx +1 -1
  55. package/src/index.ts +1 -4
  56. package/src/meta.ts +1 -1
  57. package/src/types.ts +0 -13
  58. package/dist/lib/browser/chunk-6CGQHKET.mjs.map +0 -7
  59. package/dist/lib/browser/chunk-CAENAAHY.mjs.map +0 -7
  60. package/dist/lib/browser/meta.mjs +0 -9
  61. package/dist/lib/browser/meta.mjs.map +0 -7
  62. package/dist/types/src/components/DebugSurface.d.ts +0 -9
  63. package/dist/types/src/components/DebugSurface.d.ts.map +0 -1
  64. package/src/components/DebugSurface.tsx +0 -55
@@ -2,355 +2,68 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import React, { useCallback, useEffect, useState } from 'react';
6
-
7
- import {
8
- createIntent,
9
- createSurface,
10
- definePlugin,
11
- parseGraphPlugin,
12
- parseIntentPlugin,
13
- parseMetadataResolverPlugin,
14
- parseSettingsPlugin,
15
- resolvePlugin,
16
- } from '@dxos/app-framework';
17
- import { Timer } from '@dxos/async';
18
- import { Devtools } from '@dxos/devtools';
19
- import { invariant } from '@dxos/invariant';
20
- import { parseClientPlugin } from '@dxos/plugin-client/types';
21
- import { createExtension, Graph, type Node, toSignal } from '@dxos/plugin-graph';
22
- import { memoizeQuery, SpaceAction } from '@dxos/plugin-space';
23
- import { CollectionType } from '@dxos/plugin-space/types';
5
+ import { Capabilities, contributes, defineModule, definePlugin, Events } from '@dxos/app-framework';
6
+ import { DeckCapabilities } from '@dxos/plugin-deck';
24
7
  import { type Client } from '@dxos/react-client';
25
- import {
26
- create,
27
- getTypename,
28
- isEchoObject,
29
- isSpace,
30
- parseId,
31
- type ReactiveEchoObject,
32
- type ReactiveObject,
33
- type Space,
34
- SpaceState,
35
- } from '@dxos/react-client/echo';
36
8
 
37
- import {
38
- DebugApp,
39
- DebugObjectPanel,
40
- DebugSettings,
41
- DebugSpace,
42
- DebugStatus,
43
- SpaceGenerator,
44
- Wireframe,
45
- } from './components';
46
- import meta, { DEBUG_PLUGIN } from './meta';
9
+ import { AppGraphBuilder, DebugSettings, ReactContext, ReactSurface } from './capabilities';
10
+ import { DEBUG_PLUGIN, meta } from './meta';
47
11
  import translations from './translations';
48
- import { DebugContext, type DebugPluginProvides, type DebugSettingsProps, DebugSettingsSchema } from './types';
49
-
50
- type SpaceDebug = {
51
- type: string;
52
- space: Space;
53
- };
54
12
 
55
- type GraphDebug = {
56
- graph: Graph;
13
+ export const DebugPlugin = () => {
14
+ setupDevtools();
15
+
16
+ return definePlugin(meta, [
17
+ defineModule({
18
+ id: `${meta.id}/module/settings`,
19
+ activatesOn: Events.SetupSettings,
20
+ activate: DebugSettings,
21
+ }),
22
+ defineModule({
23
+ id: `${meta.id}/module/translations`,
24
+ activatesOn: Events.SetupTranslations,
25
+ activate: () => contributes(Capabilities.Translations, translations),
26
+ }),
27
+ defineModule({
28
+ id: `${meta.id}/module/complementary-panel`,
29
+ activatesOn: Events.Startup,
30
+ activate: () =>
31
+ contributes(DeckCapabilities.ComplementaryPanel, {
32
+ id: 'debug',
33
+ label: ['debug label', { ns: DEBUG_PLUGIN }],
34
+ icon: 'ph--bug--regular',
35
+ }),
36
+ }),
37
+ defineModule({
38
+ id: `${meta.id}/module/react-context`,
39
+ activatesOn: Events.Startup,
40
+ activate: ReactContext,
41
+ }),
42
+ defineModule({
43
+ id: `${meta.id}/module/react-surface`,
44
+ activatesOn: Events.Startup,
45
+ activate: ReactSurface,
46
+ }),
47
+ defineModule({
48
+ id: `${meta.id}/module/app-graph-builder`,
49
+ activatesOn: Events.SetupAppGraph,
50
+ activate: AppGraphBuilder,
51
+ }),
52
+ ]);
57
53
  };
58
54
 
59
- const isSpaceDebug = (data: any): data is SpaceDebug => data.type === `${DEBUG_PLUGIN}/space` && isSpace(data.space);
60
- const isGraphDebug = (data: any): data is GraphDebug => data.graph instanceof Graph;
61
-
62
- export const DebugPlugin = definePlugin<DebugPluginProvides>((context) => {
63
- const settings = create<DebugSettingsProps>({
64
- debug: true,
65
- devtools: true,
66
- });
67
-
68
- return {
69
- meta,
70
- ready: async ({ plugins }) => {
71
- context.init(plugins);
72
- context.resolvePlugin(parseSettingsPlugin).provides.settingsStore.createStore({
73
- schema: DebugSettingsSchema,
74
- prefix: DEBUG_PLUGIN,
75
- value: settings,
76
- });
77
-
78
- // TODO(burdon): Remove hacky dependency on global variable.
79
- // Used to test how composer handles breaking protocol changes.
80
- const composer = (window as any).composer;
81
- composer.changeStorageVersionInMetadata = async (version: number) => {
82
- const { changeStorageVersionInMetadata } = await import('@dxos/echo-pipeline/testing');
83
- const { createStorageObjects } = await import('@dxos/client-services');
84
- const client: Client = (window as any).dxos.client;
85
- const config = client.config;
86
- await client.destroy();
87
- const { storage } = createStorageObjects(config.values?.runtime?.client?.storage ?? {});
88
- await changeStorageVersionInMetadata(storage, version);
89
- location.pathname = '/';
90
- };
91
- },
92
- unload: async () => {
93
- context.dispose();
94
- },
95
- provides: {
96
- settings,
97
- translations,
98
- complementary: {
99
- panels: [{ id: 'debug', label: ['open debug panel label', { ns: DEBUG_PLUGIN }], icon: 'ph--bug--regular' }],
100
- },
101
- context: ({ children }) => {
102
- const [timer, setTimer] = useState<Timer>();
103
- useEffect(() => timer?.state.on((value) => !value && setTimer(undefined)), [timer]);
104
- useEffect(() => {
105
- timer?.stop();
106
- }, []);
107
-
108
- return (
109
- <DebugContext.Provider
110
- value={{
111
- running: !!timer,
112
- start: (cb, options) => {
113
- timer?.stop();
114
- setTimer(new Timer(cb).start(options));
115
- },
116
- stop: () => timer?.stop(),
117
- }}
118
- >
119
- {children}
120
- </DebugContext.Provider>
121
- );
122
- },
123
- graph: {
124
- builder: (plugins) => {
125
- const clientPlugin = resolvePlugin(plugins, parseClientPlugin);
126
- const metadataPlugin = resolvePlugin(plugins, parseMetadataResolverPlugin);
127
- const graphPlugin = resolvePlugin(plugins, parseGraphPlugin);
128
- const resolve = metadataPlugin?.provides.metadata.resolver;
129
- const client = clientPlugin?.provides.client;
130
- invariant(resolve);
131
- invariant(client);
132
-
133
- return [
134
- // Devtools node.
135
- createExtension({
136
- id: 'dxos.org/plugin/debug/devtools',
137
- filter: (node): node is Node<null> => !!settings.devtools && node.id === 'root',
138
- connector: () => [
139
- {
140
- // TODO(zan): Removed `/` because it breaks deck layout reload. Fix?
141
- id: 'dxos.org.plugin.debug.devtools',
142
- data: 'devtools',
143
- type: 'dxos.org/plugin/debug/devtools',
144
- properties: {
145
- label: ['devtools label', { ns: DEBUG_PLUGIN }],
146
- icon: 'ph--hammer--regular',
147
- },
148
- },
149
- ],
150
- }),
151
-
152
- // Debug node.
153
- createExtension({
154
- id: 'dxos.org/plugin/debug/debug',
155
- filter: (node): node is Node<null> => !!settings.debug && node.id === 'root',
156
- connector: () => [
157
- {
158
- id: 'dxos.org/plugin/debug/debug',
159
- type: 'dxos.org/plugin/debug/debug',
160
- data: { graph: graphPlugin?.provides.graph },
161
- properties: {
162
- label: ['debug label', { ns: DEBUG_PLUGIN }],
163
- icon: 'ph--bug--regular',
164
- },
165
- },
166
- ],
167
- }),
168
-
169
- // Space debug nodes.
170
- createExtension({
171
- id: 'dxos.org/plugin/debug/spaces',
172
- filter: (node): node is Node<Space> => !!settings.debug && isSpace(node.data),
173
- connector: ({ node }) => {
174
- const space = node.data;
175
- const state = toSignal(
176
- (onChange) => space.state.subscribe(() => onChange()).unsubscribe,
177
- () => space.state.get(),
178
- space.id,
179
- );
180
- if (state !== SpaceState.SPACE_READY) {
181
- return;
182
- }
183
-
184
- // Not adding the debug node until the root collection is available aligns the behaviour of this
185
- // extension with that of the space plugin adding objects. This ensures that the debug node is added at
186
- // the same time as objects and prevents order from changing as the nodes are added.
187
- const collection = space.properties[CollectionType.typename]?.target as CollectionType | undefined;
188
- if (!collection) {
189
- return;
190
- }
191
-
192
- return [
193
- {
194
- id: `${space.id}-debug`, // TODO(burdon): Change to slashes consistently.
195
- type: 'dxos.org/plugin/debug/space',
196
- data: { space, type: 'dxos.org/plugin/debug/space' },
197
- properties: {
198
- label: ['debug label', { ns: DEBUG_PLUGIN }],
199
- icon: 'ph--bug--regular',
200
- },
201
- },
202
- ];
203
- },
204
- }),
205
-
206
- // Create nodes for debug sidebar.
207
- createExtension({
208
- id: `${DEBUG_PLUGIN}/debug-for-subject`,
209
- resolver: ({ id }) => {
210
- // TODO(Zan): Find util (or make one).
211
- if (!id.endsWith('~debug')) {
212
- return;
213
- }
214
-
215
- const type = 'orphan-settings-for-subject';
216
- const icon = 'ph--bug--regular';
217
-
218
- const [subjectId] = id.split('~');
219
- const { spaceId, objectId } = parseId(subjectId);
220
- const spaces = toSignal(
221
- (onChange) => client.spaces.subscribe(() => onChange()).unsubscribe,
222
- () => client.spaces.get(),
223
- );
224
- const space = spaces?.find(
225
- (space) => space.state.get() === SpaceState.SPACE_READY && space.id === spaceId,
226
- );
227
- if (!objectId) {
228
- // TODO(burdon): Ref SPACE_PLUGIN ns.
229
- const label = space
230
- ? space.properties.name || ['unnamed space label', { ns: DEBUG_PLUGIN }]
231
- : ['unnamed object settings label', { ns: DEBUG_PLUGIN }];
232
-
233
- // TODO(wittjosiah): Support comments for arbitrary subjects.
234
- // This is to ensure that the comments panel is not stuck on an old object.
235
- return {
236
- id,
237
- type,
238
- data: null,
239
- properties: {
240
- icon,
241
- label,
242
- showResolvedThreads: false,
243
- object: null,
244
- space,
245
- },
246
- };
247
- }
248
-
249
- const [object] = memoizeQuery(space, { id: objectId });
250
- if (!object || !subjectId) {
251
- return;
252
- }
253
-
254
- const meta = resolve(getTypename(object) ?? '');
255
- const label = meta.label?.(object) ||
256
- object.name ||
257
- meta.placeholder || ['unnamed object settings label', { ns: DEBUG_PLUGIN }];
258
-
259
- return {
260
- id,
261
- type,
262
- data: null,
263
- properties: {
264
- icon,
265
- label,
266
- object,
267
- },
268
- };
269
- },
270
- }),
271
- ];
272
- },
273
- },
274
- surface: {
275
- definitions: () => [
276
- createSurface({
277
- id: `${DEBUG_PLUGIN}/settings`,
278
- role: 'settings',
279
- filter: (data): data is any => data.subject === DEBUG_PLUGIN,
280
- component: () => <DebugSettings settings={settings} />,
281
- }),
282
- createSurface({
283
- id: `${DEBUG_PLUGIN}/status`,
284
- role: 'status',
285
- component: () => <DebugStatus />,
286
- }),
287
- createSurface({
288
- id: `${DEBUG_PLUGIN}/complementary`,
289
- role: 'complementary--debug',
290
- filter: (data): data is { subject: ReactiveEchoObject<any> } => isEchoObject(data.subject),
291
- component: ({ data }) => <DebugObjectPanel object={data.subject} />,
292
- }),
293
- createSurface({
294
- id: `${DEBUG_PLUGIN}/devtools`,
295
- role: 'article',
296
- filter: (data): data is any => data.subject === 'devtools' && !!settings.devtools,
297
- component: () => <Devtools />,
298
- }),
299
- createSurface({
300
- id: `${DEBUG_PLUGIN}/space`,
301
- role: 'article',
302
- filter: (data): data is { subject: SpaceDebug } => isSpaceDebug(data.subject),
303
- component: ({ data }) => {
304
- const handleCreateObject = useCallback(
305
- (objects: ReactiveObject<any>[]) => {
306
- if (!isSpace(data.subject.space)) {
307
- return;
308
- }
309
-
310
- const collection =
311
- data.subject.space.state.get() === SpaceState.SPACE_READY &&
312
- data.subject.space.properties[CollectionType.typename]?.target;
313
- if (!(collection instanceof CollectionType)) {
314
- return;
315
- }
316
-
317
- objects.forEach((object) => {
318
- void context
319
- .resolvePlugin(parseIntentPlugin)
320
- .provides.intent.dispatchPromise(
321
- createIntent(SpaceAction.AddObject, { target: collection, object }),
322
- );
323
- });
324
- },
325
- [data.subject.space],
326
- );
327
-
328
- const deprecated = false;
329
- return deprecated ? (
330
- <DebugSpace space={data.subject.space} onAddObjects={handleCreateObject} />
331
- ) : (
332
- <SpaceGenerator space={data.subject.space} onCreateObjects={handleCreateObject} />
333
- );
334
- },
335
- }),
336
- createSurface({
337
- id: `${DEBUG_PLUGIN}/graph`,
338
- role: 'article',
339
- filter: (data): data is { subject: GraphDebug } => isGraphDebug(data.subject),
340
- component: ({ data }) => <DebugApp graph={data.subject.graph} />,
341
- }),
342
- createSurface({
343
- id: `${DEBUG_PLUGIN}/wireframe`,
344
- role: ['article', 'section'],
345
- disposition: 'hoist',
346
- filter: (data): data is { subject: ReactiveEchoObject<any> } =>
347
- isEchoObject(data.subject) && !!settings.wireframe,
348
- component: ({ data, role }) => (
349
- <Wireframe label={`${role}:${name}`} object={data.subject} classNames='row-span-2 overflow-hidden' />
350
- ),
351
- }),
352
- ],
353
- },
354
- },
55
+ const setupDevtools = () => {
56
+ (globalThis as any).composer ??= {};
57
+
58
+ // Used to test how composer handles breaking protocol changes.
59
+ (globalThis as any).composer.changeStorageVersionInMetadata = async (version: number) => {
60
+ const { changeStorageVersionInMetadata } = await import('@dxos/echo-pipeline/testing');
61
+ const { createStorageObjects } = await import('@dxos/client-services');
62
+ const client: Client = (window as any).dxos.client;
63
+ const config = client.config;
64
+ await client.destroy();
65
+ const { storage } = createStorageObjects(config.values?.runtime?.client?.storage ?? {});
66
+ await changeStorageVersionInMetadata(storage, version);
67
+ location.pathname = '/';
355
68
  };
356
- });
69
+ };
@@ -0,0 +1,177 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { contributes, Capabilities, type PluginsContext } from '@dxos/app-framework';
6
+ import { ClientCapabilities } from '@dxos/plugin-client';
7
+ import { createExtension, toSignal, type Node } from '@dxos/plugin-graph';
8
+ import { memoizeQuery } from '@dxos/plugin-space';
9
+ import { CollectionType } from '@dxos/plugin-space/types';
10
+ import { getTypename, parseId, SpaceState } from '@dxos/react-client/echo';
11
+ import { isSpace, type Space } from '@dxos/react-client/echo';
12
+
13
+ import { DEBUG_PLUGIN } from '../meta';
14
+ import { type DebugSettingsProps } from '../types';
15
+
16
+ export default (context: PluginsContext) => {
17
+ const resolve = (typename: string) =>
18
+ context.requestCapabilities(Capabilities.Metadata).find(({ id }) => id === typename)?.metadata ?? {};
19
+
20
+ return contributes(Capabilities.AppGraphBuilder, [
21
+ // Devtools node.
22
+ createExtension({
23
+ id: 'dxos.org/plugin/debug/devtools',
24
+ filter: (node): node is Node<null> => {
25
+ const settings = context
26
+ .requestCapabilities(Capabilities.SettingsStore)[0]
27
+ ?.getStore<DebugSettingsProps>(DEBUG_PLUGIN)?.value;
28
+ return !!settings?.devtools && node.id === 'root';
29
+ },
30
+ connector: () => [
31
+ {
32
+ // TODO(zan): Removed `/` because it breaks deck layout reload. Fix?
33
+ id: 'dxos.org.plugin.debug.devtools',
34
+ data: 'devtools',
35
+ type: 'dxos.org/plugin/debug/devtools',
36
+ properties: {
37
+ label: ['devtools label', { ns: DEBUG_PLUGIN }],
38
+ icon: 'ph--hammer--regular',
39
+ },
40
+ },
41
+ ],
42
+ }),
43
+
44
+ // Debug node.
45
+ createExtension({
46
+ id: 'dxos.org/plugin/debug/debug',
47
+ filter: (node): node is Node<null> => {
48
+ const settings = context
49
+ .requestCapabilities(Capabilities.SettingsStore)[0]
50
+ ?.getStore<DebugSettingsProps>(DEBUG_PLUGIN)?.value;
51
+ return !!settings?.debug && node.id === 'root';
52
+ },
53
+ connector: () => {
54
+ const graph = context.requestCapability(Capabilities.AppGraph);
55
+
56
+ return [
57
+ {
58
+ id: 'dxos.org/plugin/debug/debug',
59
+ type: 'dxos.org/plugin/debug/debug',
60
+ data: { graph },
61
+ properties: {
62
+ label: ['debug label', { ns: DEBUG_PLUGIN }],
63
+ icon: 'ph--bug--regular',
64
+ },
65
+ },
66
+ ];
67
+ },
68
+ }),
69
+
70
+ // Space debug nodes.
71
+ createExtension({
72
+ id: 'dxos.org/plugin/debug/spaces',
73
+ filter: (node): node is Node<Space> => {
74
+ const settings = context
75
+ .requestCapabilities(Capabilities.SettingsStore)[0]
76
+ ?.getStore<DebugSettingsProps>(DEBUG_PLUGIN)?.value;
77
+ return !!settings?.debug && isSpace(node.data);
78
+ },
79
+ connector: ({ node }) => {
80
+ const space = node.data;
81
+ const state = toSignal(
82
+ (onChange) => space.state.subscribe(() => onChange()).unsubscribe,
83
+ () => space.state.get(),
84
+ space.id,
85
+ );
86
+ if (state !== SpaceState.SPACE_READY) {
87
+ return;
88
+ }
89
+
90
+ // Not adding the debug node until the root collection is available aligns the behaviour of this
91
+ // extension with that of the space plugin adding objects. This ensures that the debug node is added at
92
+ // the same time as objects and prevents order from changing as the nodes are added.
93
+ const collection = space.properties[CollectionType.typename]?.target as CollectionType | undefined;
94
+ if (!collection) {
95
+ return;
96
+ }
97
+
98
+ return [
99
+ {
100
+ id: `${space.id}-debug`, // TODO(burdon): Change to slashes consistently.
101
+ type: 'dxos.org/plugin/debug/space',
102
+ data: { space, type: 'dxos.org/plugin/debug/space' },
103
+ properties: {
104
+ label: ['debug label', { ns: DEBUG_PLUGIN }],
105
+ icon: 'ph--bug--regular',
106
+ },
107
+ },
108
+ ];
109
+ },
110
+ }),
111
+
112
+ // Create nodes for debug sidebar.
113
+ createExtension({
114
+ id: `${DEBUG_PLUGIN}/debug-for-subject`,
115
+ resolver: ({ id }) => {
116
+ // TODO(Zan): Find util (or make one).
117
+ if (!id.endsWith('~debug')) {
118
+ return;
119
+ }
120
+
121
+ const type = 'orphan-settings-for-subject';
122
+ const icon = 'ph--bug--regular';
123
+
124
+ const client = context.requestCapability(ClientCapabilities.Client);
125
+ const [subjectId] = id.split('~');
126
+ const { spaceId, objectId } = parseId(subjectId);
127
+ const spaces = toSignal(
128
+ (onChange) => client.spaces.subscribe(() => onChange()).unsubscribe,
129
+ () => client.spaces.get(),
130
+ );
131
+ const space = spaces?.find((space) => space.state.get() === SpaceState.SPACE_READY && space.id === spaceId);
132
+ if (!objectId) {
133
+ // TODO(burdon): Ref SPACE_PLUGIN ns.
134
+ const label = space
135
+ ? space.properties.name || ['unnamed space label', { ns: DEBUG_PLUGIN }]
136
+ : ['unnamed object settings label', { ns: DEBUG_PLUGIN }];
137
+
138
+ // TODO(wittjosiah): Support comments for arbitrary subjects.
139
+ // This is to ensure that the comments panel is not stuck on an old object.
140
+ return {
141
+ id,
142
+ type,
143
+ data: null,
144
+ properties: {
145
+ icon,
146
+ label,
147
+ showResolvedThreads: false,
148
+ object: null,
149
+ space,
150
+ },
151
+ };
152
+ }
153
+
154
+ const [object] = memoizeQuery(space, { id: objectId });
155
+ if (!object || !subjectId) {
156
+ return;
157
+ }
158
+
159
+ const meta = resolve(getTypename(object) ?? '');
160
+ const label = meta.label?.(object) ||
161
+ object.name ||
162
+ meta.placeholder || ['unnamed object settings label', { ns: DEBUG_PLUGIN }];
163
+
164
+ return {
165
+ id,
166
+ type,
167
+ data: null,
168
+ properties: {
169
+ icon,
170
+ label,
171
+ object,
172
+ },
173
+ };
174
+ },
175
+ }),
176
+ ]);
177
+ };
@@ -0,0 +1,10 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { lazy } from '@dxos/app-framework';
6
+
7
+ export const AppGraphBuilder = lazy(() => import('./app-graph-builder'));
8
+ export const ReactContext = lazy(() => import('./react-context'));
9
+ export const ReactSurface = lazy(() => import('./react-surface'));
10
+ export const DebugSettings = lazy(() => import('./settings'));
@@ -0,0 +1,38 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { useEffect, useState } from 'react';
6
+
7
+ import { Capabilities, contributes } from '@dxos/app-framework';
8
+ import { Timer } from '@dxos/async';
9
+
10
+ import { DEBUG_PLUGIN } from '../meta';
11
+ import { DebugContext } from '../types';
12
+
13
+ export default () =>
14
+ contributes(Capabilities.ReactContext, {
15
+ id: DEBUG_PLUGIN,
16
+ context: ({ children }) => {
17
+ const [timer, setTimer] = useState<Timer>();
18
+ useEffect(() => timer?.state.on((value) => !value && setTimer(undefined)), [timer]);
19
+ useEffect(() => {
20
+ timer?.stop();
21
+ }, []);
22
+
23
+ return (
24
+ <DebugContext.Provider
25
+ value={{
26
+ running: !!timer,
27
+ start: (cb, options) => {
28
+ timer?.stop();
29
+ setTimer(new Timer(cb).start(options));
30
+ },
31
+ stop: () => timer?.stop(),
32
+ }}
33
+ >
34
+ {children}
35
+ </DebugContext.Provider>
36
+ );
37
+ },
38
+ });