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

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 (80) hide show
  1. package/dist/lib/browser/{DebugSpace-4JHYA7FG.mjs → DebugSpace-BTMTVZ6C.mjs} +2 -2
  2. package/dist/lib/browser/SpaceGenerator-BPZGOSH4.mjs +1238 -0
  3. package/dist/lib/browser/SpaceGenerator-BPZGOSH4.mjs.map +7 -0
  4. package/dist/lib/browser/app-graph-builder-BZFZ6UG6.mjs +533 -0
  5. package/dist/lib/browser/app-graph-builder-BZFZ6UG6.mjs.map +7 -0
  6. package/dist/lib/browser/chunk-EF3UVAVI.mjs +21 -0
  7. package/dist/lib/browser/chunk-EF3UVAVI.mjs.map +7 -0
  8. package/dist/lib/browser/chunk-UASI2CRI.mjs +72 -0
  9. package/dist/lib/browser/chunk-UASI2CRI.mjs.map +7 -0
  10. package/dist/lib/browser/index.mjs +40 -10
  11. package/dist/lib/browser/index.mjs.map +3 -3
  12. package/dist/lib/browser/meta.json +1 -1
  13. package/dist/lib/browser/react-context-TCD3MNIT.mjs +16 -0
  14. package/dist/lib/browser/react-context-TCD3MNIT.mjs.map +7 -0
  15. package/dist/lib/browser/{react-surface-5GNO6NWP.mjs → react-surface-W6QLG4YJ.mjs} +258 -85
  16. package/dist/lib/browser/react-surface-W6QLG4YJ.mjs.map +7 -0
  17. package/dist/lib/browser/{settings-JCZUA643.mjs → settings-INPXR64L.mjs} +6 -7
  18. package/dist/lib/browser/{settings-JCZUA643.mjs.map → settings-INPXR64L.mjs.map} +3 -3
  19. package/dist/types/src/DebugPlugin.d.ts.map +1 -1
  20. package/dist/types/src/capabilities/app-graph-builder.d.ts +110 -110
  21. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  22. package/dist/types/src/capabilities/index.d.ts +116 -116
  23. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  24. package/dist/types/src/capabilities/react-context.d.ts.map +1 -1
  25. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  26. package/dist/types/src/capabilities/settings.d.ts.map +1 -1
  27. package/dist/types/src/components/Container.d.ts +2 -2
  28. package/dist/types/src/components/Container.d.ts.map +1 -1
  29. package/dist/types/src/components/DebugObjectPanel.d.ts +1 -2
  30. package/dist/types/src/components/DebugObjectPanel.d.ts.map +1 -1
  31. package/dist/types/src/components/DebugSettings.d.ts +1 -2
  32. package/dist/types/src/components/DebugSettings.d.ts.map +1 -1
  33. package/dist/types/src/components/DebugSpace/ObjectCreator.d.ts +1 -2
  34. package/dist/types/src/components/DebugSpace/ObjectCreator.d.ts.map +1 -1
  35. package/dist/types/src/components/DebugStatus.d.ts +1 -2
  36. package/dist/types/src/components/DebugStatus.d.ts.map +1 -1
  37. package/dist/types/src/components/SpaceGenerator/ObjectGenerator.d.ts.map +1 -1
  38. package/dist/types/src/components/SpaceGenerator/SchemaTable.d.ts +1 -2
  39. package/dist/types/src/components/SpaceGenerator/SchemaTable.d.ts.map +1 -1
  40. package/dist/types/src/components/SpaceGenerator/SpaceGenerator.d.ts +1 -2
  41. package/dist/types/src/components/SpaceGenerator/SpaceGenerator.d.ts.map +1 -1
  42. package/dist/types/src/components/SpaceGenerator/presets.d.ts +22 -0
  43. package/dist/types/src/components/SpaceGenerator/presets.d.ts.map +1 -0
  44. package/dist/types/src/components/Wireframe.d.ts +1 -2
  45. package/dist/types/src/components/Wireframe.d.ts.map +1 -1
  46. package/dist/types/src/components/index.d.ts +4 -4
  47. package/dist/types/src/components/index.d.ts.map +1 -1
  48. package/dist/types/src/meta.d.ts +1 -0
  49. package/dist/types/src/meta.d.ts.map +1 -1
  50. package/dist/types/src/translations.d.ts +28 -0
  51. package/dist/types/src/translations.d.ts.map +1 -1
  52. package/dist/types/src/types.d.ts +44 -1
  53. package/dist/types/src/types.d.ts.map +1 -1
  54. package/package.json +50 -43
  55. package/src/DebugPlugin.tsx +6 -3
  56. package/src/capabilities/app-graph-builder.ts +297 -89
  57. package/src/capabilities/react-context.tsx +3 -25
  58. package/src/capabilities/react-surface.tsx +202 -33
  59. package/src/capabilities/settings.ts +0 -1
  60. package/src/components/DebugObjectPanel.tsx +17 -5
  61. package/src/components/DebugSettings.tsx +7 -12
  62. package/src/components/DebugStatus.tsx +17 -21
  63. package/src/components/SpaceGenerator/ObjectGenerator.tsx +31 -4
  64. package/src/components/SpaceGenerator/SpaceGenerator.tsx +75 -6
  65. package/src/components/SpaceGenerator/presets.ts +563 -0
  66. package/src/meta.ts +3 -1
  67. package/src/translations.ts +28 -0
  68. package/src/types.ts +52 -1
  69. package/dist/lib/browser/SpaceGenerator-NJCG57CU.mjs +0 -279
  70. package/dist/lib/browser/SpaceGenerator-NJCG57CU.mjs.map +0 -7
  71. package/dist/lib/browser/app-graph-builder-FXELWOFS.mjs +0 -177
  72. package/dist/lib/browser/app-graph-builder-FXELWOFS.mjs.map +0 -7
  73. package/dist/lib/browser/chunk-I3ON45JK.mjs +0 -18
  74. package/dist/lib/browser/chunk-I3ON45JK.mjs.map +0 -7
  75. package/dist/lib/browser/chunk-P7GHHMDB.mjs +0 -21
  76. package/dist/lib/browser/chunk-P7GHHMDB.mjs.map +0 -7
  77. package/dist/lib/browser/react-context-OZU6J7G3.mjs +0 -37
  78. package/dist/lib/browser/react-context-OZU6J7G3.mjs.map +0 -7
  79. package/dist/lib/browser/react-surface-5GNO6NWP.mjs.map +0 -7
  80. /package/dist/lib/browser/{DebugSpace-4JHYA7FG.mjs.map → DebugSpace-BTMTVZ6C.mjs.map} +0 -0
