@dxos/compute 0.8.4-main.84f28bd → 0.8.4-main.937b3ca

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 (56) hide show
  1. package/dist/lib/browser/{chunk-2PBHA7EI.mjs → chunk-KGBGT4NT.mjs} +104 -76
  2. package/dist/lib/browser/chunk-KGBGT4NT.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +1 -1
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/testing/index.mjs +31 -6
  6. package/dist/lib/browser/testing/index.mjs.map +4 -4
  7. package/dist/lib/node-esm/{chunk-GTPQNWA3.mjs → chunk-2MATJWLB.mjs} +104 -76
  8. package/dist/lib/node-esm/chunk-2MATJWLB.mjs.map +7 -0
  9. package/dist/lib/node-esm/index.mjs +1 -1
  10. package/dist/lib/node-esm/meta.json +1 -1
  11. package/dist/lib/node-esm/testing/index.mjs +31 -6
  12. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  13. package/dist/types/src/compute-graph-registry.d.ts +10 -7
  14. package/dist/types/src/compute-graph-registry.d.ts.map +1 -1
  15. package/dist/types/src/compute-graph-registry.test.d.ts +2 -0
  16. package/dist/types/src/compute-graph-registry.test.d.ts.map +1 -0
  17. package/dist/types/src/compute-graph.d.ts +5 -2
  18. package/dist/types/src/compute-graph.d.ts.map +1 -1
  19. package/dist/types/src/compute-node.d.ts +1 -2
  20. package/dist/types/src/compute-node.d.ts.map +1 -1
  21. package/dist/types/src/functions/async-function.d.ts +13 -11
  22. package/dist/types/src/functions/async-function.d.ts.map +1 -1
  23. package/dist/types/src/functions/edge-function.d.ts +3 -3
  24. package/dist/types/src/functions/edge-function.d.ts.map +1 -1
  25. package/dist/types/src/index.d.ts.map +1 -1
  26. package/dist/types/src/testing/index.d.ts +1 -0
  27. package/dist/types/src/testing/index.d.ts.map +1 -1
  28. package/dist/types/src/testing/test-builder.d.ts +1 -1
  29. package/dist/types/src/testing/test-builder.d.ts.map +1 -1
  30. package/dist/types/src/testing/test-plugin.d.ts +4 -5
  31. package/dist/types/src/testing/test-plugin.d.ts.map +1 -1
  32. package/dist/types/src/testing/test-runtime.d.ts +10 -0
  33. package/dist/types/src/testing/test-runtime.d.ts.map +1 -0
  34. package/dist/types/src/types/hyperformula.d.ts +3 -6
  35. package/dist/types/src/types/hyperformula.d.ts.map +1 -1
  36. package/dist/types/tsconfig.tsbuildinfo +1 -1
  37. package/package.json +28 -29
  38. package/src/compute-graph-registry.test.ts +158 -0
  39. package/src/compute-graph-registry.ts +20 -13
  40. package/src/compute-graph.test.ts +31 -12
  41. package/src/compute-graph.ts +21 -16
  42. package/src/compute-node.ts +2 -4
  43. package/src/functions/async-function.ts +21 -16
  44. package/src/functions/edge-function.ts +33 -31
  45. package/src/hyperformula.test.ts +2 -2
  46. package/src/index.ts +0 -27
  47. package/src/testing/index.ts +1 -0
  48. package/src/testing/test-builder.ts +8 -2
  49. package/src/testing/test-plugin.ts +2 -4
  50. package/src/testing/test-runtime.ts +34 -0
  51. package/src/testing/util.ts +1 -1
  52. package/src/types/hyperformula.ts +8 -8
  53. package/src/types/types.test.ts +2 -2
  54. package/dist/lib/browser/chunk-2PBHA7EI.mjs.map +0 -7
  55. package/dist/lib/node-esm/chunk-GTPQNWA3.mjs.map +0 -7
  56. package/dist/vendor/hyperformula.mjs +0 -36400
package/package.json CHANGED
@@ -1,26 +1,26 @@
1
1
  {
2
2
  "name": "@dxos/compute",
3
- "version": "0.8.4-main.84f28bd",
3
+ "version": "0.8.4-main.937b3ca",
4
4
  "description": "Low-level compute API",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/dxos/dxos"
10
+ },
7
11
  "license": "MIT",
