@dxos/functions 0.5.3-main.6e12b97 → 0.5.3-main.6f2dfea

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 (76) hide show
  1. package/dist/lib/browser/index.mjs +422 -663
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +419 -648
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/types/src/handler.d.ts +12 -32
  8. package/dist/types/src/handler.d.ts.map +1 -1
  9. package/dist/types/src/index.d.ts +0 -2
  10. package/dist/types/src/index.d.ts.map +1 -1
  11. package/dist/types/src/runtime/dev-server.d.ts +10 -7
  12. package/dist/types/src/runtime/dev-server.d.ts.map +1 -1
  13. package/dist/types/src/runtime/scheduler.d.ts +59 -10
  14. package/dist/types/src/runtime/scheduler.d.ts.map +1 -1
  15. package/dist/types/src/testing/test/handler.d.ts +0 -1
  16. package/dist/types/src/testing/test/handler.d.ts.map +1 -1
  17. package/dist/types/src/types.d.ts +112 -118
  18. package/dist/types/src/types.d.ts.map +1 -1
  19. package/package.json +13 -16
  20. package/schema/functions.json +103 -122
  21. package/src/handler.ts +27 -50
  22. package/src/index.ts +0 -2
  23. package/src/runtime/dev-server.test.ts +35 -15
  24. package/src/runtime/dev-server.ts +22 -40
  25. package/src/runtime/scheduler.test.ts +75 -54
  26. package/src/runtime/scheduler.ts +300 -67
  27. package/src/testing/test/handler.ts +2 -8
  28. package/src/types.ts +40 -56
  29. package/dist/types/src/registry/function-registry.d.ts +0 -24
  30. package/dist/types/src/registry/function-registry.d.ts.map +0 -1
  31. package/dist/types/src/registry/function-registry.test.d.ts +0 -2
  32. package/dist/types/src/registry/function-registry.test.d.ts.map +0 -1
  33. package/dist/types/src/registry/index.d.ts +0 -2
  34. package/dist/types/src/registry/index.d.ts.map +0 -1
  35. package/dist/types/src/testing/functions-integration.test.d.ts +0 -2
  36. package/dist/types/src/testing/functions-integration.test.d.ts.map +0 -1
  37. package/dist/types/src/testing/index.d.ts +0 -4
  38. package/dist/types/src/testing/index.d.ts.map +0 -1
  39. package/dist/types/src/testing/setup.d.ts +0 -5
  40. package/dist/types/src/testing/setup.d.ts.map +0 -1
  41. package/dist/types/src/testing/types.d.ts +0 -9
  42. package/dist/types/src/testing/types.d.ts.map +0 -1
  43. package/dist/types/src/testing/util.d.ts +0 -3
  44. package/dist/types/src/testing/util.d.ts.map +0 -1
  45. package/dist/types/src/trigger/index.d.ts +0 -2
  46. package/dist/types/src/trigger/index.d.ts.map +0 -1
  47. package/dist/types/src/trigger/trigger-registry.d.ts +0 -40
  48. package/dist/types/src/trigger/trigger-registry.d.ts.map +0 -1
  49. package/dist/types/src/trigger/trigger-registry.test.d.ts +0 -2
  50. package/dist/types/src/trigger/trigger-registry.test.d.ts.map +0 -1
  51. package/dist/types/src/trigger/type/index.d.ts +0 -5
  52. package/dist/types/src/trigger/type/index.d.ts.map +0 -1
  53. package/dist/types/src/trigger/type/subscription-trigger.d.ts +0 -4
  54. package/dist/types/src/trigger/type/subscription-trigger.d.ts.map +0 -1
  55. package/dist/types/src/trigger/type/timer-trigger.d.ts +0 -4
  56. package/dist/types/src/trigger/type/timer-trigger.d.ts.map +0 -1
  57. package/dist/types/src/trigger/type/webhook-trigger.d.ts +0 -4
  58. package/dist/types/src/trigger/type/webhook-trigger.d.ts.map +0 -1
  59. package/dist/types/src/trigger/type/websocket-trigger.d.ts +0 -13
  60. package/dist/types/src/trigger/type/websocket-trigger.d.ts.map +0 -1
  61. package/src/registry/function-registry.test.ts +0 -105
  62. package/src/registry/function-registry.ts +0 -84
  63. package/src/registry/index.ts +0 -5
  64. package/src/testing/functions-integration.test.ts +0 -99
  65. package/src/testing/index.ts +0 -7
  66. package/src/testing/setup.ts +0 -45
  67. package/src/testing/types.ts +0 -9
  68. package/src/testing/util.ts +0 -16
  69. package/src/trigger/index.ts +0 -5
  70. package/src/trigger/trigger-registry.test.ts +0 -229
  71. package/src/trigger/trigger-registry.ts +0 -176
  72. package/src/trigger/type/index.ts +0 -8
  73. package/src/trigger/type/subscription-trigger.ts +0 -73
  74. package/src/trigger/type/timer-trigger.ts +0 -44
  75. package/src/trigger/type/webhook-trigger.ts +0 -47
  76. package/src/trigger/type/websocket-trigger.ts +0 -91
