@dxos/functions-testing 0.8.4-main.3c1ae3b → 0.8.4-main.3fbcb4aa9b

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,9 +1,13 @@
1
1
  {
2
2
  "name": "@dxos/functions-testing",
3
- "version": "0.8.4-main.3c1ae3b",
3
+ "version": "0.8.4-main.3fbcb4aa9b",
4
4
  "description": "Functions tests",
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": "info@dxos.org",
9
13
  "sideEffects": true,
@@ -21,31 +25,29 @@
21
25
  }
22
26
  },
23
27
  "types": "dist/types/src/index.d.ts",
24
- "typesVersions": {
25
- "*": {
26
- "testing": [
27
- "dist/types/src/testing/index.d.ts"
28
- ]
29
- }
30
- },
31
28
  "files": [
32
29
  "dist",
33
30
  "src"
34
31
  ],
35
32
  "dependencies": {
36
- "@effect/platform": "0.92.1",
37
- "@dxos/async": "0.8.4-main.3c1ae3b",
38
- "@dxos/client": "0.8.4-main.3c1ae3b",
39
- "@dxos/functions": "0.8.4-main.3c1ae3b",
40
- "@dxos/config": "0.8.4-main.3c1ae3b",
41
- "@dxos/echo": "0.8.4-main.3c1ae3b",
42
- "@dxos/functions-runtime": "0.8.4-main.3c1ae3b",
43
- "@dxos/functions-runtime-cloudflare": "0.8.4-main.3c1ae3b",
44
- "@dxos/invariant": "0.8.4-main.3c1ae3b",
45
- "@dxos/log": "0.8.4-main.3c1ae3b",
46
- "@dxos/protocols": "0.8.4-main.3c1ae3b"
33
+ "@effect/platform": "0.94.4",
34
+ "@dxos/assistant-toolkit": "0.8.4-main.3fbcb4aa9b",
35
+ "@dxos/compute": "0.8.4-main.3fbcb4aa9b",
36
+ "@dxos/config": "0.8.4-main.3fbcb4aa9b",
37
+ "@dxos/context": "0.8.4-main.3fbcb4aa9b",
38
+ "@dxos/async": "0.8.4-main.3fbcb4aa9b",
39
+ "@dxos/client": "0.8.4-main.3fbcb4aa9b",
40
+ "@dxos/echo": "0.8.4-main.3fbcb4aa9b",
41
+ "@dxos/functions": "0.8.4-main.3fbcb4aa9b",
42
+ "@dxos/invariant": "0.8.4-main.3fbcb4aa9b",
43
+ "@dxos/functions-runtime": "0.8.4-main.3fbcb4aa9b",
44
+ "@dxos/functions-runtime-cloudflare": "0.8.4-main.3fbcb4aa9b",
45
+ "@dxos/log": "0.8.4-main.3fbcb4aa9b",
46
+ "@dxos/operation": "0.8.4-main.3fbcb4aa9b",
47
+ "@dxos/protocols": "0.8.4-main.3fbcb4aa9b",
48
+ "@dxos/util": "0.8.4-main.3fbcb4aa9b",
49
+ "@dxos/schema": "0.8.4-main.3fbcb4aa9b"
47
50
  },
48
- "devDependencies": {},
49
51
  "publishConfig": {
50
52
  "access": "public"
51
53
  },
@@ -3,7 +3,6 @@
3
3
  //
4
4
 
5
5
  import { join } from 'node:path';
6
-
7
6
  import { describe, it } from 'vitest';
8
7
 
9
8
  import { bundleFunction } from '@dxos/functions-runtime/native';
@@ -4,17 +4,18 @@
4
4
 
5
5
  import { describe, test } from 'vitest';
6
6
 
7
+ import { Trigger } from '@dxos/compute';
7
8
  import { configPreset } from '@dxos/config';
9
+ import { Context } from '@dxos/context';
8
10
  import { Obj, Ref } from '@dxos/echo';
9
- import { Trigger } from '@dxos/functions';
10
11
  import { FunctionRuntimeKind } from '@dxos/protocols';
11
12
 
12
13
  import { deployFunction, observeInvocations, setup, sync } from './testing';
