@dxos/compute 0.8.4-main.bc674ce → 0.8.4-main.bcb3aa67d6

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/compute",
3
- "version": "0.8.4-main.bc674ce",
3
+ "version": "0.8.4-main.bcb3aa67d6",
4
4
  "description": "Low-level compute API",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -16,14 +16,12 @@
16
16
  ".": {
17
17
  "source": "./src/index.ts",
18
18
  "types": "./dist/types/src/index.d.ts",
19
- "browser": "./dist/lib/browser/index.mjs",
20
- "node": "./dist/lib/node-esm/index.mjs"
19
+ "default": "./dist/lib/neutral/index.mjs"
21
20
  },
22
21
  "./testing": {
23
22
  "source": "./src/testing/index.ts",
24
23
  "types": "./dist/types/src/testing/index.d.ts",
25
- "browser": "./dist/lib/browser/testing/index.mjs",
26
- "node": "./dist/lib/node-esm/testing/index.mjs"
24
+ "default": "./dist/lib/neutral/testing/index.mjs"
27
25
  }
28
26
  },
29
27
  "types": "dist/types/src/index.d.ts",
@@ -39,34 +37,35 @@
39
37
  "src"
40
38
  ],
41
39
  "dependencies": {
42
- "effect": "3.19.11",
40
+ "effect": "3.20.0",
43
41
  "lodash.defaultsdeep": "^4.6.1",
44
- "@dxos/ai": "0.8.4-main.bc674ce",
45
- "@dxos/async": "0.8.4-main.bc674ce",
46
- "@dxos/context": "0.8.4-main.bc674ce",
47
- "@dxos/debug": "0.8.4-main.bc674ce",
48
- "@dxos/client": "0.8.4-main.bc674ce",
49
- "@dxos/echo": "0.8.4-main.bc674ce",
50
- "@dxos/functions": "0.8.4-main.bc674ce",
51
- "@dxos/functions-runtime": "0.8.4-main.bc674ce",
52
- "@dxos/invariant": "0.8.4-main.bc674ce",
53
- "@dxos/keys": "0.8.4-main.bc674ce",
54
- "@dxos/log": "0.8.4-main.bc674ce",
55
- "@dxos/plugin-automation": "0.8.4-main.bc674ce",
56
- "@dxos/schema": "0.8.4-main.bc674ce",
57
- "@dxos/util": "0.8.4-main.bc674ce",
58
- "@dxos/protocols": "0.8.4-main.bc674ce",
59
- "@dxos/vendor-hyperformula": "0.8.4-main.bc674ce"
42
+ "@dxos/async": "0.8.4-main.bcb3aa67d6",
43
+ "@dxos/context": "0.8.4-main.bcb3aa67d6",
44
+ "@dxos/debug": "0.8.4-main.bcb3aa67d6",
45
+ "@dxos/echo": "0.8.4-main.bcb3aa67d6",
46
+ "@dxos/ai": "0.8.4-main.bcb3aa67d6",
47
+ "@dxos/client": "0.8.4-main.bcb3aa67d6",
48
+ "@dxos/functions": "0.8.4-main.bcb3aa67d6",
49
+ "@dxos/invariant": "0.8.4-main.bcb3aa67d6",
50
+ "@dxos/keys": "0.8.4-main.bcb3aa67d6",
51
+ "@dxos/functions-runtime": "0.8.4-main.bcb3aa67d6",
52
+ "@dxos/operation": "0.8.4-main.bcb3aa67d6",
53
+ "@dxos/log": "0.8.4-main.bcb3aa67d6",
54
+ "@dxos/schema": "0.8.4-main.bcb3aa67d6",
55
+ "@dxos/vendor-hyperformula": "0.8.4-main.bcb3aa67d6",
56
+ "@dxos/plugin-automation": "0.8.4-main.bcb3aa67d6",
57
+ "@dxos/util": "0.8.4-main.bcb3aa67d6",
58
+ "@dxos/protocols": "0.8.4-main.bcb3aa67d6"
60
59
  },