package/src/handler.ts CHANGED
@@ -8,61 +8,38 @@ import { type EchoReactiveObject } from '@dxos/echo-schema';
8
8
  import { log } from '@dxos/log';
9
9
  import { nonNullable } from '@dxos/util';
10
10
 
11
- // TODO(burdon): Model after http request. Ref Lambda/OpenFaaS.
12
- // https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html
11
+ // Lambda-like function definitions.
13
12
  // https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml/#functions
14
13
  // https://www.npmjs.com/package/aws-lambda
14
+ // https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html
15
15
 
16
- /**
17
- * Function handler.
18
- */
19
- export type FunctionHandler<TData = {}, TMeta = {}> = (params: {
20
- context: FunctionContext;
21
- event: FunctionEvent<TData, TMeta>;
22
- response: FunctionResponse;
23
- }) => Promise<FunctionResponse | void>;
16
+ // TODO(burdon): No response?
17
+ export interface Response {
18
+ status(code: number): Response;
19
+ }
24
20
 
25
- /**
26
- * Function context.
27
- */
28
21
  export interface FunctionContext {
29
22
  // TODO(burdon): Limit access to individual space.
30
23
  client: Client;
31
24
  // TODO(burdon): Replace with storage service abstraction.
32
25
  dataDir?: string;
26
+ // Data passed to function invocation.
27
+ data?: any;
33
28
  }
34
29
 
35
- /**
36
- * Event payload.
37
- */
38
- export type FunctionEvent<TData = {}, TMeta = {}> = {
39
- data: FunctionEventMeta<TMeta> & TData;
40
- };
41
-
42
- /**
43
- * Metadata from trigger.
44
- */
45
- export type FunctionEventMeta<TMeta = {}> = {
46
- meta: TMeta;
47
- };
48
-
49
- /**
50
- * Function response.
51
- */
52
- export interface FunctionResponse {
53
- status(code: number): FunctionResponse;
54
- }
55
-
56
- //
57
- // Subscription utils.
58
- //
30
+ // TODO(burdon): Model after http request. Ref Lambda/OpenFaaS.
31
+ export type FunctionHandler<T extends {}> = (params: {
32
+ event: T;
33
+ context: FunctionContext;
34
+ response: Response;
35
+ }) => Promise<Response | void>;
59
36
 
