@dxos/functions 0.5.3-main.d7fe7b5 → 0.5.3-main.e76d664

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 (81) hide show
  1. package/dist/lib/browser/index.mjs +429 -802
  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 +426 -787
  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 -33
  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 +13 -16
  12. package/dist/types/src/runtime/dev-server.d.ts.map +1 -1
  13. package/dist/types/src/runtime/scheduler.d.ts +27 -12
  14. package/dist/types/src/runtime/scheduler.d.ts.map +1 -1
  15. package/dist/types/src/types.d.ts +101 -129
  16. package/dist/types/src/types.d.ts.map +1 -1
  17. package/package.json +13 -18
  18. package/schema/functions.json +101 -128
  19. package/src/handler.ts +31 -54
  20. package/src/index.ts +0 -2
  21. package/src/runtime/dev-server.ts +52 -104
  22. package/src/runtime/scheduler.test.ts +73 -56
  23. package/src/runtime/scheduler.ts +271 -79
  24. package/src/types.ts +32 -57
  25. package/dist/types/src/registry/function-registry.d.ts +0 -24
  26. package/dist/types/src/registry/function-registry.d.ts.map +0 -1
  27. package/dist/types/src/registry/function-registry.test.d.ts +0 -2
  28. package/dist/types/src/registry/function-registry.test.d.ts.map +0 -1
  29. package/dist/types/src/registry/index.d.ts +0 -2
  30. package/dist/types/src/registry/index.d.ts.map +0 -1
  31. package/dist/types/src/runtime/dev-server.test.d.ts +0 -2
  32. package/dist/types/src/runtime/dev-server.test.d.ts.map +0 -1
  33. package/dist/types/src/testing/functions-integration.test.d.ts +0 -2
  34. package/dist/types/src/testing/functions-integration.test.d.ts.map +0 -1
  35. package/dist/types/src/testing/index.d.ts +0 -4
  36. package/dist/types/src/testing/index.d.ts.map +0 -1
  37. package/dist/types/src/testing/setup.d.ts +0 -5
  38. package/dist/types/src/testing/setup.d.ts.map +0 -1
  39. package/dist/types/src/testing/test/handler.d.ts +0 -4
  40. package/dist/types/src/testing/test/handler.d.ts.map +0 -1
  41. package/dist/types/src/testing/test/index.d.ts +0 -3
  42. package/dist/types/src/testing/test/index.d.ts.map +0 -1
  43. package/dist/types/src/testing/types.d.ts +0 -9
  44. package/dist/types/src/testing/types.d.ts.map +0 -1
  45. package/dist/types/src/testing/util.d.ts +0 -3
  46. package/dist/types/src/testing/util.d.ts.map +0 -1
  47. package/dist/types/src/trigger/index.d.ts +0 -2
  48. package/dist/types/src/trigger/index.d.ts.map +0 -1
  49. package/dist/types/src/trigger/trigger-registry.d.ts +0 -40
  50. package/dist/types/src/trigger/trigger-registry.d.ts.map +0 -1
  51. package/dist/types/src/trigger/trigger-registry.test.d.ts +0 -2
  52. package/dist/types/src/trigger/trigger-registry.test.d.ts.map +0 -1
  53. package/dist/types/src/trigger/type/index.d.ts +0 -5
  54. package/dist/types/src/trigger/type/index.d.ts.map +0 -1
  55. package/dist/types/src/trigger/type/subscription-trigger.d.ts +0 -4
  56. package/dist/types/src/trigger/type/subscription-trigger.d.ts.map +0 -1
  57. package/dist/types/src/trigger/type/timer-trigger.d.ts +0 -4
  58. package/dist/types/src/trigger/type/timer-trigger.d.ts.map +0 -1
  59. package/dist/types/src/trigger/type/webhook-trigger.d.ts +0 -4
  60. package/dist/types/src/trigger/type/webhook-trigger.d.ts.map +0 -1
  61. package/dist/types/src/trigger/type/websocket-trigger.d.ts +0 -13
  62. package/dist/types/src/trigger/type/websocket-trigger.d.ts.map +0 -1
  63. package/src/registry/function-registry.test.ts +0 -105
  64. package/src/registry/function-registry.ts +0 -84
  65. package/src/registry/index.ts +0 -5
  66. package/src/runtime/dev-server.test.ts +0 -60
  67. package/src/testing/functions-integration.test.ts +0 -99
  68. package/src/testing/index.ts +0 -7
  69. package/src/testing/setup.ts +0 -45
  70. package/src/testing/test/handler.ts +0 -15
  71. package/src/testing/test/index.ts +0 -7
  72. package/src/testing/types.ts +0 -9
  73. package/src/testing/util.ts +0 -16
  74. package/src/trigger/index.ts +0 -5
  75. package/src/trigger/trigger-registry.test.ts +0 -229
  76. package/src/trigger/trigger-registry.ts +0 -176
  77. package/src/trigger/type/index.ts +0 -8
  78. package/src/trigger/type/subscription-trigger.ts +0 -73
  79. package/src/trigger/type/timer-trigger.ts +0 -44
  80. package/src/trigger/type/webhook-trigger.ts +0 -47
  81. 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