61
60
  "devDependencies": {
62
61
  "@tldraw/indices": "^2.0.0-alpha.14",
63
62
  "@types/lodash.defaultsdeep": "^4.6.6",
64
- "@dxos/echo": "0.8.4-main.bc674ce",
65
- "@dxos/echo-db": "0.8.4-main.bc674ce",
66
- "@dxos/random": "0.8.4-main.bc674ce"
63
+ "@dxos/echo": "0.8.4-main.bcb3aa67d6",
64
+ "@dxos/echo-db": "0.8.4-main.bcb3aa67d6",
65
+ "@dxos/random": "0.8.4-main.bcb3aa67d6"
67
66
  },
68
67
  "peerDependencies": {
69
- "effect": "3.19.11"
68
+ "effect": "3.20.0"
70
69
  },
71
70
  "publishConfig": {
72
71
  "access": "public"
@@ -2,32 +2,43 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ import * as Effect from 'effect/Effect';
5
6
  import * as Schema from 'effect/Schema';
6
7
  import { describe, expect, onTestFinished, test } from 'vitest';
7
8
 
8
9
  import { Trigger } from '@dxos/async';
9
10
  import { Obj } from '@dxos/echo';
10
- import { Function, FunctionDefinition } from '@dxos/functions';
11
+ import { Operation, OperationHandlerSet } from '@dxos/operation';
11
12
 
12
13
  import { ComputeGraphRegistry, defaultPlugins } from './compute-graph-registry';
13
14
  import { TestBuilder, createMockedComputeRuntimeProvider } from './testing';
14
15
 
15
- describe('ComputeGraphRegistry', () => {
16
- const add = FunctionDefinition.make({
16
+ const AddDefinition = Operation.make({
17
+ meta: {
17
18
  key: 'add',
18
19
  name: 'add',
19
20
  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
- });
21
+ },
22
+ input: Schema.Struct({ a: Schema.Number, b: Schema.Number }),
23
+ output: Schema.Number,
24
+ services: [],
25
+ });
24
26
 
27
+ const add = AddDefinition.pipe(
28
+ Operation.withHandler(
29
+ Effect.fn(function* ({ a, b }) {
30
+ return a + b;
31
+ }),
32
+ ),
33
+ );
34
+
35
+ describe('ComputeGraphRegistry', () => {
25
36
  test('invokes user function through compute graph', async () => {
26
37
  const computeRuntime = createMockedComputeRuntimeProvider({
27
- functions: [add],
38
+ functions: OperationHandlerSet.make(add),
28
39
  });
29
40
  const testBuilder = new TestBuilder({
30
- types: [Function.Function],
41
+ types: [Operation.PersistentOperation],
31
42
  computeRuntime,
32
43
  });
33
44
  await testBuilder.open();
@@ -53,10 +64,9 @@ describe('ComputeGraphRegistry', () => {
53
64
  await graph.close();
54
65
  });
55
66
 
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';
67
+ const functionObj = Operation.serialize(add);
68
+ Obj.change(functionObj, (obj) => {
69
+ obj.binding = 'ADD';
60
70
  });
61
71
  space.db.add(functionObj);
62
72
 
@@ -84,10 +94,10 @@ describe('ComputeGraphRegistry', () => {
84
94
 
85
95
  test('adding a function binding updates autocomplete and enables execution', async () => {
86
96
  const computeRuntime = createMockedComputeRuntimeProvider({
87
- functions: [add],
97
+ functions: OperationHandlerSet.make(add),
88
98
  });
89
99
  const testBuilder = new TestBuilder({
90
- types: [Function.Function],
100
+ types: [Operation.PersistentOperation],
91
101
  computeRuntime,
92
102
  });
93
103
  await testBuilder.open();
@@ -124,10 +134,9 @@ describe('ComputeGraphRegistry', () => {
124
134
  });
125
135
  onTestFinished(unsubscribe);
126
136
 
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';
137
+ const functionObj = Operation.serialize(add);
138
+ Obj.change(functionObj, (obj) => {
139
+ obj.binding = 'ADD';
131
140
  });
132
141
  space.db.add(functionObj);
133
142
 
@@ -6,7 +6,7 @@ import { afterEach, beforeEach, describe, expect, test } from 'vitest';
6
6
 
7
7
  import { Trigger } from '@dxos/async';
8
8
  import { Obj } from '@dxos/echo';
9
- import { Function } from '@dxos/functions';
9
+ import { Operation } from '@dxos/operation';
10
10
  import { type CellValue } from '@dxos/vendor-hyperformula';
11
11
  import { DetailedCellError } from '@dxos/vendor-hyperformula';
12
12
 
@@ -15,7 +15,7 @@ import { TestBuilder } from './testing';
15
15
  describe('ComputeGraph', () => {
16
16
  let testBuilder: TestBuilder;
17
17
  beforeEach(async () => {
18
- testBuilder = new TestBuilder({ types: [Function.Function] });
18
+ testBuilder = new TestBuilder({ types: [Operation.PersistentOperation] });
19
19
  await testBuilder.open();
20
20
  });
21
21
  afterEach(async () => {
@@ -30,13 +30,45 @@ describe('ComputeGraph', () => {
30
30
  // Create script.
31
31
  const trigger = new Trigger();
32
32
  graph.update.once(() => trigger.wake());
33
- const functionObject = space.db.add(Function.make({ name: 'test', version: '0.0.1', binding: 'TEST' }));
33
+ const functionObject = space.db.add(
34
+ Obj.make(Operation.PersistentOperation, { name: 'test', version: '0.0.1', binding: 'TEST' }),
35
+ );
34
36
  await trigger.wait();
35
37
  const functions = graph.getFunctions({ echo: true });
36
38
  expect(functions).to.toHaveLength(1);
37
39
 
38
40
  const id = graph.mapFunctionBindingToId('TEST()');
39
41
  expect(id).to.eq(`${Obj.getDXN(functionObject).toString()}()`);
42
+
43
+ const restored = graph.mapFunctionBindingFromId(id);
44
+ expect(restored).to.eq('TEST()');
45
+ });
46
+
47
+ test('map functions roundtrip with args', async () => {
48
+ const space = await testBuilder.client.spaces.create();
49
+ const graph = testBuilder.registry.createGraph(space);
50
+ await graph.open();
51
+
52
+ const trigger = new Trigger();
53
+ graph.update.once(() => trigger.wake());
54
+ space.db.add(Obj.make(Operation.PersistentOperation, { name: 'forex', version: '0.0.1', binding: 'FOREX' }));
55
+ await trigger.wait();
56
+
57
+ const stored = graph.mapFunctionBindingToId('=FOREX(C6,C7)');
58
+ expect(stored).to.include('dxn:echo:');
59
+ expect(stored).not.to.include('FOREX');
60
+
61
+ const restored = graph.mapFunctionBindingFromId(stored);
62
+ expect(restored).to.eq('=FOREX(C6,C7)');
63
+ });
64
+
65
+ test('map functions unknown binding returns undefined', async () => {
66
+ const space = await testBuilder.client.spaces.create();
67
+ const graph = testBuilder.registry.createGraph(space);
68
+ await graph.open();
69
+
70
+ const result = graph.mapFunctionBindingFromId('=dxn:echo:@:01ABCDEF01ABCDEF01ABCDEF01(A1,B1)');
71
+ expect(result).to.be.undefined;
40
72
  });
41
73
 
42
74
  test('cross-node references', async () => {
@@ -6,10 +6,10 @@ import type * as ManagedRuntime from 'effect/ManagedRuntime';
6
6
 
7
7
  import { Event } from '@dxos/async';
8
8
  import { Filter, type Space } from '@dxos/client/echo';
9
- import { FQ_ID_LENGTH } from '@dxos/client/echo';
10
9
  import { Resource } from '@dxos/context';
11
10
  import { Obj } from '@dxos/echo';
12
- import { Function, type FunctionInvocationService } from '@dxos/functions';
11
+ import { type FunctionInvocationService } from '@dxos/functions';
12
+ import { Operation } from '@dxos/operation';
13
13
  import { invariant } from '@dxos/invariant';
14
14
  import { PublicKey } from '@dxos/keys';
15
15
  import { log } from '@dxos/log';
@@ -37,7 +37,7 @@ type ObjectRef = { type: string; id: string };
37
37
 
38
38
  /**
39
39
  * Marker for sheets that are managed by an ECHO object.
40
- * Sheet ID: `dxos.org/type/SheetType@1234`
40
+ * Sheet ID: `org.dxos.type.sheet-type@1234`
41
41
  */
42
42
  export const createSheetName = ({ type, id }: ObjectRef) => `${type}@${id}`;
43
43
  export const parseSheetName = (name: string): Partial<ObjectRef> => {
@@ -60,7 +60,7 @@ export class ComputeGraph extends Resource {
60
60
  private readonly _nodes = new Map<number, ComputeNode>();
61
61
 
62
62
  // Cached function objects.
63
- private _remoteFunctions: Function.Function[] = [];
63
+ private _remoteFunctions: Operation.PersistentOperation[] = [];
64
64
 
65
65
  public readonly update = new Event<{ type: ComputeGraphEvent }>();
66
66
 
@@ -153,7 +153,7 @@ export class ComputeGraph extends Resource {
153
153
  formula
154
154
  //
155
155
  // Map cross-sheet references by name onto sheet stored by ECHO object/model.
156
- // Example: "Test Sheet"!A0 => "dxos.org/type/SheetType@1234"!A0
156
+ // Example: "Test Sheet"!A0 => "org.dxos.type.sheet-type@1234"!A0
157
157
  // https://hyperformula.handsontable.com/guide/cell-references.html#cell-references
158
158
  //
159
159
  .replace(/['"]?([ \w]+)['"]?!/, (_match, name) => {
@@ -198,8 +198,8 @@ export class ComputeGraph extends Resource {
198
198
  }
199
199
 
200
200
  /**
201
- * Map from binding to fully qualified ECHO ID (to store).
202
- * E.g., HELLO() => spaceId:objectId()
201
+ * Map from binding to fully qualified ECHO DXN (to store).
202
+ * E.g., HELLO() => dxn:echo:spaceId:objectId()
203
203
  */
204
204
  mapFunctionBindingToId(formula: string): string {
205
205
  return formula.replace(/(\w+)\((.*)\)/g, (match, binding, args) => {
@@ -218,23 +218,22 @@ export class ComputeGraph extends Resource {
218
218
  }
219
219
 
220
220
  /**
221
- * Map from fully qualified ECHO ID to binding (from store).
222
- * E.g., spaceId:objectId() => HELLO()
221
+ * Map from fully qualified ECHO DXN to binding (from store).
222
+ * E.g., dxn:echo:spaceId:objectId() => HELLO()
223
223
  */
224
224
  mapFunctionBindingFromId(formula: string): string | undefined {
225
- const binding = formula.replace(/(\w+):([a-zA-Z0-9]+)\((.*)\)/g, (match, spaceId, objectId, args) => {
226
- const id = `${spaceId}:${objectId}`;
227
- if (id.length !== FQ_ID_LENGTH) {
228
- return match;
229
- }
230
-
231
- const fn = this._remoteFunctions.find((fn) => Obj.getDXN(fn).toString() === id);
232
- if (fn?.binding) {
233
- return `${fn.binding}(${args})`;
234
- } else {
235
- return UNKNOWN_BINDING;
236
- }
237
- });
225
+ const binding = formula.replace(
226
+ /dxn:([^:]+):([^:(]+):([a-zA-Z0-9]+)\((.*)\)/g,
227
+ (_match, kind, spaceTag, objectId, args) => {
228
+ const dxn = `dxn:${kind}:${spaceTag}:${objectId}`;
229
+ const fn = this._remoteFunctions.find((fn) => Obj.getDXN(fn).toString() === dxn);
230
+ if (fn?.binding) {
231
+ return `${fn.binding}(${args})`;
232
+ } else {
233
+ return UNKNOWN_BINDING;
234
+ }
235
+ },
236
+ );
238
237
 
239
238
  if (binding.startsWith(`=${UNKNOWN_BINDING}`)) {
240
239
  return undefined;
@@ -246,11 +245,14 @@ export class ComputeGraph extends Resource {
246
245
  protected override async _open(): Promise<void> {
247
246
  if (this._space) {
248
247
  // Subscribe to remote function definitions.
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);
252
- this.update.emit({ type: 'functionsUpdated' });
253
- });
248
+ const query = this._space.db.query(Filter.type(Operation.PersistentOperation));
249
+ const unsubscribe = query.subscribe(
250
+ () => {
251
+ this._remoteFunctions = query.results.filter((fn) => fn.binding);
252
+ this.update.emit({ type: 'functionsUpdated' });
253
+ },
254
+ { fire: true },
255
+ );
254
256
 
255
257
  this._ctx.onDispose(unsubscribe);
256
258
  }
@@ -7,8 +7,8 @@ import * as SchemaAST from 'effect/SchemaAST';
7
7
 
8
8
  import { Filter } from '@dxos/client/echo';
9
9
  import { JsonSchema, Obj } from '@dxos/echo';
10
- import { Function, FunctionInvocationService, TracingService } from '@dxos/functions';
11
- import { FunctionDefinition } from '@dxos/functions';
10
+ import { FunctionInvocationService, TracingService } from '@dxos/functions';
11
+ import { Operation } from '@dxos/operation';
12
12
  import { log } from '@dxos/log';
13
13
  import { isNonNullable } from '@dxos/util';
14
14
  import { type ProcedureAst } from '@dxos/vendor-hyperformula';
@@ -35,7 +35,7 @@ export class EdgeFunctionPlugin extends AsyncFunctionPlugin {
35
35
  return new CellError(ErrorType.REF, 'Missing space');
36
36
  }
37
37
 
38
- const [fn] = await space.db.query(Filter.type(Function.Function, { binding })).run();
38
+ const [fn] = await space.db.query(Filter.type(Operation.PersistentOperation, { binding })).run();
39
39
  if (!fn) {
40
40
  log.info('Function not found', { binding });
41
41
  return new CellError(ErrorType.REF, 'Function not found');
@@ -55,7 +55,7 @@ export class EdgeFunctionPlugin extends AsyncFunctionPlugin {
55
55
  }
56
56
 
57
57
  const runtime = this.context.runtime;
58
- const functionDef = FunctionDefinition.deserialize(fn);
58
+ const functionDef = Operation.deserialize(fn);
59
59
  // If input schema exists, construct an object from args using the schema props order, otherwise pass { args }.
60
60
  let input: any;
61
61
  if (fn.inputSchema) {
@@ -7,9 +7,10 @@ import * as ManagedRuntime from 'effect/ManagedRuntime';
7
7
 
8
8
  import { AiService } from '@dxos/ai';
9
9
  import { type SpaceId } from '@dxos/client/echo';
10
- import { Database } from '@dxos/echo';
11
- import { CredentialsService, type FunctionDefinition, QueueService } from '@dxos/functions';
10
+ import { Database, Feed } from '@dxos/echo';
11
+ import { CredentialsService, QueueService } from '@dxos/functions';
12
12
  import { FunctionInvocationServiceLayerTest } from '@dxos/functions-runtime/testing';
13
+ import { OperationHandlerSet } from '@dxos/operation';
13
14
 
14
15
  import { type FunctionsRuntimeProvider } from '../compute-graph-registry';
15
16
 
@@ -19,15 +20,16 @@ import { type FunctionsRuntimeProvider } from '../compute-graph-registry';
19
20
  */
20
21
  export const createMockedComputeRuntimeProvider = ({
21
22
  functions,
22
- }: { functions?: FunctionDefinition.Any[] } = {}): FunctionsRuntimeProvider => {
23
+ }: { functions?: OperationHandlerSet.OperationHandlerSet } = {}): FunctionsRuntimeProvider => {
23
24
  return {
24
25
  getRuntime: (_spaceId: SpaceId) =>
25
26
  ManagedRuntime.make(
26
27
  FunctionInvocationServiceLayerTest({ functions }).pipe(
27
28
  Layer.provide(AiService.notAvailable),
28
29
  Layer.provide(CredentialsService.configuredLayer([])),
29
- Layer.provide(Database.Service.notAvailable),
30
+ Layer.provide(Database.notAvailable),
30
31
  Layer.provide(QueueService.notAvailable),
32
+ Layer.provide(Feed.notAvailable),
31
33
  ),
32
34
  ),
33
35
  };