@@ -4,19 +4,26 @@
4
4
 
5
5
  import React, { useCallback, useMemo, useState } from 'react';
6
6
 
7
- import { type ReactiveObject } from '@dxos/live-object';
7
+ import { createIntent, useIntentDispatcher } from '@dxos/app-framework';
8
+ import { ComputeGraph } from '@dxos/conductor';
9
+ import { toEffectSchema } from '@dxos/echo-schema';
10
+ import { create, type ReactiveObject } from '@dxos/live-object';
11
+ import { log } from '@dxos/log';
8
12
  import { DocumentType } from '@dxos/plugin-markdown/types';
9
13
  import { SheetType } from '@dxos/plugin-sheet/types';
10
14
  import { DiagramType } from '@dxos/plugin-sketch/types';
15
+ import { SpaceAction } from '@dxos/plugin-space/types';
11
16
  import { useClient } from '@dxos/react-client';
12
17
  import { getTypename, type Space } from '@dxos/react-client/echo';
13
18
  import { IconButton, Input, Toolbar, useAsyncEffect } from '@dxos/react-ui';
14
19
  import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
20
+ import { initializeTable, TableType } from '@dxos/react-ui-table';
15
21
  import { Testing } from '@dxos/schema/testing';
16
22
  import { jsonKeyReplacer, sortKeys } from '@dxos/util';
17
23
 
18
24
  import { type ObjectGenerator, createGenerator, staticGenerators } from './ObjectGenerator';
19
25
  import { SchemaTable } from './SchemaTable';
26
+ import { presets } from './presets';
20
27
 