60
- export type RawSubscriptionData = {
37
+ export type RawSubscriptionEvent = {
61
38
  spaceKey?: string;
62
39
  objects?: string[];
63
40
  };
64
41
 
65
- export type SubscriptionData = {
42
+ export type SubscriptionEvent = {
66
43
  space?: Space;
67
44
  objects?: EchoReactiveObject<any>[];
68
45
  };
@@ -77,22 +54,22 @@ export type SubscriptionData = {
77
54
  *
78
55
  * NOTE: Get space key from devtools or `dx space list --json`
79
56
  */
80
- export const subscriptionHandler = <TMeta>(
81
- handler: FunctionHandler<SubscriptionData, TMeta>,
82
- ): FunctionHandler<RawSubscriptionData, TMeta> => {
83
- return ({ event: { data }, context, ...rest }) => {
57
+ export const subscriptionHandler = (
58
+ handler: FunctionHandler<SubscriptionEvent>,
59
+ ): FunctionHandler<RawSubscriptionEvent> => {
60
+ return ({ event, context, ...rest }) => {
84
61
  const { client } = context;
85
- const space = data.spaceKey ? client.spaces.get(PublicKey.from(data.spaceKey)) : undefined;
86
- const objects = space
87
- ? data.objects?.map<EchoReactiveObject<any> | undefined>((id) => space!.db.getObjectById(id)).filter(nonNullable)
88
- : [];
62
+ const space = event.spaceKey ? client.spaces.get(PublicKey.from(event.spaceKey)) : undefined;
63
+ const objects =
64
+ space &&
65
+ event.objects?.map<EchoReactiveObject<any> | undefined>((id) => space!.db.getObjectById(id)).filter(nonNullable);
89
66
 
90
- if (!!data.spaceKey && !space) {
91
- log.warn('invalid space', { data });
67
+ if (!!event.spaceKey && !space) {
68
+ log.warn('invalid space', { event });
92
69
  } else {
93
70
  log.info('handler', { space: space?.key.truncate(), objects: objects?.length });
94
71
  }
95
72
 
96
- return handler({ event: { data: { ...data, space, objects } }, context, ...rest });
73
+ return handler({ event: { space, objects }, context, ...rest });
97
74
  };
98
75
  };
package/src/index.ts CHANGED
@@ -3,7 +3,5 @@
3
3
  //
4
4
 
5
5
  export * from './handler';
6
- export * from './registry';
7
6
  export * from './runtime';
8
- export * from './trigger';
9
7
  export * from './types';
@@ -5,14 +5,12 @@
5
5
  import { expect } from 'chai';
6
6
  import path from 'path';
7
7
 
8
- import { waitForCondition } from '@dxos/async';
9
- import { type Client } from '@dxos/client';
8
+ import { FunctionsPlugin } from '@dxos/agent';
9
+ import { Client, Config } from '@dxos/client';
10
10
  import { TestBuilder } from '@dxos/client/testing';
11
- import { describe, test } from '@dxos/test';
11
+ import { describe, openAndClose, test } from '@dxos/test';
12
12
 
13
13
  import { DevServer } from './dev-server';
14
- import { FunctionRegistry } from '../registry';
15
- import { createFunctionRuntime } from '../testing';
16
14
  import { type FunctionManifest } from '../types';
17
15
 
18
16
  describe('dev server', () => {
@@ -20,10 +18,35 @@ describe('dev server', () => {
20
18
  let testBuilder: TestBuilder;
21
19
  before(async () => {
22
20
  testBuilder = new TestBuilder();
23
- client = await createFunctionRuntime(testBuilder);
21
+ const config = new Config({
22
+ runtime: {
23
+ agent: {
24
+ plugins: [
25
+ {
26
+ id: 'dxos.org/agent/plugin/functions',
27
+ config: {
28
+ port: 8080,
29
+ },
30
+ },
31
+ ],
32
+ },
33
+ },
34
+ });
35
+
36
+ const services = testBuilder.createLocalClientServices();
37
+ client = new Client({ config, services });
38
+
39
+ await client.initialize();
40
+ await client.halo.createIdentity();
41
+ testBuilder.ctx.onDispose(() => client.destroy());
42
+
43
+ // TODO(burdon): Better way to configure plugin? (Rationalize chess.test).
44
+ const functionsPlugin = new FunctionsPlugin();
45
+ await functionsPlugin.initialize({ client, clientServices: services });
46
+ await openAndClose(functionsPlugin);
47
+
24
48
  expect(client.services.services.FunctionRegistryService).to.exist;
25
49
  });
26
-
27
50
  after(async () => {
28
51
  await testBuilder.destroy();
29
52
  });
@@ -32,19 +55,18 @@ describe('dev server', () => {
32
55
  const manifest: FunctionManifest = {
33
56
  functions: [
34
57
  {
35
- uri: 'example.com/function/test',
36
- route: 'test',
58
+ id: 'example.com/function/test',
59
+ path: 'test',
37
60
  handler: 'test',
38
61
  },
39
62
  ],
40
63
  };
41
64
 
42
- const registry = new FunctionRegistry(client);
43
- const server = new DevServer(client, registry, {
65
+ const server = new DevServer(client, {
66
+ manifest,
44
67
  baseDir: path.join(__dirname, '../testing'),
45
68
  });
46
- const space = await client.spaces.create();
47
- await registry.register(space, manifest);
69
+ await server.initialize();
48
70
  await server.start();
49
71
 
50
72
  // TODO(burdon): Doesn't shut down cleanly.
@@ -52,8 +74,6 @@ describe('dev server', () => {
52
74
  testBuilder.ctx.onDispose(() => server.stop());
53
75
  expect(server).to.exist;
54
76
 
55
- await waitForCondition({ condition: () => server.functions.length > 0 });
56
-
57
77
  await server.invoke('test', {});
58
78
  expect(server.stats.seq).to.eq(1);
59
79
  });
@@ -9,15 +9,14 @@ import { join } from 'node:path';
9
9
 
10
10
  import { Event, Trigger } from '@dxos/async';
11
11
  import { type Client } from '@dxos/client';
12
- import { Context } from '@dxos/context';
13
12
  import { invariant } from '@dxos/invariant';
14
13
  import { log } from '@dxos/log';
15
14
 
16
- import { type FunctionContext, type FunctionEvent, type FunctionHandler, type FunctionResponse } from '../handler';
17
- import { type FunctionRegistry } from '../registry';
18
- import { type FunctionDef } from '../types';
15
+ import { type FunctionContext, type FunctionHandler, type Response } from '../handler';
16
+ import { type FunctionDef, type FunctionManifest } from '../types';
19
17
 
20
18
  export type DevServerOptions = {
19
+ manifest: FunctionManifest;
21
20
  baseDir: string;
22
21
  port?: number;
23
22
  reload?: boolean;
@@ -28,8 +27,6 @@ export type DevServerOptions = {
28
27
  * Functions dev server provides a local HTTP server for testing functions.
29
28
  */
30
29
  export class DevServer {
31
- private _ctx = createContext();
32
-
33
30
  // Function handlers indexed by name (URL path).
34
31
  private readonly _handlers: Record<string, { def: FunctionDef; handler: FunctionHandler<any> }> = {};
35
32
 
@@ -44,15 +41,8 @@ export class DevServer {
44
41
  // prettier-ignore
45
42
  constructor(
46
43
  private readonly _client: Client,
47
- private readonly _functionsRegistry: FunctionRegistry,
48
44
  private readonly _options: DevServerOptions,
49
- ) {
50
- this._functionsRegistry.onFunctionsRegistered.on(async ({ newFunctions }) => {
51
- newFunctions.forEach((def) => this._load(def));
52
- await this._safeUpdateRegistration();
53
- log('new functions loaded', { newFunctions });
54
- });
55
- }
45
+ ) {}
56
46
 
57
47
  get stats() {
58
48
  return {
@@ -73,10 +63,19 @@ export class DevServer {
73
63
  return Object.values(this._handlers);
74
64
  }
75
65
 
66
+ async initialize() {
67
+ for (const def of this._options.manifest.functions) {
68
+ try {
69
+ await this._load(def);
70
+ } catch (err) {
71
+ log.error('parsing function (check manifest)', err);
72
+ }
73
+ }
74
+ }
75
+
76
76
  async start() {
77
77
  invariant(!this._server);
78
78
  log.info('starting...');
79
- this._ctx = createContext();
80
79
 
81
80
  // TODO(burdon): Move to hono.
82
81
  const app = express();
@@ -108,14 +107,12 @@ export class DevServer {
108
107
  // Register functions.
109
108
  const { registrationId, endpoint } = await this._client.services.services.FunctionRegistryService!.register({
110
109
  endpoint: this.endpoint,
110
+ functions: this.functions.map(({ def: { id, path } }) => ({ id, path })),
111
111
  });
112
112
 
113
113
  log.info('registered', { endpoint });
114
114
  this._proxy = endpoint;
115
115
  this._functionServiceRegistration = registrationId;
116
-
117
- // Open after registration, so that it can be updated with the list of function definitions.
118
- await this._functionsRegistry.open(this._ctx);
119
116
  } catch (err: any) {
120
117
  await this.stop();
121
118
  throw new Error('FunctionRegistryService not available (check plugin is configured).');
@@ -159,9 +156,9 @@ export class DevServer {
159
156
  * Load function.
160
157
  */
161
158
  private async _load(def: FunctionDef, force = false) {
162
- const { uri, route, handler } = def;
159
+ const { id, path, handler } = def;
163
160
  const filePath = join(this._options.baseDir, handler);
164
- log.info('loading', { uri, force });
161
+ log.info('loading', { id, force });
165
162
 
166
163
  // Remove from cache.
167
164
  if (force) {
@@ -172,26 +169,13 @@ export class DevServer {
172
169
  });
173
170
  }
174
171
 
175
- // TODO(burdon): Import types.
176
172
  // eslint-disable-next-line @typescript-eslint/no-var-requires
177
173
  const module = require(filePath);
178
174
  if (typeof module.default !== 'function') {
179
- throw new Error(`Handler must export default function: ${uri}`);
175
+ throw new Error(`Handler must export default function: ${id}`);
180
176
  }
181
177
 
182
- this._handlers[route] = { def, handler: module.default };
183
- }
184
-
185
- private async _safeUpdateRegistration(): Promise<void> {
186
- invariant(this._functionServiceRegistration);
187
- try {
188
- await this._client.services.services.FunctionRegistryService!.updateRegistration({
189
- registrationId: this._functionServiceRegistration,
190
- functions: this.functions.map(({ def: { id, route } }) => ({ id, route })),
191
- });
192
- } catch (e) {
193
- log.catch(e);
194
- }
178
+ this._handlers[path] = { def, handler: module.default };
195
179
  }
196
180
 
197
181
  /**
@@ -202,14 +186,14 @@ export class DevServer {
202
186
  const now = Date.now();
203
187
 
204
188
  log.info('req', { seq, path });
205
- const statusCode = await this._invoke(path, { data });
189
+ const statusCode = await this._invoke(path, data);
206
190
 
207
191
  log.info('res', { seq, path, statusCode, duration: Date.now() - now });
208
192
  this.update.emit(statusCode);
209
193
  return statusCode;
210
194
  }
211
195
 
212
- private async _invoke(path: string, event: FunctionEvent) {
196
+ private async _invoke(path: string, event: any) {
213
197
  const { handler } = this._handlers[path] ?? {};
214
198
  invariant(handler, `invalid path: ${path}`);
215
199
 
@@ -219,7 +203,7 @@ export class DevServer {
219
203
  };
220
204
 
221
205
  let statusCode = 200;
222
- const response: FunctionResponse = {
206
+ const response: Response = {
223
207
  status: (code: number) => {
224
208
  statusCode = code;
225
209
  return response;
@@ -230,5 +214,3 @@ export class DevServer {
230
214
  return statusCode;
231
215
  }
232
216
  }
233
-
234
- const createContext = () => new Context({ name: 'DevServer' });
@@ -6,43 +6,40 @@ import { expect } from 'chai';
6
6
  import WebSocket from 'ws';
7
7
 
8
8
  import { Trigger } from '@dxos/async';
9
- import { type Client } from '@dxos/client';
9
+ import { Client } from '@dxos/client';
10
10
  import { TestBuilder } from '@dxos/client/testing';
11
- import { create } from '@dxos/echo-schema';
11
+ import { create, S, TypedObject } from '@dxos/echo-schema';
12
12
  import { describe, test } from '@dxos/test';
13
13
 
14
- import { Scheduler, type SchedulerOptions } from './scheduler';
15
- import { FunctionRegistry } from '../registry';
16
- import { createInitializedClients, TestType, triggerWebhook } from '../testing';
17
- import { TriggerRegistry } from '../trigger';
18
- import { type FunctionManifest } from '../types';
14
+ import { Scheduler } from './scheduler';
15
+ import { type FunctionManifest, type WebhookTrigger } from '../types';
19
16
 
20
17
  // TODO(burdon): Test we can add and remove triggers.
21
18
  describe('scheduler', () => {
22
- let testBuilder: TestBuilder;
23
19
  let client: Client;
24
20
  before(async () => {
25
- testBuilder = new TestBuilder();
26
- client = (await createInitializedClients(testBuilder, 1))[0];
21
+ const testBuilder = new TestBuilder();
22
+ client = new Client({ services: testBuilder.createLocalClientServices() });
23
+ await client.initialize();
24
+ await client.halo.createIdentity();
27
25
  });
28
26
  after(async () => {
29
- await testBuilder.destroy();
27
+ await client.destroy();
30
28
  });
31
29
 
32
30
  test('timer', async () => {
33
31
  const manifest: FunctionManifest = {
34
32
  functions: [
35
33
  {
36
- uri: 'example.com/function/test',
37
- route: '/test',
34
+ id: 'example.com/function/test',
35
+ path: '/test',
38
36
  handler: 'test',
39
37
  },
40
38
  ],
41
39
  triggers: [
42
40
  {
43
41
  function: 'example.com/function/test',
44
- spec: {
45
- type: 'timer',
42
+ timer: {
46
43
  cron: '0/1 * * * * *', // Every 1s.
47
44
  },
48
45
  },
@@ -51,13 +48,18 @@ describe('scheduler', () => {
51
48
 
52
49
  let count = 0;
53
50
  const done = new Trigger();
54
- const scheduler = createScheduler(async () => {
55
- if (++count === 3) {
56
- done.wake();
57
- }
51
+ const scheduler = new Scheduler(client, manifest, {
52
+ callback: async () => {
53
+ if (++count === 3) {
54
+ done.wake();
55
+ }
56
+ },
58
57
  });
59
- await scheduler.register(client.spaces.default, manifest);
58
+
60
59
  await scheduler.start();
60
+ after(async () => {
61
+ await scheduler.stop();
62
+ });
61
63
 
62
64
  await done.wait({ timeout: 5_000 });
63
65
  expect(count).to.equal(3);
@@ -67,16 +69,15 @@ describe('scheduler', () => {
67
69
  const manifest: FunctionManifest = {
68
70
  functions: [
69
71
  {
70
- uri: 'example.com/function/test',
71
- route: '/test',
72
+ id: 'example.com/function/test',
73
+ path: '/test',
72
74
  handler: 'test',
73
75
  },
74
76
  ],
75
77
  triggers: [
76
78
  {
77
79
  function: 'example.com/function/test',
78
- spec: {
79
- type: 'webhook',
80
+ webhook: {
80
81
  method: 'GET',
81
82
  },
82
83
  },
@@ -84,14 +85,23 @@ describe('scheduler', () => {
84
85
  };
85
86
 
86
87
  const done = new Trigger();
87
- const scheduler = createScheduler(async () => {
88
- done.wake();
88
+ const scheduler = new Scheduler(client, manifest, {
89
+ callback: async () => {
90
+ done.wake();
91
+ },
89
92
  });
90
- const space = await client.spaces.create();
91
- await scheduler.register(space, manifest);
93
+
92
94
  await scheduler.start();
95
+ after(async () => {
96
+ await scheduler.stop();
97
+ });
93
98
 
94
- setTimeout(async () => triggerWebhook(space, manifest.functions![0].uri));
99
+ setTimeout(() => {
100
+ const mount: WebhookTrigger = scheduler.mounts.find(
101
+ (mount) => mount.function === 'example.com/function/test',
102
+ )!.webhook!;
103
+ void fetch(`http://localhost:${mount.port}`);
104
+ });
95
105
 
96
106
  await done.wait();
97
107
  });
@@ -100,16 +110,15 @@ describe('scheduler', () => {
100
110
  const manifest: FunctionManifest = {
101
111
  functions: [
102
112
  {
103
- uri: 'example.com/function/test',
104
- route: '/test',
113
+ id: 'example.com/function/test',
114
+ path: '/test',
105
115
  handler: 'test',
106
116
  },
107
117
  ],
108
118
  triggers: [
109
119
  {
110
120
  function: 'example.com/function/test',
111
- spec: {
112
- type: 'websocket',
121
+ websocket: {
113
122
  // url: 'https://hub.dxos.network/api/mailbox/test',
114
123
  url: 'http://localhost:8081',
115
124
  init: {
@@ -121,11 +130,16 @@ describe('scheduler', () => {
121
130
  };
122
131
 
123
132
  const done = new Trigger();
124
- const scheduler = createScheduler(async () => {
125
- done.wake();
133
+ const scheduler = new Scheduler(client, manifest, {
134
+ callback: async (data) => {
135
+ done.wake();
136
+ },
126
137
  });
127
- await scheduler.register(client.spaces.default, manifest);
138
+
128
139
  await scheduler.start();
140
+ after(async () => {
141
+ await scheduler.stop();
142
+ });
129
143
 
130
144
  // Test server.
131
145
  setTimeout(() => {
@@ -143,20 +157,29 @@ describe('scheduler', () => {
143
157
  });
144
158
 
145
159
  test('subscription', async () => {
160
+ class TestType extends TypedObject({ typename: 'example.com/type/Test', version: '0.1.0' })({
161
+ title: S.string,
162
+ }) {}
163
+ client.addSchema(TestType);
164
+
146
165
  const manifest: FunctionManifest = {
147
166
  functions: [
148
167
  {
149
- uri: 'example.com/function/test',
150
- route: '/test',
168
+ id: 'example.com/function/test',
169
+ path: '/test',
151
170
  handler: 'test',
152
171
  },
153
172
  ],
154
173
  triggers: [
155
174
  {
156
175
  function: 'example.com/function/test',
157
- spec: {
158
- type: 'subscription',
159
- filter: [{ type: TestType.typename }],
176
+ subscription: {
177
+ spaceKey: client.spaces.default.key.toHex(),
178
+ filter: [
179
+ {
180
+ type: TestType.typename,
181
+ },
182
+ ],
160
183
  },
161
184
  },
162
185
  ],
@@ -164,14 +187,20 @@ describe('scheduler', () => {
164
187
 
165
188
  let count = 0;
166
189
  const done = new Trigger();
167
- const scheduler = createScheduler(async () => {
168
- if (++count === 2) {
169
- done.wake();
170
- }
190
+ const scheduler = new Scheduler(client, manifest, {
191
+ callback: async () => {
192
+ if (++count === 2) {
193
+ done.wake();
194
+ }
195
+ },
171
196
  });
172
- await scheduler.register(client.spaces.default, manifest);
197
+
173
198
  await scheduler.start();
199
+ after(async () => {
200
+ await scheduler.stop();
201
+ });
174
202
 
203
+ // TODO(burdon): Query for Expando?
175
204
  setTimeout(() => {
176
205
  const space = client.spaces.default;
177
206
  const object = create(TestType, { title: 'Hello world!' });
@@ -180,12 +209,4 @@ describe('scheduler', () => {
180
209
 
181
210
  await done.wait();
182
211
  });
183
-
184
- const createScheduler = (callback: SchedulerOptions['callback']) => {
185
- const scheduler = new Scheduler(new FunctionRegistry(client), new TriggerRegistry(client), { callback });
186
- after(async () => {
187
- await scheduler.stop();
188
- });
189
- return scheduler;
190
- };
191
212
  });