@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.
- package/dist/lib/browser/index.mjs +429 -802
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +426 -787
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/handler.d.ts +12 -33
- package/dist/types/src/handler.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +0 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/runtime/dev-server.d.ts +13 -16
- package/dist/types/src/runtime/dev-server.d.ts.map +1 -1
- package/dist/types/src/runtime/scheduler.d.ts +27 -12
- package/dist/types/src/runtime/scheduler.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +101 -129
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +13 -18
- package/schema/functions.json +101 -128
- package/src/handler.ts +31 -54
- package/src/index.ts +0 -2
- package/src/runtime/dev-server.ts +52 -104
- package/src/runtime/scheduler.test.ts +73 -56
- package/src/runtime/scheduler.ts +271 -79
- package/src/types.ts +32 -57
- package/dist/types/src/registry/function-registry.d.ts +0 -24
- package/dist/types/src/registry/function-registry.d.ts.map +0 -1
- package/dist/types/src/registry/function-registry.test.d.ts +0 -2
- package/dist/types/src/registry/function-registry.test.d.ts.map +0 -1
- package/dist/types/src/registry/index.d.ts +0 -2
- package/dist/types/src/registry/index.d.ts.map +0 -1
- package/dist/types/src/runtime/dev-server.test.d.ts +0 -2
- package/dist/types/src/runtime/dev-server.test.d.ts.map +0 -1
- package/dist/types/src/testing/functions-integration.test.d.ts +0 -2
- package/dist/types/src/testing/functions-integration.test.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -4
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/testing/setup.d.ts +0 -5
- package/dist/types/src/testing/setup.d.ts.map +0 -1
- package/dist/types/src/testing/test/handler.d.ts +0 -4
- package/dist/types/src/testing/test/handler.d.ts.map +0 -1
- package/dist/types/src/testing/test/index.d.ts +0 -3
- package/dist/types/src/testing/test/index.d.ts.map +0 -1
- package/dist/types/src/testing/types.d.ts +0 -9
- package/dist/types/src/testing/types.d.ts.map +0 -1
- package/dist/types/src/testing/util.d.ts +0 -3
- package/dist/types/src/testing/util.d.ts.map +0 -1
- package/dist/types/src/trigger/index.d.ts +0 -2
- package/dist/types/src/trigger/index.d.ts.map +0 -1
- package/dist/types/src/trigger/trigger-registry.d.ts +0 -40
- package/dist/types/src/trigger/trigger-registry.d.ts.map +0 -1
- package/dist/types/src/trigger/trigger-registry.test.d.ts +0 -2
- package/dist/types/src/trigger/trigger-registry.test.d.ts.map +0 -1
- package/dist/types/src/trigger/type/index.d.ts +0 -5
- package/dist/types/src/trigger/type/index.d.ts.map +0 -1
- package/dist/types/src/trigger/type/subscription-trigger.d.ts +0 -4
- package/dist/types/src/trigger/type/subscription-trigger.d.ts.map +0 -1
- package/dist/types/src/trigger/type/timer-trigger.d.ts +0 -4
- package/dist/types/src/trigger/type/timer-trigger.d.ts.map +0 -1
- package/dist/types/src/trigger/type/webhook-trigger.d.ts +0 -4
- package/dist/types/src/trigger/type/webhook-trigger.d.ts.map +0 -1
- package/dist/types/src/trigger/type/websocket-trigger.d.ts +0 -13
- package/dist/types/src/trigger/type/websocket-trigger.d.ts.map +0 -1
- package/src/registry/function-registry.test.ts +0 -105
- package/src/registry/function-registry.ts +0 -84
- package/src/registry/index.ts +0 -5
- package/src/runtime/dev-server.test.ts +0 -60
- package/src/testing/functions-integration.test.ts +0 -99
- package/src/testing/index.ts +0 -7
- package/src/testing/setup.ts +0 -45
- package/src/testing/test/handler.ts +0 -15
- package/src/testing/test/index.ts +0 -7
- package/src/testing/types.ts +0 -9
- package/src/testing/util.ts +0 -16
- package/src/trigger/index.ts +0 -5
- package/src/trigger/trigger-registry.test.ts +0 -229
- package/src/trigger/trigger-registry.ts +0 -176
- package/src/trigger/type/index.ts +0 -8
- package/src/trigger/type/subscription-trigger.ts +0 -73
- package/src/trigger/type/timer-trigger.ts +0 -44
- package/src/trigger/type/webhook-trigger.ts +0 -47
- 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):
|
|
12
|
-
//
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
|
61
|
-
|
|
36
|
+
export type FunctionSubscriptionEvent = {
|
|
37
|
+
space?: string; // TODO(burdon): Convert to PublicKey.
|
|
62
38
|
objects?: string[];
|
|
63
39
|
};
|
|
64
40
|
|
|
65
|
-
|
|
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 =
|
|
81
|
-
handler: FunctionHandler<
|
|
82
|
-
): FunctionHandler<
|
|
83
|
-
return ({ event
|
|
57
|
+
export const subscriptionHandler = (
|
|
58
|
+
handler: FunctionHandler<FunctionSubscriptionEvent2>,
|
|
59
|
+
): FunctionHandler<FunctionSubscriptionEvent> => {
|
|
60
|
+
return ({ event, context, ...rest }) => {
|
|
84
61
|
const { client } = context;
|
|
85
|
-
const space =
|
|
86
|
-
const objects =
|
|
87
|
-
|
|
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 (!!
|
|
91
|
-
log.warn('invalid space', {
|
|
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: {
|
|
73
|
+
return handler({ event: { space, objects }, context, ...rest });
|
|
97
74
|
};
|
|
98
75
|
};
|
package/src/index.ts
CHANGED
|
@@ -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 {
|
|
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
|
|
17
|
-
import { type
|
|
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
|
|
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
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
68
|
+
async start() {
|
|
82
69
|
const app = express();
|
|
83
70
|
app.use(express.json());
|
|
84
71
|
|
|
85
|
-
app.post('/:
|
|
86
|
-
const {
|
|
72
|
+
app.post('/:name', async (req, res) => {
|
|
73
|
+
const { name } = req.params;
|
|
87
74
|
try {
|
|
88
|
-
log.info('calling', {
|
|
75
|
+
log.info('calling', { name });
|
|
89
76
|
if (this._options.reload) {
|
|
90
|
-
const { def } = this._handlers[
|
|
77
|
+
const { def } = this._handlers[name];
|
|
91
78
|
await this._load(def, true);
|
|
92
79
|
}
|
|
93
80
|
|
|
94
|
-
|
|
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
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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,
|
|
162
|
-
const {
|
|
163
|
-
const
|
|
164
|
-
log.info('loading', {
|
|
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 (
|
|
139
|
+
if (flush) {
|
|
168
140
|
Object.keys(require.cache)
|
|
169
|
-
.filter((key) => key.startsWith(
|
|
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(
|
|
146
|
+
const module = require(path);
|
|
178
147
|
if (typeof module.default !== 'function') {
|
|
179
|
-
throw new Error(`Handler must export default function: ${
|
|
148
|
+
throw new Error(`Handler must export default function: ${id}`);
|
|
180
149
|
}
|
|
181
150
|
|
|
182
|
-
this._handlers[
|
|
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
|
-
|
|
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,
|
|
205
|
-
const
|
|
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:
|
|
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 {
|
|
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
|
|
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 = (
|
|
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
|
|
27
|
+
await client.destroy();
|
|
30
28
|
});
|
|
31
29
|
|
|
32
30
|
test('timer', async () => {
|
|
33
31
|
const manifest: FunctionManifest = {
|
|
34
32
|
functions: [
|
|
35
33
|
{
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
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 =
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
const scheduler = new Scheduler(client, manifest, {
|
|
52
|
+
callback: async () => {
|
|
53
|
+
if (++count === 3) {
|
|
54
|
+
done.wake();
|
|
55
|
+
}
|
|
56
|
+
},
|
|
58
57
|
});
|
|
59
|
-
|
|
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
|
-
|
|
71
|
-
|
|
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
|
-
|
|
79
|
-
|
|
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 =
|
|
88
|
-
|
|
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
|
-
|
|
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
|
-
|
|
104
|
-
|
|
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
|
-
|
|
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 =
|
|
125
|
-
|
|
129
|
+
const scheduler = new Scheduler(client, manifest, {
|
|
130
|
+
callback: async (data) => {
|
|
131
|
+
done.wake();
|
|
132
|
+
},
|
|
126
133
|
});
|
|
127
|
-
|
|
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
|
-
|
|
150
|
-
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
filter: [
|
|
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 =
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
186
|
+
const scheduler = new Scheduler(client, manifest, {
|
|
187
|
+
callback: async () => {
|
|
188
|
+
if (++count === 2) {
|
|
189
|
+
done.wake();
|
|
190
|
+
}
|
|
191
|
+
},
|
|
171
192
|
});
|
|
172
|
-
|
|
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
|
});
|