21
28
  export type SpaceGeneratorProps = {
22
29
  space: Space;
@@ -24,20 +31,27 @@ export type SpaceGeneratorProps = {
24
31
  };
25
32
 
26
33
  export const SpaceGenerator = ({ space, onCreateObjects }: SpaceGeneratorProps) => {
34
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
27
35
  const client = useClient();
28
- const staticTypes = [DocumentType, DiagramType, SheetType]; // TODO(burdon): Make extensible.
29
- const mutableTypes = [Testing.OrgType, Testing.ProjectType, Testing.ContactType];
36
+ const staticTypes = [DocumentType, DiagramType, SheetType, ComputeGraph]; // TODO(burdon): Make extensible.
37
+ const mutableTypes = [
38
+ Testing.OrgType,
39
+ Testing.ProjectType,
40
+ Testing.ContactType,
41
+ Testing.EmailType,
42
+ Testing.MessageType,
43
+ ];
30
44
  const [count, setCount] = useState(1);
31
45
  const [info, setInfo] = useState<any>({});
32
46
 
33
47
  // Create type generators.
34
48
  const typeMap = useMemo(() => {
35
- client.addTypes(staticTypes);
49
+ client.addTypes([...staticTypes, ...presets.schemas]);
36
50
  const mutableGenerators = new Map<string, ObjectGenerator<any>>(
37
- mutableTypes.map((type) => [type.typename, createGenerator(type)]),
51
+ mutableTypes.map((type) => [type.typename, createGenerator(type as any)]),
38
52
  );
39
53
 
40
- return new Map([...staticGenerators, ...mutableGenerators]);
54
+ return new Map([...staticGenerators, ...presets.items, ...mutableGenerators]);
41
55
  }, [client, mutableTypes]);
42
56
 
43
57
  // Query space to get info.
@@ -82,10 +96,64 @@ export const SpaceGenerator = ({ space, onCreateObjects }: SpaceGeneratorProps)
82
96
  [typeMap, count],
83
97
  );
84
98
 
99
+ // TODO(wittjosiah): Remove. Replace with proper echo import.
100
+ const handleLoadTables = useCallback(async () => {
101
+ const input = document.createElement('input');
102
+ input.type = 'file';
103
+ input.accept = '.json';
104
+
105
+ input.onchange = async (e) => {
106
+ const file = (e.target as HTMLInputElement).files?.[0];
107
+ if (!file) {
108
+ return;
109
+ }
110
+
111
+ try {
112
+ const content = await file.text();
113
+ const data = JSON.parse(content);
114
+ const schemas = await space.db.schemaRegistry.register(data.schemas.map(toEffectSchema));
115
+ // TODO(wittjosiah): If the schema is already registered this should skip.
116
+ await Promise.all(
117
+ schemas.map(async (schema) => {
118
+ const parts = schema.typename.split('/');
119
+ const name = parts[parts.length - 1];
120
+ const table = create(TableType, { name, threads: [] });
121
+ await initializeTable({ space, table, initialSchema: schema.typename });
122
+ await dispatch(createIntent(SpaceAction.AddObject, { target: space, object: table }));
123
+ return table;
124
+ }),
125
+ );
126
+ // TODO(wittjosiah): This should query the space for schemas.
127
+ await Promise.all(
128
+ data.objects.map(async ({ id, '@type': typename, ...fields }: any) => {
129
+ const schema = schemas.find((s) => `dxn:type:${s.typename}:${s.version}` === typename);
130
+ if (!schema) {
131
+ log.warn('Missing schema for object', { id, typename });
132
+ return;
133
+ }
134
+ const object = create(schema, fields);
135
+ space.db.add(object);
136
+ return object;
137
+ }),
138
+ );
139
+ } catch (err) {
140
+ log.catch(err);
141
+ }
142
+ };
143
+
144
+ input.click();
145
+ }, []);
146
+
85
147
  return (
86
148
  <div role='none' className='flex flex-col divide-y divide-separator'>
87
149
  <Toolbar.Root classNames='p-1'>
88
150
  <IconButton icon='ph--arrow-clockwise--regular' iconOnly label='Refresh' onClick={updateInfo} />
151
+ <IconButton
152
+ icon='ph--file-arrow-up--regular'
153
+ iconOnly
154
+ label='Load tables from JSON'
155
+ onClick={handleLoadTables}
156
+ />
89
157
  <Toolbar.Separator variant='gap' />
90
158
  <div className='flex'>
91
159
  <Input.Root>
@@ -104,6 +172,7 @@ export const SpaceGenerator = ({ space, onCreateObjects }: SpaceGeneratorProps)
104
172
 
105
173
  <SchemaTable types={staticTypes} objects={info.objects} label='Static Types' onClick={handleCreateData} />
106
174
  <SchemaTable types={mutableTypes} objects={info.objects} label='Mutable Types' onClick={handleCreateData} />
175
+ <SchemaTable types={presets.types} objects={info.objects} label='Presets' onClick={handleCreateData} />
107
176
 
108
177
  <SyntaxHighlighter classNames='flex text-xs' language='json'>
109
178
  {JSON.stringify({ space, ...info }, jsonKeyReplacer({ truncate: true }), 2)}
@@ -0,0 +1,563 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type ComputeGraphModel, EmailTriggerOutput, NODE_INPUT } from '@dxos/conductor';
6
+ import { AST, ObjectId, S, toJsonSchema } from '@dxos/echo-schema';
7
+ import { FunctionTrigger, TriggerKind, type TriggerType } from '@dxos/functions/types';
8
+ import { invariant } from '@dxos/invariant';
9
+ import { DXN } from '@dxos/keys';
10
+ import { create, makeRef } from '@dxos/live-object';
11
+ import { Filter, type Space } from '@dxos/react-client/echo';
12
+ import {
13
+ type ComputeShape,
14
+ createAppend,
15
+ createChat,
16
+ createComputeGraph,
17
+ createConstant,
18
+ createFunction,
19
+ createGpt,
20
+ createQueue,
21
+ createSurface,
22
+ createRandom,
23
+ createTemplate,
24
+ createText,
25
+ createTrigger,
26
+ } from '@dxos/react-ui-canvas-compute';
27
+ import {
28
+ CanvasBoardType,
29
+ CanvasGraphModel,
30
+ pointMultiply,
31
+ pointsToRect,
32
+ rectToPoints,
33
+ } from '@dxos/react-ui-canvas-editor';
34
+ import { TableType } from '@dxos/react-ui-table';
35
+ import { range } from '@dxos/util';
36
+
37
+ import { type ObjectGenerator } from './ObjectGenerator';
38
+
39
+ export enum PresetName {
40
+ EMAIL_TABLE = 'email-table',
41
+ GPT_QUEUE = 'webhook-gpt-queue',
42
+ CHAT_GPT = 'chat-gpt-text',
43
+ EMAIL_WITH_SUMMARY = 'email-gptSummary-table',
44
+ OBJECT_CHANGE_QUEUE = 'objectChange-queue',
45
+ FOREX_FUNCTION_CALL = 'forex-function-call',
46
+ TIMER_TICK_QUEUE = 'timerTick-queue',
47
+ DISCORD_MESSAGES = 'discord-messages',
48
+ KANBAN_QUEUE = 'kanban-queue',
49
+ }
50
+
51
+ export const presets = {
52
+ schemas: [CanvasBoardType, FunctionTrigger],
53
+ types: Object.values(PresetName).map((name) => ({ typename: name })),
54
+ items: [
55
+ [
56
+ PresetName.GPT_QUEUE,
57
+ async (space, n, cb) => {
58
+ const objects = range(n, () => {
59
+ const canvasModel = CanvasGraphModel.create<ComputeShape>();
60
+
61
+ let functionTrigger: FunctionTrigger | undefined;
62
+ canvasModel.builder.call((builder) => {
63
+ const gpt = canvasModel.createNode(createGpt(position({ x: 0, y: -14 })));
64
+ const triggerShape = createTrigger({
65
+ spaceId: space.id,
66
+ triggerKind: TriggerKind.Webhook,
67
+ ...position({ x: -18, y: -2 }),
68
+ });
69
+ const trigger = canvasModel.createNode(triggerShape);
70
+ const text = canvasModel.createNode(createText(position({ x: 19, y: 3, width: 10, height: 10 })));
71
+ const { queueId } = setupQueue(space, canvasModel);
72
+ const append = canvasModel.createNode(createAppend(position({ x: 10, y: 6 })));
73
+
74
+ builder
75
+ .createEdge({ source: trigger.id, target: gpt.id, input: 'prompt', output: 'bodyText' })
76
+ .createEdge({ source: gpt.id, target: text.id, output: 'text' })
77
+ .createEdge({ source: queueId.id, target: append.id, input: 'id' })
78
+ .createEdge({ source: gpt.id, target: append.id, output: 'messages', input: 'items' });
79
+
80
+ functionTrigger = triggerShape.functionTrigger!.target!;
81
+ });
82
+
83
+ const computeModel = createComputeGraph(canvasModel);
84
+
85
+ attachTrigger(functionTrigger, computeModel);
86
+
87
+ return addToSpace(PresetName.GPT_QUEUE, space, canvasModel, computeModel);
88
+ });
89
+ cb?.(objects);
90
+ return objects;
91
+ },
92
+ ],
93
+
94
+ [
95
+ PresetName.OBJECT_CHANGE_QUEUE,
96
+ async (space, n, cb) => {
97
+ const objects = range(n, () => {
98
+ const { canvasModel, computeModel } = createQueueSinkPreset(
99
+ space,
100
+ TriggerKind.Subscription,
101
+ (triggerSpec) => (triggerSpec.filter = { type: 'dxn:type:dxos.org/type/Chess' }),
102
+ 'type',
103
+ );
104
+ return addToSpace(PresetName.OBJECT_CHANGE_QUEUE, space, canvasModel, computeModel);
105
+ });
106
+ cb?.(objects);
107
+ return objects;
108
+ },
109
+ ],
110
+
111
+ [
112
+ PresetName.TIMER_TICK_QUEUE,
113
+ async (space, n, cb) => {
114
+ const objects = range(n, () => {
115
+ const { canvasModel, computeModel } = createQueueSinkPreset(
116
+ space,
117
+ TriggerKind.Timer,
118
+ (triggerSpec) => (triggerSpec.cron = '*/5 * * * * *'),
119
+ 'result',
120
+ );
121
+ return addToSpace(PresetName.TIMER_TICK_QUEUE, space, canvasModel, computeModel);
122
+ });
123
+ cb?.(objects);
124
+ return objects;
125
+ },
126
+ ],
127
+
128
+ [
129
+ PresetName.EMAIL_TABLE,
130
+ async (space, n, cb) => {
131
+ const objects = range(n, () => {
132
+ const canvasModel = CanvasGraphModel.create<ComputeShape>();
133
+
134
+ const results = space.db.query(Filter.schema(TableType)).runSync();
135
+ const emailTable = results.find((r) => r.object?.view?.target?.query?.type?.endsWith('Email'));
136
+ invariant(emailTable, 'Email table not found.');
137
+
138
+ const template = canvasModel.createNode(
139
+ createTemplate({
140
+ valueType: 'object',
141
+ ...rawPosition({ centerX: -80, centerY: -64, width: 320, height: 320 }),
142
+ }),
143
+ );
144
+ const templateContent = ['{'];
145
+
146
+ let functionTrigger: FunctionTrigger | undefined;
147
+ canvasModel.builder.call((builder) => {
148
+ const triggerShape = createTrigger({
149
+ spaceId: space.id,
150
+ triggerKind: TriggerKind.Email,
151
+ ...position({ x: -18, y: -2 }),
152
+ });
153
+ const trigger = canvasModel.createNode(triggerShape);
154
+
155
+ const tableId = canvasModel.createNode(
156
+ createConstant({
157
+ value: DXN.fromLocalObjectId(emailTable.id).toString(),
158
+ ...position({ x: -18, y: 5, width: 8, height: 6 }),
159
+ }),
160
+ );
161
+
162
+ const appendToTable = canvasModel.createNode(createAppend(position({ x: 10, y: 6 })));
163
+
164
+ const properties = AST.getPropertySignatures(EmailTriggerOutput.ast);
165
+ for (let i = 0; i < properties.length; i++) {
166
+ const propName = properties[i].name.toString();
167
+ builder.createEdge({ source: trigger.id, target: template.id, input: propName, output: propName });
168
+ templateContent.push(` "${propName}": "{{${propName}}}"` + (i === properties.length - 1 ? '' : ','));
169
+ }
170
+ templateContent.push('}');
171
+
172
+ builder
173
+ .createEdge({ source: tableId.id, target: appendToTable.id, input: 'id' })
174
+ .createEdge({ source: template.id, target: appendToTable.id, input: 'items' });
175
+
176
+ functionTrigger = triggerShape.functionTrigger!.target!;
177
+ });
178
+
179
+ const computeModel = createComputeGraph(canvasModel);
180
+
181
+ const templateComputeNode = computeModel.nodes.find((n) => n.id === template.node);
182
+ invariant(templateComputeNode, 'Template compute node was not created.');
183
+ templateComputeNode.value = templateContent.join('\n');
184
+ templateComputeNode.inputSchema = toJsonSchema(EmailTriggerOutput);
185
+
186
+ attachTrigger(functionTrigger, computeModel);
187
+
188
+ return addToSpace(PresetName.EMAIL_TABLE, space, canvasModel, computeModel);
189
+ });
190
+ cb?.(objects);
191
+ return objects;
192
+ },
193
+ ],
194
+
195
+ [
196
+ PresetName.CHAT_GPT,
197
+ async (space, n, cb) => {
198
+ const objects = range(n, () => {
199
+ const canvasModel = CanvasGraphModel.create<ComputeShape>();
200
+
201
+ canvasModel.builder.call((builder) => {
202
+ const gpt = canvasModel.createNode(createGpt(position({ x: 0, y: -14 })));
203
+ const chat = canvasModel.createNode(createChat(position({ x: -18, y: -2 })));
204
+ const text = canvasModel.createNode(createText(position({ x: 19, y: 3, width: 10, height: 10 })));
205
+ const { queueId } = setupQueue(space, canvasModel);
206
+
207
+ const append = canvasModel.createNode(createAppend(position({ x: 10, y: 6 })));
208
+
209
+ builder
210
+ .createEdge({ source: chat.id, target: gpt.id, input: 'prompt' })
211
+ .createEdge({ source: gpt.id, target: text.id, output: 'text' })
212
+ .createEdge({ source: queueId.id, target: append.id, input: 'id' })
213
+ .createEdge({ source: gpt.id, target: append.id, output: 'messages', input: 'items' });
214
+ });
215
+
216
+ const computeModel = createComputeGraph(canvasModel);
217
+
218
+ return addToSpace(PresetName.CHAT_GPT, space, canvasModel, computeModel);
219
+ });
220
+ cb?.(objects);
221
+ return objects;
222
+ },
223
+ ],
224
+
225
+ [
226
+ PresetName.EMAIL_WITH_SUMMARY,
227
+ async (space, n, cb) => {
228
+ const objects = range(n, () => {
229
+ const canvasModel = CanvasGraphModel.create<ComputeShape>();
230
+
231
+ const results = space.db.query(Filter.schema(TableType)).runSync();
232
+ const emailTable = results.find((r) => r.object?.view?.target?.query?.type?.endsWith('Email'));
233
+ invariant(emailTable, 'Email table not found.');
234
+
235
+ const template = canvasModel.createNode(
236
+ createTemplate({
237
+ valueType: 'object',
238
+ ...rawPosition({ centerX: 192, centerY: -176, width: 320, height: 320 }),
239
+ }),
240
+ );
241
+ const templateContent = ['{'];
242
+
243
+ let functionTrigger: FunctionTrigger | undefined;
244
+ canvasModel.builder.call((builder) => {
245
+ const gpt = canvasModel.createNode(
246
+ createGpt(rawPosition({ centerX: -400, centerY: -112, width: 256, height: 202 })),
247
+ );
248
+ const systemPrompt = canvasModel.createNode(
249
+ createConstant({
250
+ value: "use one word to describe content category. don't write anything else",
251
+ ...rawPosition({ centerX: -800, centerY: -160, width: 192, height: 128 }),
252
+ }),
253
+ );
254
+ const triggerShape = createTrigger({
255
+ spaceId: space.id,
256
+ triggerKind: TriggerKind.Email,
257
+ ...rawPosition({ centerX: -736, centerY: -384, width: 182, height: 192 }),
258
+ });
259
+ const trigger = canvasModel.createNode(triggerShape);
260
+
261
+ const { queueId } = setupQueue(space, canvasModel, {
262
+ idPosition: { centerX: -720, centerY: 224, width: 192, height: 256 },
263
+ queuePosition: { centerX: -144, centerY: 416, width: 320, height: 448 },
264
+ });
265
+ const appendToQueue = canvasModel.createNode(
266
+ createAppend(rawPosition({ centerX: -80, centerY: 96, width: 122, height: 128 })),
267
+ );
268
+
269
+ const tableId = canvasModel.createNode(
270
+ createConstant({
271
+ value: DXN.fromLocalObjectId(emailTable.id).toString(),
272
+ ...rawPosition({ centerX: -112, centerY: -544, width: 192, height: 256 }),
273
+ }),
274
+ );
275
+
276
+ const appendToTable = canvasModel.createNode(
277
+ createAppend(rawPosition({ centerX: 560, centerY: -416, width: 128, height: 122 })),
278
+ );
279
+
280
+ templateContent.push(' "category": "{{text}}",');
281
+ builder.createEdge({ source: gpt.id, target: template.id, input: 'text', output: 'text' });
282
+
283
+ const properties = AST.getPropertySignatures(EmailTriggerOutput.ast);
284
+ for (let i = 0; i < properties.length; i++) {
285
+ const propName = properties[i].name.toString();
286
+ builder.createEdge({ source: trigger.id, target: template.id, input: propName, output: propName });
287
+ templateContent.push(` "${propName}": "{{${propName}}}"` + (i === properties.length - 1 ? '' : ','));
288
+ }
289
+ templateContent.push('}');
290
+
291
+ builder
292
+ .createEdge({ source: tableId.id, target: appendToTable.id, input: 'id' })
293
+ .createEdge({ source: queueId.id, target: appendToQueue.id, input: 'id' })
294
+ .createEdge({ source: gpt.id, target: appendToQueue.id, output: 'messages', input: 'items' })
295
+ .createEdge({ source: systemPrompt.id, target: gpt.id, input: 'systemPrompt' })
296
+ .createEdge({ source: trigger.id, target: gpt.id, input: 'prompt', output: 'body' })
297
+ .createEdge({ source: template.id, target: appendToTable.id, input: 'items' });
298
+
299
+ functionTrigger = triggerShape.functionTrigger!.target!;
300
+ });
301
+
302
+ const computeModel = createComputeGraph(canvasModel);
303
+
304
+ const templateComputeNode = computeModel.nodes.find((n) => n.id === template.node);
305
+ invariant(templateComputeNode, 'Template compute node was not created.');
306
+ templateComputeNode.value = templateContent.join('\n');
307
+ const extendedSchema = S.extend(EmailTriggerOutput, S.Struct({ text: S.String }));
308
+ templateComputeNode.inputSchema = toJsonSchema(extendedSchema);
309
+
310
+ attachTrigger(functionTrigger, computeModel);
311
+
312
+ return addToSpace(PresetName.EMAIL_WITH_SUMMARY, space, canvasModel, computeModel);
313
+ });
314
+ cb?.(objects);
315
+ return objects;
316
+ },
317
+ ],
318
+
319
+ [
320
+ PresetName.FOREX_FUNCTION_CALL,
321
+ async (space, n, cb) => {
322
+ const objects = range(n, () => {
323
+ const canvasModel = CanvasGraphModel.create<ComputeShape>();
324
+
325
+ canvasModel.builder.call((builder) => {
326
+ const sourceCurrency = canvasModel.createNode(
327
+ createConstant({ value: 'USD', ...position({ x: -10, y: -5 }) }),
328
+ );
329
+ const targetCurrency = canvasModel.createNode(
330
+ createConstant({ value: 'EUR', ...position({ x: -10, y: 5 }) }),
331
+ );
332
+ const converter = canvasModel.createNode(createFunction(position({ x: 0, y: 0 })));
333
+ const view = canvasModel.createNode(createSurface(position({ x: 12, y: 0 })));
334
+
335
+ builder
336
+ .createEdge({ source: sourceCurrency.id, target: converter.id, input: 'from' })
337
+ .createEdge({ source: targetCurrency.id, target: converter.id, input: 'to' })
338
+ .createEdge({ source: converter.id, target: view.id, output: 'rate' });
339
+ });
340
+
341
+ const computeModel = createComputeGraph(canvasModel);
342
+
343
+ return addToSpace(PresetName.FOREX_FUNCTION_CALL, space, canvasModel, computeModel);
344
+ });
345
+ cb?.(objects);
346
+ return objects;
347
+ },
348
+ ],
349
+
350
+ [
351
+ PresetName.DISCORD_MESSAGES,
352
+ async (space, n, cb) => {
353
+ const objects = range(n, () => {
354
+ const canvasModel = CanvasGraphModel.create<ComputeShape>();
355
+
356
+ let functionTrigger: FunctionTrigger | undefined;
357
+ canvasModel.builder.call((builder) => {
358
+ const triggerShape = createTrigger({
359
+ spaceId: space.id,
360
+ triggerKind: TriggerKind.Timer,
361
+ ...position({ x: -10, y: -5 }),
362
+ });
363
+ const trigger = canvasModel.createNode(triggerShape);
364
+ // DXOS dev-null channel.
365
+ const channelId = canvasModel.createNode(
366
+ createConstant({ value: '1088569858767212554', ...position({ x: -10, y: 0 }) }),
367
+ );
368
+ const queueId = canvasModel.createNode(
369
+ createConstant({
370
+ value: new DXN(DXN.kind.QUEUE, ['data', space.id, ObjectId.random()]).toString(),
371
+ ...position({ x: -10, y: 5 }),
372
+ }),
373
+ );
374
+ const converter = canvasModel.createNode(createFunction(position({ x: 0, y: 0 })));
375
+ const view = canvasModel.createNode(createText(position({ x: 12, y: 0 })));
376
+ const queue = canvasModel.createNode(createQueue(position({ x: 0, y: 12 })));
377
+
378
+ builder
379
+ .createEdge({ source: trigger.id, target: converter.id, input: 'tick' })
380
+ .createEdge({ source: channelId.id, target: converter.id, input: 'channelId' })
381
+ .createEdge({ source: queueId.id, target: converter.id, input: 'queueId' })
382
+ .createEdge({ source: converter.id, target: view.id, output: 'newMessages' })
383
+ .createEdge({ source: queueId.id, target: queue.id, input: 'input' });
384
+
385
+ functionTrigger = triggerShape.functionTrigger!.target!;
386
+ });
387
+
388
+ const computeModel = createComputeGraph(canvasModel);
389
+ attachTrigger(functionTrigger, computeModel);
390
+
391
+ return addToSpace(PresetName.DISCORD_MESSAGES, space, canvasModel, computeModel);
392
+ });
393
+ cb?.(objects);
394
+ return objects;
395
+ },
396
+ ],
397
+
398
+ [
399
+ PresetName.KANBAN_QUEUE,
400
+ async (space, n, cb) => {
401
+ const objects = range(n, () => {
402
+ const canvasModel = CanvasGraphModel.create<ComputeShape>();
403
+
404
+ // TODO(wittjosiah): Integrate directly w/ Kanban.
405
+ // const results = space.db.query(Filter.schema(KanbanType)).runSync();
406
+ // const kanban = results.find((r) => r.object?.cardView?.target?.query?.type?.endsWith('Message'));
407
+ // invariant(kanban, 'Kanban not found.');
408
+
409
+ const results = space.db.query(Filter.schema(TableType)).runSync();
410
+ const messages = results.find((r) => r.object?.view?.target?.query?.type?.endsWith('Message'));
411
+ invariant(messages, 'Table not found.');
412
+
413
+ let functionTrigger: FunctionTrigger | undefined;
414
+ canvasModel.builder.call((builder) => {
415
+ const triggerShape = createTrigger({
416
+ spaceId: space.id,
417
+ triggerKind: TriggerKind.Queue,
418
+ ...position({ x: -10, y: -5 }),
419
+ });
420
+ const trigger = canvasModel.createNode(triggerShape);
421
+
422
+ const tableId = canvasModel.createNode(
423
+ createConstant({
424
+ value: DXN.fromLocalObjectId(messages.id).toString(),
425
+ ...position({ x: -10, y: 5 }),
426
+ }),
427
+ );
428
+ const appendToTable = canvasModel.createNode(createAppend(position({ x: 10, y: 0 })));
429
+
430
+ builder
431
+ .createEdge({ source: tableId.id, target: appendToTable.id, input: 'id' })
432
+ .createEdge({ source: trigger.id, target: appendToTable.id, input: 'items', output: 'item' });
433
+
434
+ functionTrigger = triggerShape.functionTrigger!.target!;
435
+ });
436
+
437
+ const computeModel = createComputeGraph(canvasModel);
438
+ attachTrigger(functionTrigger, computeModel);
439
+
440
+ return addToSpace(PresetName.KANBAN_QUEUE, space, canvasModel, computeModel);
441
+ });
442
+ cb?.(objects);
443
+ return objects;
444
+ },
445
+ ],
446
+ ] as [PresetName, ObjectGenerator<any>][],
447
+ };
448
+
449
+ const createQueueSinkPreset = <SpecType extends TriggerKind>(
450
+ space: Space,
451
+ triggerKind: SpecType,
452
+ initSpec: (spec: Extract<TriggerType, { type: SpecType }>) => void,
453
+ triggerOutputName: string,
454
+ ) => {
455
+ const canvasModel = CanvasGraphModel.create<ComputeShape>();
456
+
457
+ const template = canvasModel.createNode(
458
+ createTemplate({
459
+ valueType: 'object',
460
+ ...rawPosition({ centerX: -64, centerY: -79, width: 320, height: 320 }),
461
+ }),
462
+ );
463
+
464
+ let functionTrigger: FunctionTrigger | undefined;
465
+ canvasModel.builder.call((builder) => {
466
+ const triggerShape = createTrigger({
467
+ spaceId: space.id,
468
+ triggerKind,
469
+ ...rawPosition({ centerX: -578, centerY: -187, height: 320, width: 320 }),
470
+ });
471
+ const trigger = canvasModel.createNode(triggerShape);
472
+ const { queueId } = setupQueue(space, canvasModel, {
473
+ queuePosition: { centerX: -80, centerY: 378, width: 320, height: 448 },
474
+ });
475
+ const append = canvasModel.createNode(
476
+ createAppend(rawPosition({ centerX: 320, centerY: 192, width: 128, height: 122 })),
477
+ );
478
+ const random = canvasModel.createNode(
479
+ createRandom(rawPosition({ centerX: -509, centerY: -30, width: 64, height: 64 })),
480
+ );
481
+
482
+ builder
483
+ .createEdge({ source: queueId.id, target: append.id, input: 'id' })
484
+ .createEdge({ source: template.id, target: append.id, input: 'items' })
485
+ .createEdge({ source: trigger.id, target: template.id, output: triggerOutputName, input: 'type' })
486
+ .createEdge({
487
+ source: random.id,
488
+ target: template.id,
489
+ input: 'changeId',
490
+ });
491
+
492
+ functionTrigger = triggerShape.functionTrigger!.target!;
493
+ const triggerSpec = functionTrigger.spec;
494
+ invariant(triggerSpec && triggerSpec.type === triggerKind, 'No trigger spec.');
495
+ initSpec(triggerSpec as any);
496
+ });
497
+
498
+ const computeModel = createComputeGraph(canvasModel);
499
+
500
+ const templateComputeNode = computeModel.nodes.find((n) => n.id === template.node);
501
+ invariant(templateComputeNode, 'Template compute node was not created.');
502
+ templateComputeNode.value = ['{', ' "@type": "{{type}}",', ' "id": "@{{changeId}}"', '}'].join('\n');
503
+ templateComputeNode.inputSchema = toJsonSchema(S.Struct({ type: S.String, changeId: S.String }));
504
+
505
+ attachTrigger(functionTrigger, computeModel);
506
+
507
+ return { canvasModel, computeModel };
508
+ };
509
+
510
+ const addToSpace = (name: string, space: Space, canvas: CanvasGraphModel, compute: ComputeGraphModel) => {
511
+ return space.db.add(
512
+ create(CanvasBoardType, {
513
+ name,
514
+ computeGraph: makeRef(compute.root),
515
+ layout: canvas.graph,
516
+ }),
517
+ );
518
+ };
519
+
520
+ const setupQueue = (
521
+ space: Space,
522
+ canvasModel: CanvasGraphModel,
523
+ args?: { idPosition?: RawPositionInput; queuePosition?: RawPositionInput },
524
+ ) => {
525
+ const queueId = canvasModel.createNode(
526
+ createConstant({
527
+ value: new DXN(DXN.kind.QUEUE, ['data', space.id, ObjectId.random()]).toString(),
528
+ ...(args?.idPosition ? rawPosition(args.idPosition) : position({ x: -18, y: 5, width: 8, height: 6 })),
529
+ }),
530
+ );
531
+ const queue = canvasModel.createNode(
532
+ createQueue(
533
+ args?.queuePosition ? rawPosition(args.queuePosition) : position({ x: -3, y: 3, width: 14, height: 10 }),
534
+ ),
535
+ );
536
+ canvasModel.createEdge({ source: queueId.id, target: queue.id });
537
+ return { queue, queueId };
538
+ };
539
+
540
+ const attachTrigger = (functionTrigger: FunctionTrigger | undefined, computeModel: ComputeGraphModel) => {
541
+ invariant(functionTrigger);
542
+ functionTrigger.function = DXN.fromLocalObjectId(computeModel.root.id).toString();
543
+ functionTrigger.meta ??= {};
544
+ const inputNode = computeModel.nodes.find((node) => node.type === NODE_INPUT)!;
545
+ functionTrigger.meta.computeNodeId = inputNode.id;
546
+ };
547
+
548
+ type RawPositionInput = { centerX: number; centerY: number; width: number; height: number };
549
+
550
+ const rawPosition = (args: RawPositionInput) => {
551
+ return { center: { x: args.centerX, y: args.centerY }, size: { width: args.width, height: args.height } };
552
+ };
553
+
554
+ const position = (rect: { x: number; y: number; width?: number; height?: number }) => {
555
+ const snap = 32;
556
+ const [center, size] = rectToPoints({ width: 0, height: 0, ...rect });
557
+ const { x, y, width, height } = pointsToRect([pointMultiply(center, snap), pointMultiply(size, snap)]);
558
+ if (width && height) {
559
+ return { center: { x, y }, size: width && height ? { width, height } : undefined };
560
+ } else {
561
+ return { center: { x, y } };
562
+ }
563
+ };