13
14
 
14
15
  const FIB_FUNCTION_PATH = new URL('./functions/fib.ts', import.meta.url).pathname;
15
16
 
16
- // Test suite to explore who CPU time limits influence function execution
17
- describe.runIf(process.env.DX_TEST_TAGS?.includes('functions-e2e'))('CPU limit', () => {
17
+ // Test suite to explore who CPU time limits influence function execution.
18
+ describe('CPU limit', { tags: ['functions-e2e'] }, () => {
18
19
  const config = configPreset({ edge: 'dev' });
19
20
 
20
21
  test('invoke directly', { timeout: 120_000 }, async ({ expect }) => {
@@ -26,6 +27,7 @@ describe.runIf(process.env.DX_TEST_TAGS?.includes('functions-e2e'))('CPU limit',
26
27
  FunctionRuntimeKind.enums.WORKERS_FOR_PLATFORMS,
27
28
  );
28
29
  const result = await functionsServiceClient.invoke(
30
+ Context.default(),
29
31
  func,
30
32
  {
31
33
  iterations: 100,
@@ -49,12 +51,12 @@ describe.runIf(process.env.DX_TEST_TAGS?.includes('functions-e2e'))('CPU limit',
49
51
  Obj.make(Trigger.Trigger, {
50
52
  enabled: true,
51
53
  function: Ref.make(func),
52
- spec: { kind: 'timer', cron: '* */30 * * * *' },
54
+ spec: Trigger.specTimer('* */30 * * * *'),
53
55
  input: { iterations: 100 },
54
56
  }),
55
57
  );
56
58
  await sync(space);
57
- const result = await functionsServiceClient.forceRunCronTrigger(space.id, trigger.id);
59
+ const result = await functionsServiceClient.forceRunCronTrigger(Context.default(), space.id, trigger.id);
58
60
  console.log(result);
59
61
  });
60
62
 
@@ -70,25 +72,27 @@ describe.runIf(process.env.DX_TEST_TAGS?.includes('functions-e2e'))('CPU limit',
70
72
  Obj.make(Trigger.Trigger, {
71
73
  enabled: true,
72
74
  function: Ref.make(func),
73
- spec: { kind: 'timer', cron: '* */30 * * * *' },
75
+ spec: Trigger.specTimer('* */30 * * * *'),
74
76
  input: { iterations: 1_000_000_000 },
75
77
  }),
76
78
  );
77
79
  await sync(space);
78
80
  {
79
- const result = await functionsServiceClient.forceRunCronTrigger(space.id, trigger.id);
81
+ const result = await functionsServiceClient.forceRunCronTrigger(Context.default(), space.id, trigger.id);
80
82
  console.log(result);
81
83
  }
82
84
 
83
85
  {
84
- const result = await functionsServiceClient.forceRunCronTrigger(space.id, trigger.id);
86
+ const result = await functionsServiceClient.forceRunCronTrigger(Context.default(), space.id, trigger.id);
85
87
  console.log(result);
86
88
  }
87
89
 
88
90
  {
89
- trigger.input!.iterations = 100;
91
+ Obj.update(trigger, (trigger) => {
92
+ trigger.input!.iterations = 100;
93
+ });
90
94
  await sync(space);
91
- const result = await functionsServiceClient.forceRunCronTrigger(space.id, trigger.id);
95
+ const result = await functionsServiceClient.forceRunCronTrigger(Context.default(), space.id, trigger.id);
92
96
  console.log(result);
93
97
  }
94
98
  });
@@ -105,7 +109,7 @@ describe.runIf(process.env.DX_TEST_TAGS?.includes('functions-e2e'))('CPU limit',
105
109
  Obj.make(Trigger.Trigger, {
106
110
  enabled: true,
107
111
  function: Ref.make(func),
108
- spec: { kind: 'timer', cron: '* * * * * *' },
112
+ spec: Trigger.specTimer('* * * * * *'),
109
113
  input: { iterations: 1_000_000 },
110
114
  }),
111
115
  );
@@ -125,18 +129,22 @@ describe.runIf(process.env.DX_TEST_TAGS?.includes('functions-e2e'))('CPU limit',
125
129
  Obj.make(Trigger.Trigger, {
126
130
  enabled: true,
127
131
  function: Ref.make(func),
128
- spec: { kind: 'timer', cron: '* * * * * *' },
132
+ spec: Trigger.specTimer('* * * * * *'),
129
133
  input: { iterations: 100 },
130
134
  }),
131
135
  );
132
136
  await sync(space);
133
137
  await observeInvocations(space, 5);
134
138
 
135
- trigger.input!.iterations = 1_000_000_000;
139
+ Obj.update(trigger, (trigger) => {
140
+ trigger.input!.iterations = 1_000_000_000;
141
+ });
136
142
  await sync(space);
137
143
  await observeInvocations(space, 10);
138
144
 
139
- trigger.input!.iterations = 100;
145
+ Obj.update(trigger, (trigger) => {
146
+ trigger.input!.iterations = 100;
147
+ });
140
148
  await sync(space);
141
149
  await observeInvocations(space, 1_000);
142
150
  });
@@ -0,0 +1,110 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+ import { describe, test } from 'vitest';
7
+
8
+ import { AgentPrompt, DatabaseBlueprint, Chat } from '@dxos/assistant-toolkit';
9
+ import { Client } from '@dxos/client';
10
+ import { Blueprint, Operation, Routine, Trigger } from '@dxos/compute';
11
+ import { configPreset } from '@dxos/config';
12
+ import { Context } from '@dxos/context';
13
+ import { Feed, Obj, Ref } from '@dxos/echo';
14
+ import { TestSchema } from '@dxos/echo/testing';
15
+ import { dbg, log } from '@dxos/log';
16
+ import { ErrorCodec } from '@dxos/protocols';
17
+ import { EdgeReplicationSetting } from '@dxos/protocols/proto/dxos/echo/metadata';
18
+ import { Text } from '@dxos/schema';
19
+ import { trim } from '@dxos/util';
20
+
21
+ import { sync } from './testing';
22
+
23
+ /**
24
+ * Cron trigger on EDGE runs {@link AgentPrompt} for a {@link Routine} that uses the Database
25
+ * blueprint Query tool against replicated ECHO documents.
26
+ *
27
+ * Prereq: local EDGE (`configPreset({ edge: 'local' })` → `http://localhost:8787`) with LLM
28
+ * available (API key and/or memo replay under `conversationsCache/`).
29
+ */
30
+ describe('Edge routine', { tags: ['functions-e2e'] }, () => {
31
+ const config = configPreset({ edge: 'local' });
32
+
33
+ test('timer trigger runs routine with database blueprint on edge', { timeout: 420_000 }, async ({ expect }) => {
34
+ await using client = await new Client({
35
+ config,
36
+ types: [
37
+ Operation.PersistentOperation,
38
+ Trigger.Trigger,
39
+ Routine.Routine,
40
+ Blueprint.Blueprint,
41
+ Feed.Feed,
42
+ Text.Text,
43
+ Chat.Chat,
44
+ TestSchema.Organization,
45
+ ],
46
+ }).initialize();
47
+
48
+ await client.halo.createIdentity();
49
+ const space = await client.spaces.create();
50
+ await space.waitUntilReady();
51
+
52
+ await space.internal.setEdgeReplicationPreference(EdgeReplicationSetting.ENABLED);
53
+
54
+ Obj.update(space.properties, (properties) => {
55
+ properties.computeEnvironment = 'edge';
56
+ });
57
+
58
+ space.db.add(Obj.make(TestSchema.Organization, { name: 'Acme Corp' }));
59
+ space.db.add(Obj.make(TestSchema.Organization, { name: 'Globex Industries' }));
60
+ space.db.add(Obj.make(TestSchema.Organization, { name: 'Initech' }));
61
+
62
+ const databaseBlueprint = space.db.add(DatabaseBlueprint.make());
63
+
64
+ const routine = space.db.add(
65
+ Routine.make({
66
+ name: 'edge-e2e-count-orgs-db-blueprint',
67
+ instructions: trim`
68
+ You have access to the Database blueprint tools.
69
+ Use the Query tool exactly once with typename "${TestSchema.Organization.typename}" and no other arguments.
70
+ Then call completeJob with the output object { "count": <number of rows returned by Query> }.
71
+ If you are unable to query -- fail.
72
+ Do not list schemas first.
73
+ `,
74
+ input: Schema.Struct({}),
75
+ output: Schema.Struct({
76
+ count: Schema.Number,
77
+ }),
78
+ blueprints: [Ref.make(databaseBlueprint)],
79
+ context: [],
80
+ }),
81
+ );
82
+ const fn = Operation.serialize(AgentPrompt);
83
+ dbg(Obj.toJSON(fn));
84
+
85
+ const trigger = space.db.add(
86
+ Obj.make(Trigger.Trigger, {
87
+ enabled: true,
88
+ function: Ref.make(fn),
89
+ spec: Trigger.specTimer('* * * * * *'),
90
+ input: {
91
+ prompt: Ref.make(routine),
92
+ input: {},
93
+ model: '@anthropic/claude-haiku-4-5',
94
+ },
95
+ }),
96
+ );
97
+
98
+ await sync(space);
99
+
100
+ log('trigger created and synced');
101
+ log.break();
102
+
103
+ const runResult: any = await client.edge.http.forceRunCronTrigger(Context.default(), space.id, trigger.id);
104
+ if (runResult._kind === 'error') {
105
+ throw ErrorCodec.decode(runResult.error);
106
+ }
107
+ log('trigger ran', { runResult });
108
+ expect(runResult.result.count).toBe(3);
109
+ });
110
+ });
@@ -0,0 +1,61 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+
7
+ import { Operation } from '@dxos/compute';
8
+ import { Database } from '@dxos/echo';
9
+
10
+ export const Fibonacci = Operation.make({
11
+ meta: {
12
+ key: 'org.example.function.fib',
13
+ name: 'Fibonacci',
14
+ description: 'Function that calculates a Fibonacci number',
15
+ },
16
+ input: Schema.Struct({
17
+ iterations: Schema.optional(Schema.Number).annotations({
18
+ description: 'Number of iterations',
19
+ default: 100_000,
20
+ }),
21
+ }),
22
+ output: Schema.Struct({
23
+ result: Schema.String,
24
+ }),
25
+ });
26
+
27
+ export const Reply = Operation.make({
28
+ meta: {
29
+ key: 'org.example.function.reply',
30
+ name: 'Reply',
31
+ description: 'Function that echoes the input',
32
+ },
33
+ input: Schema.Any,
34
+ output: Schema.Any,
35
+ });
36
+
37
+ export const Sleep = Operation.make({
38
+ meta: {
39
+ key: 'org.example.function.sleep',
40
+ name: 'Sleep',
41
+ description: 'Function that sleeps for a given amount of time',
42
+ },
43
+ input: Schema.Struct({
44
+ duration: Schema.optional(Schema.Number).annotations({
45
+ description: 'Milliseconds to sleep',
46
+ default: 100_000,
47
+ }),
48
+ }),
49
+ output: Schema.Void,
50
+ });
51
+
52
+ export const QueryDb = Operation.make({
53
+ meta: {
54
+ key: 'org.example.function.query',
55
+ name: 'Query',
56
+ description: 'Queries the database',
57
+ },
58
+ input: Schema.Any,
59
+ output: Schema.Any,
60
+ services: [Database.Service],
61
+ });
@@ -3,30 +3,21 @@
3
3
  //
4
4
 
5
5
  import * as Effect from 'effect/Effect';
6
- import * as Schema from 'effect/Schema';
7
6
 
8
- import { defineFunction } from '@dxos/functions';
7
+ import { Operation } from '@dxos/compute';
9
8
 
10
- export default defineFunction({
11
- key: 'example.org/function/fib',
12
- name: 'Fibonacci',
13
- description: 'Function that calculates a Fibonacci number',
14
- inputSchema: Schema.Struct({
15
- iterations: Schema.optional(Schema.Number).annotations({
16
- description: 'Number of iterations',
17
- default: 100_000,
9
+ import { Fibonacci } from './definitions';
10
+
11
+ export default Fibonacci.pipe(
12
+ Operation.withHandler(
13
+ Effect.fn(function* ({ iterations = 100_000 }) {
14
+ let a = 0n;
15
+ let b = 1n;
16
+ for (let i = 0; i < iterations; i++) {
17
+ a += b;
18
+ b = a - b;
19
+ }
20
+ return { result: a.toString() };
18
21
  }),
19
- }),
20
- outputSchema: Schema.Struct({
21
- result: Schema.String,
22
- }),
23
- handler: Effect.fn(function* ({ data: { iterations = 100_000 } }) {
24
- let a = 0n;
25
- let b = 1n;
26
- for (let i = 0; i < iterations; i++) {
27
- a += b;
28
- b = a - b;
29
- }
30
- return { result: a.toString() };
31
- }),
32
- });
22
+ ),
23
+ );
@@ -10,35 +10,39 @@ import * as Effect from 'effect/Effect';
10
10
  import * as Schedule from 'effect/Schedule';
11
11
  import * as Schema from 'effect/Schema';
12
12
 
13
- import { defineFunction } from '@dxos/functions';
13
+ import { Operation } from '@dxos/compute';
14
14
 
15
- export default defineFunction({
16
- key: 'dxos.org/script/forex-effect',
17
- name: 'Forex Effect',
18
- description: 'Returns the exchange rate between two currencies.',
19
-
20
- inputSchema: Schema.Struct({
15
+ const ForexEffect = Operation.make({
16
+ meta: {
17
+ key: 'org.dxos.script.forex-effect',
18
+ name: 'Forex Effect',
19
+ description: 'Returns the exchange rate between two currencies.',
20
+ },
21
+ input: Schema.Struct({
21
22
  from: Schema.String.annotations({ description: 'The source currency' }),
22
23
  to: Schema.String.annotations({ description: 'The target currency' }),
23
24
  }),
25
+ output: Schema.String.annotations({ description: 'The exchange rate between the two currencies' }),
26
+ });
24
27
 
25
- outputSchema: Schema.String.annotations({ description: 'The exchange rate between the two currencies' }),
26
-
27
- handler: Effect.fnUntraced(function* ({ data: { from, to } }: any) {
28
- const res = yield* HttpClientRequest.get(`https://free.ratesdb.com/v1/rates?from=${from}&to=${to}`).pipe(
29
- HttpClient.execute,
30
- Effect.flatMap(
31
- HttpClientResponse.schemaBodyJson(
32
- Schema.Struct({
33
- data: Schema.Struct({ rates: Schema.Record({ key: Schema.String, value: Schema.Number }) }),
34
- }),
28
+ export default ForexEffect.pipe(
29
+ Operation.withHandler(
30
+ Effect.fnUntraced(function* ({ from, to }) {
31
+ const res = yield* HttpClientRequest.get(`https://free.ratesdb.com/v1/rates?from=${from}&to=${to}`).pipe(
32
+ HttpClient.execute,
33
+ Effect.flatMap(
34
+ HttpClientResponse.schemaBodyJson(
35
+ Schema.Struct({
36
+ data: Schema.Struct({ rates: Schema.Record({ key: Schema.String, value: Schema.Number }) }),
37
+ }),
38
+ ),
35
39
  ),
36
- ),
37
- Effect.timeout('1 second'),
38
- Effect.retry(Schedule.exponential(1_000).pipe(Schedule.compose(Schedule.recurs(3)))),
39
- Effect.scoped,
40
- );
40
+ Effect.timeout('1 second'),
41
+ Effect.retry(Schedule.exponential(1_000).pipe(Schedule.compose(Schedule.recurs(3)))),
42
+ Effect.scoped,
43
+ );
41
44
 
42
- return res.data.rates[to].toString();
43
- }, Effect.provide(FetchHttpClient.layer)),
44
- });
45
+ return res.data.rates[to].toString();
46
+ }, Effect.provide(FetchHttpClient.layer)),
47
+ ),
48
+ );
@@ -3,19 +3,17 @@
3
3
  //
4
4
 
5
5
  import * as Effect from 'effect/Effect';
6
- import * as Schema from 'effect/Schema';
7
6
 
8
- import { Database, Filter, Query } from '@dxos/echo';
9
- import { defineFunction } from '@dxos/functions';
7
+ import { Operation } from '@dxos/compute';
8
+ import { Database, Filter, Query as EchoQuery } from '@dxos/echo';
10
9
 
11
- export default defineFunction({
12
- key: 'example.org/function/query',
13
- name: 'Query',
14
- description: 'Queries the database',
15
- inputSchema: Schema.Any,
16
- outputSchema: Schema.Any,
17
- handler: Effect.fn(function* ({ data }) {
18
- const results = yield* Database.Service.runQuery(Query.select(Filter.everything()));
19
- return { count: results.length };
20
- }),
21
- });
10
+ import { QueryDb } from './definitions';
11
+
12
+ export default QueryDb.pipe(
13
+ Operation.withHandler(
14
+ Effect.fn(function* (data) {
15
+ const results = yield* Database.runQuery(EchoQuery.select(Filter.everything()));
16
+ return { count: results.length };
17
+ }),
18
+ ),
19
+ );
@@ -4,18 +4,16 @@
4
4
 
5
5
  import * as Console from 'effect/Console';
6
6
  import * as Effect from 'effect/Effect';
7
- import * as Schema from 'effect/Schema';
8
7
 
9
- import { defineFunction } from '@dxos/functions';
8
+ import { Operation } from '@dxos/compute';
10
9
 
11
- export default defineFunction({
12
- key: 'example.org/function/reply',
13
- name: 'Reply',
14
- description: 'Function that echoes the input',
15
- inputSchema: Schema.Any,
16
- outputSchema: Schema.Any,
17
- handler: Effect.fn(function* ({ data }) {
18
- yield* Console.log('reply', { data });
19
- return data;
20
- }),
21
- });
10
+ import { Reply } from './definitions';
11
+
12
+ export default Reply.pipe(
13
+ Operation.withHandler(
14
+ Effect.fn(function* (data) {
15
+ yield* Console.log('reply', { data });
16
+ return data;
17
+ }),
18
+ ),
19
+ );
@@ -3,22 +3,15 @@
3
3
  //
4
4
 
5
5
  import * as Effect from 'effect/Effect';
6
- import * as Schema from 'effect/Schema';
7
6
 
8
- import { defineFunction } from '@dxos/functions';
7
+ import { Operation } from '@dxos/compute';
9
8
 
10
- export default defineFunction({
11
- key: 'example.org/function/sleep',
12
- name: 'Sleep',
13
- description: 'Function that sleeps for a given amount of time',
14
- inputSchema: Schema.Struct({
15
- duration: Schema.optional(Schema.Number).annotations({
16
- description: 'Milliseconds to sleep',
17
- default: 100_000,
9
+ import { Sleep } from './definitions';
10
+
11
+ export default Sleep.pipe(
12
+ Operation.withHandler(
13
+ Effect.fn(function* ({ duration = 100_000 }) {
14
+ yield* Effect.sleep(duration);
18
15
  }),
19
- }),
20
- outputSchema: Schema.Void,
21
- handler: Effect.fn(function* ({ data: { duration = 100_000 } }) {
22
- yield* Effect.sleep(duration);
23
- }),
24
- });
16
+ ),
17
+ );
@@ -7,14 +7,14 @@ import fs from 'node:fs';
7
7
  import { sleep } from '@dxos/async';
8
8
  import { Client, type Config } from '@dxos/client';
9
9
  import { type Space } from '@dxos/client/echo';
10
- import { Filter, Obj, Query } from '@dxos/echo';
11
- import { Function } from '@dxos/functions';
12
- import { Trigger } from '@dxos/functions';
10
+ import { Operation, Trigger } from '@dxos/compute';
11
+ import { Context } from '@dxos/context';
12
+ import { Feed, Obj } from '@dxos/echo';
13
13
  import { InvocationTraceEndEvent, InvocationTraceStartEvent } from '@dxos/functions-runtime';
14
14
  import { FunctionsServiceClient } from '@dxos/functions-runtime/edge';
15
15
  import { bundleFunction } from '@dxos/functions-runtime/native';
16
16
  import type { BundleResult } from '@dxos/functions-runtime/native';
17
- import { type FunctionRuntimeKind } from '@dxos/protocols';
17
+ import { ErrorCodec, type FunctionRuntimeKind } from '@dxos/protocols';
18
18
  import { EdgeReplicationSetting } from '@dxos/protocols/proto/dxos/echo/metadata';
19
19
 
20
20
  export const writeBundle = (path: string, bundle: BundleResult) => {
@@ -27,7 +27,7 @@ export const writeBundle = (path: string, bundle: BundleResult) => {
27
27
  export const setup = async (config: Config) => {
28
28
  const client = await new Client({
29
29
  config,
30
- types: [Function.Function, Trigger.Trigger],
30
+ types: [Operation.PersistentOperation, Trigger.Trigger],
31
31
  }).initialize();
32
32
  await client.halo.createIdentity();
33
33
 
@@ -41,7 +41,7 @@ export const setup = async (config: Config) => {
41
41
  };
42
42
 
43
43
  export const sync = async (space: Space) => {
44
- await space.db.flush({ indexes: true });
44
+ await space.db.flush();
45
45
  await space.internal.syncToEdge({
46
46
  onProgress: (state) =>
47
47
  console.log(state ? `${state.unsyncedDocumentCount} documents syncing...` : 'connecting to edge...'),
@@ -53,12 +53,12 @@ export const deployFunction = async (
53
53
  functionsServiceClient: FunctionsServiceClient,
54
54
  entryPoint: string,
55
55
  runtime: FunctionRuntimeKind,
56
- ) => {
56
+ ): Promise<Operation.PersistentOperation> => {
57
57
  const artifact = await bundleFunction({
58
58
  entryPoint,
59
59
  verbose: true,
60
60
  });
61
- const func = await functionsServiceClient.deploy({
61
+ const func = await functionsServiceClient.deploy(Context.default(), {
62
62
  version: '0.0.1',
63
63
  ownerPublicKey: space.key,
64
64
  entryPoint: artifact.entryPoint,
@@ -83,8 +83,9 @@ export const observeInvocations = async (space: Space, maxCount: number | null)
83
83
  let count = 0;
84
84
  while (true) {
85
85
  try {
86
- const invocations =
87
- (await space.properties.invocationTraceQueue?.target!.query(Query.select(Filter.everything())).run()) ?? [];
86
+ const traceFeed = space.properties.invocationTraceFeed?.target;
87
+ const traceQueueDxn = traceFeed ? Feed.getQueueDxn(traceFeed) : undefined;
88
+ const invocations = traceQueueDxn ? ((await space.queues.get(traceQueueDxn).queryObjects()) ?? []) : [];
88
89
 
89
90
  for (const invocation of invocations) {
90
91
  if (Obj.instanceOf(InvocationTraceStartEvent, invocation)) {
@@ -95,7 +96,9 @@ export const observeInvocations = async (space: Space, maxCount: number | null)
95
96
  count: count++,
96
97
  begin: invocation,
97
98
  });
98
- console.log(`${count.toString().padStart(3, ' ')}: BEGIN ${JSON.stringify(invocation.input)}`);
99
+ console.log(
100
+ `${count.toString().padStart(3, ' ')}: BEGIN ${invocation.runtime ?? '(unknown runtime)'} ${JSON.stringify(invocation.input)}`,
101
+ );
99
102
  } else if (Obj.instanceOf(InvocationTraceEndEvent, invocation)) {
100
103
  const data = invocationData.get(invocation.invocationId);
101
104
  if (!data || !!data.end) {
@@ -107,8 +110,8 @@ export const observeInvocations = async (space: Space, maxCount: number | null)
107
110
  console.log(
108
111
  `${data.count.toString().padStart(3, ' ')}: END outcome=${outcome} duration=${data.end.timestamp - data.begin.timestamp}`,
109
112
  );
110
- if (outcome === 'failure') {
111
- console.log(data.end.error?.stack);
113
+ if (outcome === 'failure' && data.end.error) {
114
+ console.error(ErrorCodec.decode(data.end.error));
112
115
  }
113
116
  }
114
117
  }