13
- // https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml/#functions
11
+ // TODO(burdon): Context?
12
+ // Lambda-like function definitions.
13
+ // See: https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml/#functions
14
14
  // https://www.npmjs.com/package/aws-lambda
15
+ // https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html
15
16
 
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>;
17
+ // TODO(burdon): No response?
18
+ export interface Response {
19
+ status(code: number): Response;
20
+ }
24
21
 
25
- /**
26
- * Function context.
27
- */
22
+ // TODO(burdon): Limit access to individual space?
28
23
  export interface FunctionContext {
29
- // TODO(burdon): Limit access to individual space.
30
24
  client: Client;
31
- // TODO(burdon): Replace with storage service abstraction.
32
25
  dataDir?: string;
33
26
  }
34
27
 
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
- //
28
+ // TODO(burdon): Model after http request. Ref Lambda/OpenFaaS.
29
+ // https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html
30
+ export type FunctionHandler<T extends {}> = (params: {
31
+ event: T;
32
+ context: FunctionContext;
33
+ response: Response;
34
+ }) => Promise<Response | void>;
59
35
 
60
- export type RawSubscriptionData = {
61
- spaceKey?: string;
36
+ export type FunctionSubscriptionEvent = {
37
+ space?: string; // TODO(burdon): Convert to PublicKey.
62
38
  objects?: string[];
63
39
  };
64
40
 
65
- export type SubscriptionData = {
41
+ // TODO(burdon): ???
42
+ export type FunctionSubscriptionEvent2 = {
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<FunctionSubscriptionEvent2>,
59
+ ): FunctionHandler<FunctionSubscriptionEvent> => {
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.space ? client.spaces.get(PublicKey.from(event.space)) : 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.space && !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';
@@ -7,19 +7,18 @@ import { getPort } from 'get-port-please';
7
7
  import type http from 'http';
8
8
  import { join } from 'node:path';
9
9
 
10
- import { Event, Trigger } from '@dxos/async';
10
+ import { 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 = {
21
- baseDir: string;
22
19
  port?: number;
20
+ directory: string;
21
+ manifest: FunctionManifest;
23
22
  reload?: boolean;
24
23
  dataDir?: string;
25
24
  };
@@ -28,37 +27,20 @@ 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
 
36
33
  private _server?: http.Server;
37
34
  private _port?: number;
38
- private _functionServiceRegistration?: string;
35
+ private _registrationId?: string;
39
36
  private _proxy?: string;
40
37
  private _seq = 0;
41
38
 
42
- public readonly update = new Event<number>();
43
-
44
39
  // prettier-ignore
45
40
  constructor(
46
41
  private readonly _client: Client,
47
- private readonly _functionsRegistry: FunctionRegistry,
48
42
  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
- }
56
-
57
- get stats() {
58
- return {
59
- seq: this._seq,
60
- };
61
- }
43
+ ) {}
62
44
 
63
45
  get endpoint() {
64
46
  invariant(this._port);
@@ -73,26 +55,30 @@ export class DevServer {
73
55
  return Object.values(this._handlers);
74
56
  }
75
57
 
76
- async start() {
77
- invariant(!this._server);
78
- log.info('starting...');
79
- this._ctx = createContext();
58
+ async initialize() {
59
+ for (const def of this._options.manifest.functions) {
60
+ try {
61
+ await this._load(def);
62
+ } catch (err) {
63
+ log.error('parsing function (check manifest)', err);
64
+ }
65
+ }
66
+ }
80
67
 
81
- // TODO(burdon): Move to hono.
68
+ async start() {
82
69
  const app = express();
83
70
  app.use(express.json());
84
71
 
85
- app.post('/:path', async (req, res) => {
86
- const { path } = req.params;
72
+ app.post('/:name', async (req, res) => {
73
+ const { name } = req.params;
87
74
  try {
88
- log.info('calling', { path });
75
+ log.info('calling', { name });
89
76
  if (this._options.reload) {
90
- const { def } = this._handlers['/' + path];
77
+ const { def } = this._handlers[name];
91
78
  await this._load(def, true);
92
79
  }
93
80
 
94
- // TODO(burdon): Get function context.
95
- res.statusCode = await this.invoke('/' + path, req.body);
81
+ res.statusCode = await this._invoke(name, req.body);
96
82
  res.end();
97
83
  } catch (err: any) {
98
84
  log.catch(err);
@@ -108,110 +94,72 @@ export class DevServer {
108
94
  // Register functions.
109
95
  const { registrationId, endpoint } = await this._client.services.services.FunctionRegistryService!.register({
110
96
  endpoint: this.endpoint,
97
+ functions: this.functions.map(({ def: { name } }) => ({ name })),
111
98
  });
112
99
 
113
- log.info('registered', { endpoint });
100
+ log.info('registered', { registrationId, endpoint });
101
+ this._registrationId = registrationId;
114
102
  this._proxy = endpoint;
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
103
  } catch (err: any) {
120
104
  await this.stop();
121
105
  throw new Error('FunctionRegistryService not available (check plugin is configured).');
122
106
  }
123
-
124
- log.info('started', { port: this._port });
125
107
  }
126
108
 
127
109
  async stop() {
128
- invariant(this._server);
129
- log.info('stopping...');
130
-
131
110
  const trigger = new Trigger();
132
- this._server.close(async () => {
133
- log.info('server stopped');
134
- try {
135
- if (this._functionServiceRegistration) {
136
- invariant(this._client.services.services.FunctionRegistryService);
137
- await this._client.services.services.FunctionRegistryService.unregister({
138
- registrationId: this._functionServiceRegistration,
139
- });
140
-
141
- log.info('unregistered', { registrationId: this._functionServiceRegistration });
142
- this._functionServiceRegistration = undefined;
143
- this._proxy = undefined;
144
- }
111
+ this._server?.close(async () => {
112
+ if (this._registrationId) {
113
+ await this._client.services.services.FunctionRegistryService!.unregister({
114
+ registrationId: this._registrationId,
115
+ });
145
116
 
146
- trigger.wake();
147
- } catch (err) {
148
- trigger.throw(err as Error);
117
+ log.info('unregistered', { registrationId: this._registrationId });
118
+ this._registrationId = undefined;
119
+ this._proxy = undefined;
149
120
  }
121
+
122
+ trigger.wake();
150
123
  });
151
124
 
152
125
  await trigger.wait();
153
126
  this._port = undefined;
154
127
  this._server = undefined;
155
- log.info('stopped');
156
128
  }
157
129
 
158
130
  /**
159
131
  * Load function.
160
132
  */
161
- private async _load(def: FunctionDef, force = false) {
162
- const { uri, route, handler } = def;
163
- const filePath = join(this._options.baseDir, handler);
164
- log.info('loading', { uri, force });
133
+ private async _load(def: FunctionDef, flush = false) {
134
+ const { id, name, handler } = def;
135
+ const path = join(this._options.directory, handler);
136
+ log.info('loading', { id });
165
137
 
166
138
  // Remove from cache.
167
- if (force) {
139
+ if (flush) {
168
140
  Object.keys(require.cache)
169
- .filter((key) => key.startsWith(filePath))
170
- .forEach((key) => {
171
- delete require.cache[key];
172
- });
141
+ .filter((key) => key.startsWith(path))
142
+ .forEach((key) => delete require.cache[key]);
173
143
  }
174
144
 
175
- // TODO(burdon): Import types.
176
145
  // eslint-disable-next-line @typescript-eslint/no-var-requires
177
- const module = require(filePath);
146
+ const module = require(path);
178
147
  if (typeof module.default !== 'function') {
179
- throw new Error(`Handler must export default function: ${uri}`);
148
+ throw new Error(`Handler must export default function: ${id}`);
180
149
  }
181
150
 
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
- }
151
+ this._handlers[name] = { def, handler: module.default };
195
152
  }
196
153
 
197
154
  /**
198
- * Invoke function.
155
+ * Invoke function handler.
199
156
  */
200
- public async invoke(path: string, data: any): Promise<number> {
157
+ private async _invoke(name: string, event: any) {
201
158
  const seq = ++this._seq;
202
159
  const now = Date.now();
203
160
 
204
- log.info('req', { seq, path });
205
- const statusCode = await this._invoke(path, { data });
206
-
207
- log.info('res', { seq, path, statusCode, duration: Date.now() - now });
208
- this.update.emit(statusCode);
209
- return statusCode;
210
- }
211
-
212
- private async _invoke(path: string, event: FunctionEvent) {
213
- const { handler } = this._handlers[path] ?? {};
214
- invariant(handler, `invalid path: ${path}`);
161
+ log.info('req', { seq, name });
162
+ const { handler } = this._handlers[name];
215
163
 
216
164
  const context: FunctionContext = {
217
165
  client: this._client,
@@ -219,7 +167,7 @@ export class DevServer {
219
167
  };
220
168
 
221
169
  let statusCode = 200;
222
- const response: FunctionResponse = {
170
+ const response: Response = {
223
171
  status: (code: number) => {
224
172
  statusCode = code;
225
173
  return response;
@@ -227,8 +175,8 @@ export class DevServer {
227
175
  };
228
176
 
229
177
  await handler({ context, event, response });
178
+ log.info('res', { seq, name, statusCode, duration: Date.now() - now });
179
+
230
180
  return statusCode;
231
181
  }
232
182
  }
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';
14
+ import { Scheduler } from './scheduler';
18
15
  import { type FunctionManifest } 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.createLocal() });
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
+ name: '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,49 +69,52 @@ 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
+ name: '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
- method: 'GET',
80
+ webhook: {
81
+ port: 8080,
81
82
  },
82
83
  },
83
84
  ],
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);
92
- await scheduler.start();
93
93
 
94
- setTimeout(async () => triggerWebhook(space, manifest.functions![0].uri));
94
+ await scheduler.start();
95
+ after(async () => {
96
+ await scheduler.stop();
97
+ });
95
98
 
99
+ setTimeout(() => {
100
+ void fetch('http://localhost:8080');
101
+ });
96
102
  await done.wait();
97
103
  });
98
104
 
99
- test('websocket', async () => {
105
+ test.only('websocket', async () => {
100
106
  const manifest: FunctionManifest = {
101
107
  functions: [
102
108
  {
103
- uri: 'example.com/function/test',
104
- route: '/test',
109
+ id: 'example.com/function/test',
110
+ name: 'test',
105
111
  handler: 'test',
106
112
  },
107
113
  ],
108
114
  triggers: [
109
115
  {
110
116
  function: 'example.com/function/test',
111
- spec: {
112
- type: 'websocket',
117
+ websocket: {
113
118
  // url: 'https://hub.dxos.network/api/mailbox/test',
114
119
  url: 'http://localhost:8081',
115
120
  init: {
@@ -121,11 +126,16 @@ describe('scheduler', () => {
121
126
  };
122
127
 
123
128
  const done = new Trigger();
124
- const scheduler = createScheduler(async () => {
125
- done.wake();
129
+ const scheduler = new Scheduler(client, manifest, {
130
+ callback: async (data) => {
131
+ done.wake();
132
+ },
126
133
  });
127
- await scheduler.register(client.spaces.default, manifest);
134
+
128
135
  await scheduler.start();
136
+ after(async () => {
137
+ await scheduler.stop();
138
+ });
129
139
 
130
140
  // Test server.
131
141
  setTimeout(() => {
@@ -143,20 +153,29 @@ describe('scheduler', () => {
143
153
  });
144
154
 
145
155
  test('subscription', async () => {
156
+ class TestType extends TypedObject({ typename: 'example.com/type/Test', version: '0.1.0' })({
157
+ title: S.string,
158
+ }) {}
159
+ client.addSchema(TestType);
160
+
146
161
  const manifest: FunctionManifest = {
147
162
  functions: [
148
163
  {
149
- uri: 'example.com/function/test',
150
- route: '/test',
164
+ id: 'example.com/function/test',
165
+ name: 'test',
151
166
  handler: 'test',
152
167
  },
153
168
  ],
154
169
  triggers: [
155
170
  {
156
171
  function: 'example.com/function/test',
157
- spec: {
158
- type: 'subscription',
159
- filter: [{ type: TestType.typename }],
172
+ subscription: {
173
+ spaceKey: client.spaces.default.key.toHex(),
174
+ filter: [
175
+ {
176
+ type: TestType.typename,
177
+ },
178
+ ],
160
179
  },
161
180
  },
162
181
  ],
@@ -164,14 +183,20 @@ describe('scheduler', () => {
164
183
 
165
184
  let count = 0;
166
185
  const done = new Trigger();
167
- const scheduler = createScheduler(async () => {
168
- if (++count === 2) {
169
- done.wake();
170
- }
186
+ const scheduler = new Scheduler(client, manifest, {
187
+ callback: async () => {
188
+ if (++count === 2) {
189
+ done.wake();
190
+ }
191
+ },
171
192
  });
172
- await scheduler.register(client.spaces.default, manifest);
193
+
173
194
  await scheduler.start();
195
+ after(async () => {
196
+ await scheduler.stop();
197
+ });
174
198
 
199
+ // TODO(burdon): Query for Expando?
175
200
  setTimeout(() => {
176
201
  const space = client.spaces.default;
177
202
  const object = create(TestType, { title: 'Hello world!' });
@@ -180,12 +205,4 @@ describe('scheduler', () => {
180
205
 
181
206
  await done.wait();
182
207
  });
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
208
  });