8
12
  "author": "DXOS.org",
9
13
  "sideEffects": true,
10
14
  "type": "module",
11
- "imports": {
12
- "#hyperformula": {
13
- "types": "hyperformula",
14
- "default": "./dist/vendor/hyperformula.mjs"
15
- }
16
- },
17
15
  "exports": {
18
16
  ".": {
17
+ "source": "./src/index.ts",
19
18
  "types": "./dist/types/src/index.d.ts",
20
19
  "browser": "./dist/lib/browser/index.mjs",
21
20
  "node": "./dist/lib/node-esm/index.mjs"
22
21
  },
23
22
  "./testing": {
23
+ "source": "./src/testing/index.ts",
24
24
  "types": "./dist/types/src/testing/index.d.ts",
25
25
  "browser": "./dist/lib/browser/testing/index.mjs",
26
26
  "node": "./dist/lib/node-esm/testing/index.mjs"
@@ -39,35 +39,34 @@
39
39
  "src"
40
40
  ],
41
41
  "dependencies": {
42
- "@preact/signals-core": "^1.9.0",
43
- "effect": "3.16.13",
44
- "hyperformula": "^2.7.1",
42
+ "effect": "3.19.11",
45
43
  "lodash.defaultsdeep": "^4.6.1",
46
- "@dxos/async": "0.8.4-main.84f28bd",
47
- "@dxos/client": "0.8.4-main.84f28bd",
48
- "@dxos/context": "0.8.4-main.84f28bd",
49
- "@dxos/debug": "0.8.4-main.84f28bd",
50
- "@dxos/echo": "0.8.4-main.84f28bd",
51
- "@dxos/echo-db": "0.8.4-main.84f28bd",
52
- "@dxos/echo-schema": "0.8.4-main.84f28bd",
53
- "@dxos/functions": "0.8.4-main.84f28bd",
54
- "@dxos/invariant": "0.8.4-main.84f28bd",
55
- "@dxos/keys": "0.8.4-main.84f28bd",
56
- "@dxos/live-object": "0.8.4-main.84f28bd",
57
- "@dxos/log": "0.8.4-main.84f28bd",
58
- "@dxos/protocols": "0.8.4-main.84f28bd",
59
- "@dxos/schema": "0.8.4-main.84f28bd",
60
- "@dxos/util": "0.8.4-main.84f28bd"
44
+ "@dxos/async": "0.8.4-main.937b3ca",
45
+ "@dxos/client": "0.8.4-main.937b3ca",
46
+ "@dxos/ai": "0.8.4-main.937b3ca",
47
+ "@dxos/debug": "0.8.4-main.937b3ca",
48
+ "@dxos/context": "0.8.4-main.937b3ca",
49
+ "@dxos/functions": "0.8.4-main.937b3ca",
50
+ "@dxos/echo": "0.8.4-main.937b3ca",
51
+ "@dxos/functions-runtime": "0.8.4-main.937b3ca",
52
+ "@dxos/keys": "0.8.4-main.937b3ca",
53
+ "@dxos/invariant": "0.8.4-main.937b3ca",
54
+ "@dxos/log": "0.8.4-main.937b3ca",
55
+ "@dxos/plugin-automation": "0.8.4-main.937b3ca",
56
+ "@dxos/protocols": "0.8.4-main.937b3ca",
57
+ "@dxos/schema": "0.8.4-main.937b3ca",
58
+ "@dxos/util": "0.8.4-main.937b3ca",
59
+ "@dxos/vendor-hyperformula": "0.8.4-main.937b3ca"
61
60
  },
62
61
  "devDependencies": {
63
62
  "@tldraw/indices": "^2.0.0-alpha.14",
64
63
  "@types/lodash.defaultsdeep": "^4.6.6",
65
- "@dxos/echo-db": "0.8.4-main.84f28bd",
66
- "@dxos/random": "0.8.4-main.84f28bd",
67
- "@dxos/echo-schema": "0.8.4-main.84f28bd"
64
+ "@dxos/echo": "0.8.4-main.937b3ca",
65
+ "@dxos/echo-db": "0.8.4-main.937b3ca",
66
+ "@dxos/random": "0.8.4-main.937b3ca"
68
67
  },
69
68
  "peerDependencies": {
70
- "effect": "^3.13.3"
69
+ "effect": "3.19.11"
71
70
  },
72
71
  "publishConfig": {
73
72
  "access": "public"
@@ -0,0 +1,158 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+ import { describe, expect, onTestFinished, test } from 'vitest';
7
+
8
+ import { Trigger } from '@dxos/async';
9
+ import { Obj } from '@dxos/echo';
10
+ import { Function, FunctionDefinition } from '@dxos/functions';
11
+
12
+ import { ComputeGraphRegistry, defaultPlugins } from './compute-graph-registry';
13
+ import { TestBuilder, createMockedComputeRuntimeProvider } from './testing';
14
+
15
+ describe('ComputeGraphRegistry', () => {
16
+ const add = FunctionDefinition.make({
17
+ key: 'add',
18
+ name: 'add',
19
+ description: 'Adds two numbers',
20
+ inputSchema: Schema.Struct({ a: Schema.Number, b: Schema.Number }),
21
+ outputSchema: Schema.Number,
22
+ handler: ({ data }) => data.a + data.b,
23
+ });
24
+
25
+ test('invokes user function through compute graph', async () => {
26
+ const computeRuntime = createMockedComputeRuntimeProvider({
27
+ functions: [add],
28
+ });
29
+ const testBuilder = new TestBuilder({
30
+ types: [Function.Function],
31
+ computeRuntime,
32
+ });
33
+ await testBuilder.open();
34
+ onTestFinished(async () => {
35
+ await testBuilder.close();
36
+ });
37
+
38
+ const space = await testBuilder.client.spaces.create();
39
+
40
+ // Register Edge function plugin and runtime in the registry.
41
+ const registry = new ComputeGraphRegistry({
42
+ plugins: defaultPlugins,
43
+ computeRuntime,
44
+ });
45
+ await registry.open();
46
+ onTestFinished(async () => {
47
+ await registry.close();
48
+ });
49
+
50
+ const graph = registry.createGraph(space);
51
+ await graph.open();
52
+ onTestFinished(async () => {
53
+ await graph.close();
54
+ });
55
+
56
+ // Create a function object in ECHO with binding that maps to DX calls.
57
+ const functionObj = FunctionDefinition.serialize(add);
58
+ Obj.change(functionObj, (f) => {
59
+ f.binding = 'ADD';
60
+ });
61
+ space.db.add(functionObj);
62
+
63
+ const node = await graph.getOrCreateNode('sheet').open();
64
+
65
+ // Wait for value update after async invocation completes.
66
+ const trigger = new Trigger<number>();
67
+ node.update.on(() => {
68
+ const value = node.getValue({ row: 0, col: 0 });
69
+ if (typeof value === 'number') {
70
+ trigger.wake(value);
71
+ }
72
+ });
73
+
74
+ // Set formula using binding; graph will map to DX("ADD", ...)
75
+ node.setValue({ row: 0, col: 0 }, '=ADD(2, 3)');
76
+
77
+ const result = await trigger.wait();
78
+ expect(result).to.equal(5);
79
+
80
+ // Sanity check: mapping to fully qualified id works as well.
81
+ const bindingId = graph.mapFunctionBindingToId('ADD(2, 3)');
82
+ expect(bindingId.startsWith(`${Obj.getDXN(functionObj).toString()}`)).to.be.true;
83
+ });
84
+
85
+ test('adding a function binding updates autocomplete and enables execution', async () => {
86
+ const computeRuntime = createMockedComputeRuntimeProvider({
87
+ functions: [add],
88
+ });
89
+ const testBuilder = new TestBuilder({
90
+ types: [Function.Function],
91
+ computeRuntime,
92
+ });
93
+ await testBuilder.open();
94
+ onTestFinished(async () => {
95
+ await testBuilder.close();
96
+ });
97
+
98
+ const space = await testBuilder.client.spaces.create();
99
+
100
+ const registry = new ComputeGraphRegistry({
101
+ plugins: defaultPlugins,
102
+ computeRuntime,
103
+ });
104
+ await registry.open();
105
+ onTestFinished(async () => {
106
+ await registry.close();
107
+ });
108
+
109
+ const graph = registry.createGraph(space);
110
+ await graph.open();
111
+ onTestFinished(async () => {
112
+ await graph.close();
113
+ });
114
+
115
+ // Initially there should be no echo functions.
116
+ expect(graph.getFunctions({ standard: false, echo: true }).length).to.equal(0);
117
+
118
+ // Subscribe for function updates.
119
+ const functionsUpdated = new Trigger<void>();
120
+ const unsubscribe = graph.update.on((e) => {
121
+ if (e.type === 'functionsUpdated') {
122
+ functionsUpdated.wake();
123
+ }
124
+ });
125
+ onTestFinished(unsubscribe);
126
+
127
+ // Add a bound function to the space; graph should pick it up.
128
+ const functionObj = FunctionDefinition.serialize(add);
129
+ Obj.change(functionObj, (f) => {
130
+ f.binding = 'ADD';
131
+ });
132
+ space.db.add(functionObj);
133
+
134
+ await functionsUpdated.wait();
135
+
136
+ // Autocomplete should now include the binding.
137
+ const echoFunctions = graph.getFunctions({ standard: false, echo: true }).map((fn) => fn.name);
138
+ expect(echoFunctions).toContain('ADD');
139
+
140
+ // And the binding should execute when used in a formula.
141
+ const node = await graph.getOrCreateNode('sheet').open();
142
+ onTestFinished(async () => {
143
+ await node.close();
144
+ });
145
+
146
+ const valueSettled = new Trigger<number>();
147
+ node.update.on(() => {
148
+ const value = node.getValue({ row: 0, col: 0 });
149
+ if (typeof value === 'number') {
150
+ valueSettled.wake(value);
151
+ }
152
+ });
153
+
154
+ node.setValue({ row: 0, col: 0 }, '=ADD(2, 3)');
155
+ const result = await valueSettled.wait();
156
+ expect(result).to.equal(5);
157
+ });
158
+ });
@@ -2,17 +2,17 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import type { FunctionPluginDefinition } from 'hyperformula';
6
- import type { ConfigParams } from 'hyperformula/typings/ConfigParams';
7
- import type { FunctionTranslationsPackage } from 'hyperformula/typings/interpreter';
5
+ import type * as ManagedRuntime from 'effect/ManagedRuntime';
8
6
  import defaultsDeep from 'lodash.defaultsdeep';
9
7
 
10
- import { type SpaceId, type Space } from '@dxos/client/echo';
8
+ import { type Space, type SpaceId } from '@dxos/client/echo';
11
9
  import { Resource } from '@dxos/context';
10
+ import { type FunctionInvocationService } from '@dxos/functions';
12
11
  import { invariant } from '@dxos/invariant';
13
12
  import { log } from '@dxos/log';
13
+ import type { ConfigParams, FunctionPluginDefinition, FunctionTranslationsPackage } from '@dxos/vendor-hyperformula';
14
+ import { HyperFormula } from '@dxos/vendor-hyperformula';
14
15
 
15
- import { HyperFormula } from '#hyperformula';
16
16
  import { ComputeGraph } from './compute-graph';
17
17
  import { EdgeFunctionPlugin, EdgeFunctionPluginTranslations, type FunctionContextOptions } from './functions';
18
18
 
@@ -21,15 +21,16 @@ export type ComputeGraphPlugin = {
21
21
  translations: FunctionTranslationsPackage;
22
22
  };
23
23
 
24
+ export type FunctionsRuntimeProvider = {
25
+ getRuntime(spaceId: SpaceId): ManagedRuntime.ManagedRuntime<FunctionInvocationService, never>;
26
+ };
27
+
24
28
  export type ComputeGraphOptions = {
25
29
  plugins?: ComputeGraphPlugin[];
30
+ computeRuntime: FunctionsRuntimeProvider;
26
31
  } & Partial<FunctionContextOptions> &
27
32
  Partial<ConfigParams>;
28
33
 
29
- export const defaultOptions: ComputeGraphOptions = {
30
- licenseKey: 'gpl-v3',
31
- };
32
-
33
34
  export const defaultPlugins: ComputeGraphPlugin[] = [
34
35
  {
35
36
  plugin: EdgeFunctionPlugin,
@@ -37,23 +38,26 @@ export const defaultPlugins: ComputeGraphPlugin[] = [
37
38
  },
38
39
  ];
39
40
 
41
+ export const defaultOptions: Partial<ComputeGraphOptions> = {
42
+ licenseKey: 'gpl-v3',
43
+ };
44
+
40
45
  /**
41
46
  * Manages a collection of ComputeGraph instances for each space.
42
47
  *
43
48
  * [ComputePlugin] => [ComputeGraphRegistry] => [ComputeGraph(Space)] => [ComputeNode(Object)]
44
49
  *
45
50
  * NOTE: The ComputeGraphRegistry manages the hierarchy of resources via its root Context.
46
- * NOTE: The package.json file defines the packaged #hyperformula module.
47
51
  */
48
52
  // TODO(burdon): Move graph into separate plugin; isolate HF deps.
49
53
  export class ComputeGraphRegistry extends Resource {
50
54
  private readonly _graphs = new Map<SpaceId, ComputeGraph>();
51
-
52
55
  private readonly _options: ComputeGraphOptions;
53
56
 
54
- constructor(options: ComputeGraphOptions = { plugins: defaultPlugins }) {
57
+ constructor(options: ComputeGraphOptions) {
55
58
  super();
56
59
  this._options = defaultsDeep({}, options, defaultOptions);
60
+ this._options.plugins = this._options.plugins ?? defaultPlugins;
57
61
  this._options.plugins?.forEach(({ plugin, translations }) => {
58
62
  HyperFormula.registerFunctionPlugin(plugin, translations);
59
63
  });
@@ -76,7 +80,10 @@ export class ComputeGraphRegistry extends Resource {
76
80
  createGraph(space: Space): ComputeGraph {
77
81
  invariant(!this._graphs.has(space.id), `ComputeGraph already exists for space: ${space.id}`);
78
82
  const hf = HyperFormula.buildEmpty(this._options);
79
- const graph = new ComputeGraph(hf, space, this._options);
83
+ invariant(this._options.computeRuntime, 'ComputeRuntime is required');
84
+ const runtime = this._options.computeRuntime.getRuntime(space.id);
85
+
86
+ const graph = new ComputeGraph(hf, runtime, space, this._options);
80
87
  this._graphs.set(space.id, graph);
81
88
  return graph;
82
89
  }
@@ -2,21 +2,20 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { type CellValue } from 'hyperformula';
6
5
  import { afterEach, beforeEach, describe, expect, test } from 'vitest';
7
6
 
8
7
  import { Trigger } from '@dxos/async';
9
- import { fullyQualifiedId } from '@dxos/client/echo';
10
8
  import { Obj } from '@dxos/echo';
11
- import { FunctionType } from '@dxos/functions';
9
+ import { Function } from '@dxos/functions';
10
+ import { type CellValue } from '@dxos/vendor-hyperformula';
11
+ import { DetailedCellError } from '@dxos/vendor-hyperformula';
12
12
 
13
- import { DetailedCellError } from '#hyperformula';
14
13
  import { TestBuilder } from './testing';
15
14
 
16
15
  describe('ComputeGraph', () => {
17
16
  let testBuilder: TestBuilder;
18
17
  beforeEach(async () => {
19
- testBuilder = new TestBuilder({ types: [FunctionType] });
18
+ testBuilder = new TestBuilder({ types: [Function.Function] });
20
19
  await testBuilder.open();
21
20
  });
22
21
  afterEach(async () => {
@@ -31,13 +30,13 @@ describe('ComputeGraph', () => {
31
30
  // Create script.
32
31
  const trigger = new Trigger();
33
32
  graph.update.once(() => trigger.wake());
34
- const functionObject = space.db.add(Obj.make(FunctionType, { name: 'test', version: '0.0.1', binding: 'TEST' }));
33
+ const functionObject = space.db.add(Function.make({ name: 'test', version: '0.0.1', binding: 'TEST' }));
35
34
  await trigger.wait();
36
35
  const functions = graph.getFunctions({ echo: true });
37
36
  expect(functions).to.toHaveLength(1);
38
37
 
39
38
  const id = graph.mapFunctionBindingToId('TEST()');
40
- expect(id).to.eq(`${fullyQualifiedId(functionObject)}()`);
39
+ expect(id).to.eq(`${Obj.getDXN(functionObject).toString()}()`);
41
40
  });
42
41
 
43
42
  test('cross-node references', async () => {
@@ -52,22 +51,38 @@ describe('ComputeGraph', () => {
52
51
  {
53
52
  node1.graph.hf.setCellContents({ sheet: node1.sheetId, row: 0, col: 0 }, [[100, 200, 300, '=SUM(A1:C1)']]);
54
53
  node2.graph.hf.setCellContents({ sheet: node2.sheetId, row: 0, col: 0 }, "='node-1'!D1");
55
- const value1 = node1.graph.hf.getCellValue({ sheet: node1.sheetId, col: 3, row: 0 });
56
- const value2 = node2.graph.hf.getCellValue({ sheet: node2.sheetId, col: 0, row: 0 });
54
+ const value1 = node1.graph.hf.getCellValue({
55
+ sheet: node1.sheetId,
56
+ col: 3,
57
+ row: 0,
58
+ });
59
+ const value2 = node2.graph.hf.getCellValue({
60
+ sheet: node2.sheetId,
61
+ col: 0,
62
+ row: 0,
63
+ });
57
64
  expect(value1).to.eq(value2);
58
65
  }
59
66
 
60
67
  // Get updated event.
61
68
  const trigger = new Trigger<CellValue>();
62
69
  node2.update.on(({ change }) => {
63
- const value = node2.graph.hf.getCellValue({ sheet: node2.sheetId, col: 0, row: 0 });
70
+ const value = node2.graph.hf.getCellValue({
71
+ sheet: node2.sheetId,
72
+ col: 0,
73
+ row: 0,
74
+ });
64
75
  expect(value).to.eq(change?.newValue);
65
76
  trigger.wake(value);
66
77
  });
67
78
 
68
79
  {
69
80
  node1.graph.hf.setCellContents({ sheet: node1.sheetId, row: 0, col: 0 }, 400);
70
- const value1 = node1.graph.hf.getCellValue({ sheet: node1.sheetId, col: 3, row: 0 });
81
+ const value1 = node1.graph.hf.getCellValue({
82
+ sheet: node1.sheetId,
83
+ col: 3,
84
+ row: 0,
85
+ });
71
86
  const value2 = await trigger.wait();
72
87
  expect(value1).to.eq(value2);
73
88
  }
@@ -81,7 +96,11 @@ describe('ComputeGraph', () => {
81
96
 
82
97
  const node1 = await graph.getOrCreateNode('node-1').open();
83
98
  node1.graph.hf.setCellContents({ sheet: node1.sheetId, row: 0, col: 0 }, "='node-2'!A1");
84
- const value1 = node1.graph.hf.getCellValue({ sheet: node1.sheetId, col: 0, row: 0 });
99
+ const value1 = node1.graph.hf.getCellValue({
100
+ sheet: node1.sheetId,
101
+ col: 0,
102
+ row: 0,
103
+ });
85
104
  expect(value1).to.be.instanceof(DetailedCellError);
86
105
  expect((value1 as DetailedCellError).type).to.eq('REF');
87
106
  });
@@ -2,27 +2,28 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { type Listeners } from 'hyperformula/typings/Emitter';
5
+ import type * as ManagedRuntime from 'effect/ManagedRuntime';
6
6
 
7
7
  import { Event } from '@dxos/async';
8
- import { type Space, Filter, fullyQualifiedId } from '@dxos/client/echo';
8
+ import { Filter, type Space } from '@dxos/client/echo';
9
9
  import { FQ_ID_LENGTH } from '@dxos/client/echo';
10
10
  import { Resource } from '@dxos/context';
11
- import { getTypename } from '@dxos/echo-schema';
12
- import { FunctionType } from '@dxos/functions';
11
+ import { Obj } from '@dxos/echo';
12
+ import { Function, type FunctionInvocationService } from '@dxos/functions';
13
13
  import { invariant } from '@dxos/invariant';
14
14
  import { PublicKey } from '@dxos/keys';
15
15
  import { log } from '@dxos/log';
16
16
  import { isNonNullable } from '@dxos/util';
17
+ import type { Listeners } from '@dxos/vendor-hyperformula';
18
+ import { ExportedCellChange, type HyperFormula } from '@dxos/vendor-hyperformula';
17
19
 
18
- import { ExportedCellChange, type HyperFormula } from '#hyperformula';
19
20
  import { ComputeNode } from './compute-node';
20
21
  import {
21
- defaultFunctions,
22
+ EDGE_FUNCTION_NAME,
22
23
  FunctionContext,
23
24
  type FunctionContextOptions,
24
25
  type FunctionDefinition,
25
- EDGE_FUNCTION_NAME,
26
+ defaultFunctions,
26
27
  } from './functions';
27
28
 
28
29
  // TODO(burdon): Factor out compute-graph.
@@ -59,7 +60,7 @@ export class ComputeGraph extends Resource {
59
60
  private readonly _nodes = new Map<number, ComputeNode>();
60
61
 
61
62
  // Cached function objects.
62
- private _remoteFunctions: FunctionType[] = [];
63
+ private _remoteFunctions: Function.Function[] = [];
63
64
 
64
65
  public readonly update = new Event<{ type: ComputeGraphEvent }>();
65
66
 
@@ -68,12 +69,13 @@ export class ComputeGraph extends Resource {
68
69
 
69
70
  constructor(
70
71
  private readonly _hf: HyperFormula,
72
+ private readonly _runtime: ManagedRuntime.ManagedRuntime<FunctionInvocationService, never>,
71
73
  private readonly _space?: Space,
72
74
  private readonly _options?: Partial<FunctionContextOptions>,
73
75
  ) {
74
76
  super();
75
77
 
76
- this.context = new FunctionContext(this._hf, this._space, {
78
+ this.context = new FunctionContext(this._hf, this._runtime, this._space, {
77
79
  ...this._options,
78
80
  onUpdate: (update) => {
79
81
  this._options?.onUpdate?.(update);
@@ -104,7 +106,10 @@ export class ComputeGraph extends Resource {
104
106
  }
105
107
 
106
108
  getFunctions(
107
- { standard, echo }: { standard?: boolean; echo?: boolean } = { standard: true, echo: true },
109
+ { standard, echo }: { standard?: boolean; echo?: boolean } = {
110
+ standard: true,
111
+ echo: true,
112
+ },
108
113
  ): FunctionDefinition[] {
109
114
  return [
110
115
  ...(standard
@@ -164,7 +169,7 @@ export class ComputeGraph extends Resource {
164
169
 
165
170
  for (const obj of objects) {
166
171
  if (obj.name === name) {
167
- const type = getTypename(obj)!;
172
+ const type = Obj.getTypename(obj)!;
168
173
  // NOTE: Names must be single quoted.
169
174
  return `'${createSheetName({ type, id: obj.id })}'!`;
170
175
  }
@@ -204,7 +209,7 @@ export class ComputeGraph extends Resource {
204
209
 
205
210
  const fn = this._remoteFunctions.find((fn) => fn.binding === binding);
206
211
  if (fn) {
207
- const id = fullyQualifiedId(fn);
212
+ const id = Obj.getDXN(fn).toString();
208
213
  return `${id}(${args})`;
209
214
  } else {
210
215
  return match;
@@ -223,7 +228,7 @@ export class ComputeGraph extends Resource {
223
228
  return match;
224
229
  }
225
230
 
226
- const fn = this._remoteFunctions.find((fn) => fullyQualifiedId(fn) === id);
231
+ const fn = this._remoteFunctions.find((fn) => Obj.getDXN(fn).toString() === id);
227
232
  if (fn?.binding) {
228
233
  return `${fn.binding}(${args})`;
229
234
  } else {
@@ -241,9 +246,9 @@ export class ComputeGraph extends Resource {
241
246
  protected override async _open(): Promise<void> {
242
247
  if (this._space) {
243
248
  // Subscribe to remote function definitions.
244
- const query = this._space.db.query(Filter.type(FunctionType));
245
- const unsubscribe = query.subscribe(({ objects }) => {
246
- this._remoteFunctions = objects.filter(({ binding }) => binding);
249
+ const query = this._space.db.query(Filter.type(Function.Function));
250
+ const unsubscribe = query.subscribe(() => {
251
+ this._remoteFunctions = query.results.filter((fn) => fn.binding);
247
252
  this.update.emit({ type: 'functionsUpdated' });
248
253
  });
249
254
 
@@ -2,13 +2,11 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { type Listeners } from 'hyperformula/typings/Emitter';
6
- import { type ExportedCellChange } from 'hyperformula/typings/Exporter';
7
-
8
5
  import { Event } from '@dxos/async';
9
6
  import { Resource } from '@dxos/context';
7
+ import { type ExportedCellChange, type Listeners } from '@dxos/vendor-hyperformula';
8
+ import { DetailedCellError } from '@dxos/vendor-hyperformula';
10
9
 
11
- import { DetailedCellError } from '#hyperformula';
12
10
  import { type ComputeGraph } from './compute-graph';
13
11
  import { type CellAddress, type CellScalarValue, isFormula } from './types';
14
12
 
@@ -2,17 +2,18 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { type SimpleCellAddress } from 'hyperformula/typings/Cell';
6
- import { type InterpreterState } from 'hyperformula/typings/interpreter/InterpreterState';
7
- import { type InterpreterValue } from 'hyperformula/typings/interpreter/InterpreterValue';
8
- import { type ProcedureAst } from 'hyperformula/typings/parser';
5
+ import type * as ManagedRuntime from 'effect/ManagedRuntime';
9
6
  import defaultsDeep from 'lodash.defaultsdeep';
10
7
 
11
- import { debounce, type CleanupFn } from '@dxos/async';
12
- import { type Space } from '@dxos/client/echo';
8
+ import { type CleanupFn, debounce } from '@dxos/async';
9
+ import type { Space } from '@dxos/client/echo';
10
+ import { type FunctionInvocationService } from '@dxos/functions';
13
11
  import { log } from '@dxos/log';
14
-
15
- import { CellError, ErrorType, EmptyValue, FunctionPlugin, type HyperFormula } from '#hyperformula';
12
+ import type { RawInterpreterValue, SimpleCellAddress } from '@dxos/vendor-hyperformula';
13
+ import type { InterpreterState } from '@dxos/vendor-hyperformula';
14
+ import type { InterpreterValue } from '@dxos/vendor-hyperformula';
15
+ import type { ProcedureAst } from '@dxos/vendor-hyperformula';
16
+ import { CellError, EmptyValue, ErrorType, FunctionPlugin, type HyperFormula } from '@dxos/vendor-hyperformula';
16
17
 
17
18
  // TODO(burdon): Create API gateways:
18
19
  // https://publicapis.io
@@ -34,14 +35,12 @@ export type FunctionOptions = {
34
35
  export type FunctionContextOptions = {
35
36
  defaultTtl: number;
36
37
  debounceDelay: number;
37
- remoteFunctionUrl: string;
38
38
  onUpdate?: (update: FunctionUpdateEvent) => void;
39
39
  };
40
40
 
41
- export const defaultFunctionContextOptions: FunctionContextOptions = {
41
+ export const defaultFunctionContextOptions: Pick<FunctionContextOptions, 'defaultTtl' | 'debounceDelay'> = {
42
42
  defaultTtl: 5_000,
43
43
  debounceDelay: 200,
44
- remoteFunctionUrl: 'https://edge.dxos.workers.dev/functions', // TODO(burdon): Config.
45
44
  };
46
45
 
47
46
  /**
@@ -78,6 +77,7 @@ export class FunctionContext {
78
77
 
79
78
  constructor(
80
79
  private readonly _hf: HyperFormula,
80
+ private readonly _runtime: ManagedRuntime.ManagedRuntime<FunctionInvocationService, never>,
81
81
  private readonly _space: Space | undefined,
82
82
  _options?: Partial<FunctionContextOptions>,
83
83
  ) {
@@ -94,14 +94,14 @@ export class FunctionContext {
94
94
  return this._space;
95
95
  }
96
96
 
97
- get remoteFunctionUrl() {
98
- return this._options.remoteFunctionUrl;
99
- }
100
-
101
97
  get info() {
102
98
  return { cache: this._cache.size, invocations: this._invocations };
103
99
  }
104
100
 
101
+ get runtime() {
102
+ return this._runtime;
103
+ }
104
+
105
105
  flush(): void {
106
106
  this._cache.clear();
107
107
  this._invocations = {};
@@ -169,7 +169,12 @@ export class AsyncFunctionPlugin extends FunctionPlugin {
169
169
  /**
170
170
  * Immediately returns cached value then runs the async function.
171
171
  */
172
- protected runAsyncFunction(ast: ProcedureAst, state: InterpreterState, cb: AsyncFunction, options?: FunctionOptions) {
172
+ protected runAsyncFunction(
173
+ ast: ProcedureAst,
174
+ state: InterpreterState,
175
+ cb: AsyncFunction,
176
+ options?: FunctionOptions,
177
+ ): RawInterpreterValue {
173
178
  const { procedureName } = ast;
174
179
  const metadata = this.metadata(procedureName);
175
180
  return this.runFunction(ast.args, state, metadata, (...args: any) => {