@dxos/functions 0.5.3-main.f752aaa → 0.5.3-next.57eca40
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/chunk-366QG6IX.mjs +81 -0
- package/dist/lib/browser/chunk-366QG6IX.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +825 -471
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/types.mjs +12 -0
- package/dist/lib/browser/types.mjs.map +7 -0
- package/dist/lib/node/chunk-3VSJ57ZZ.cjs +97 -0
- package/dist/lib/node/chunk-3VSJ57ZZ.cjs.map +7 -0
- package/dist/lib/node/index.cjs +805 -461
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/types.cjs +33 -0
- package/dist/lib/node/types.cjs.map +7 -0
- package/dist/types/src/function/function-registry.d.ts +24 -0
- package/dist/types/src/function/function-registry.d.ts.map +1 -0
- package/dist/types/src/function/function-registry.test.d.ts +2 -0
- package/dist/types/src/function/function-registry.test.d.ts.map +1 -0
- package/dist/types/src/function/index.d.ts +2 -0
- package/dist/types/src/function/index.d.ts.map +1 -0
- package/dist/types/src/handler.d.ts +33 -12
- package/dist/types/src/handler.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/runtime/dev-server.d.ts +16 -13
- package/dist/types/src/runtime/dev-server.d.ts.map +1 -1
- package/dist/types/src/runtime/dev-server.test.d.ts +2 -0
- package/dist/types/src/runtime/dev-server.test.d.ts.map +1 -0
- package/dist/types/src/runtime/scheduler.d.ts +13 -27
- package/dist/types/src/runtime/scheduler.d.ts.map +1 -1
- package/dist/types/src/testing/functions-integration.test.d.ts +2 -0
- package/dist/types/src/testing/functions-integration.test.d.ts.map +1 -0
- package/dist/types/src/testing/index.d.ts +4 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/setup.d.ts +5 -0
- package/dist/types/src/testing/setup.d.ts.map +1 -0
- package/dist/types/src/testing/test/handler.d.ts +4 -0
- package/dist/types/src/testing/test/handler.d.ts.map +1 -0
- package/dist/types/src/testing/test/index.d.ts +3 -0
- package/dist/types/src/testing/test/index.d.ts.map +1 -0
- package/dist/types/src/testing/types.d.ts +9 -0
- package/dist/types/src/testing/types.d.ts.map +1 -0
- package/dist/types/src/testing/util.d.ts +3 -0
- package/dist/types/src/testing/util.d.ts.map +1 -0
- package/dist/types/src/trigger/index.d.ts +2 -0
- package/dist/types/src/trigger/index.d.ts.map +1 -0
- package/dist/types/src/trigger/trigger-registry.d.ts +40 -0
- package/dist/types/src/trigger/trigger-registry.d.ts.map +1 -0
- package/dist/types/src/trigger/trigger-registry.test.d.ts +2 -0
- package/dist/types/src/trigger/trigger-registry.test.d.ts.map +1 -0
- package/dist/types/src/trigger/type/index.d.ts +5 -0
- package/dist/types/src/trigger/type/index.d.ts.map +1 -0
- package/dist/types/src/trigger/type/subscription-trigger.d.ts +4 -0
- package/dist/types/src/trigger/type/subscription-trigger.d.ts.map +1 -0
- package/dist/types/src/trigger/type/timer-trigger.d.ts +4 -0
- package/dist/types/src/trigger/type/timer-trigger.d.ts.map +1 -0
- package/dist/types/src/trigger/type/webhook-trigger.d.ts +4 -0
- package/dist/types/src/trigger/type/webhook-trigger.d.ts.map +1 -0
- package/dist/types/src/trigger/type/websocket-trigger.d.ts +13 -0
- package/dist/types/src/trigger/type/websocket-trigger.d.ts.map +1 -0
- package/dist/types/src/types.d.ts +143 -101
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +15 -0
- package/dist/types/src/util.d.ts.map +1 -0
- package/dist/types/src/util.test.d.ts +2 -0
- package/dist/types/src/util.test.d.ts.map +1 -0
- package/package.json +33 -15
- package/schema/functions.json +140 -104
- package/src/function/function-registry.test.ts +105 -0
- package/src/function/function-registry.ts +90 -0
- package/src/function/index.ts +5 -0
- package/src/handler.ts +54 -31
- package/src/index.ts +2 -0
- package/src/runtime/dev-server.test.ts +60 -0
- package/src/runtime/dev-server.ts +104 -53
- package/src/runtime/scheduler.test.ts +56 -73
- package/src/runtime/scheduler.ts +87 -271
- package/src/testing/functions-integration.test.ts +99 -0
- package/src/testing/index.ts +7 -0
- package/src/testing/setup.ts +45 -0
- package/src/testing/test/handler.ts +15 -0
- package/src/testing/test/index.ts +7 -0
- package/src/testing/types.ts +9 -0
- package/src/testing/util.ts +16 -0
- package/src/trigger/index.ts +5 -0
- package/src/trigger/trigger-registry.test.ts +255 -0
- package/src/trigger/trigger-registry.ts +189 -0
- package/src/trigger/type/index.ts +8 -0
- package/src/trigger/type/subscription-trigger.ts +80 -0
- package/src/trigger/type/timer-trigger.ts +44 -0
- package/src/trigger/type/webhook-trigger.ts +47 -0
- package/src/trigger/type/websocket-trigger.ts +91 -0
- package/src/types.ts +59 -32
- package/src/util.test.ts +43 -0
- package/src/util.ts +48 -0
package/src/handler.ts
CHANGED
|
@@ -8,38 +8,61 @@ 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
|
-
// Lambda-like function definitions.
|
|
13
|
-
// See: https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml/#functions
|
|
14
|
-
// https://www.npmjs.com/package/aws-lambda
|
|
11
|
+
// TODO(burdon): Model after http request. Ref Lambda/OpenFaaS.
|
|
15
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
|
|
14
|
+
// https://www.npmjs.com/package/aws-lambda
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
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>;
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Function context.
|
|
27
|
+
*/
|
|
23
28
|
export interface FunctionContext {
|
|
29
|
+
// TODO(burdon): Limit access to individual space.
|
|
24
30
|
client: Client;
|
|
31
|
+
// TODO(burdon): Replace with storage service abstraction.
|
|
25
32
|
dataDir?: string;
|
|
26
33
|
}
|
|
27
34
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
+
//
|
|
35
59
|
|
|
36
|
-
export type
|
|
37
|
-
|
|
60
|
+
export type RawSubscriptionData = {
|
|
61
|
+
spaceKey?: string;
|
|
38
62
|
objects?: string[];
|
|
39
63
|
};
|
|
40
64
|
|
|
41
|
-
|
|
42
|
-
export type FunctionSubscriptionEvent2 = {
|
|
65
|
+
export type SubscriptionData = {
|
|
43
66
|
space?: Space;
|
|
44
67
|
objects?: EchoReactiveObject<any>[];
|
|
45
68
|
};
|
|
@@ -54,22 +77,22 @@ export type FunctionSubscriptionEvent2 = {
|
|
|
54
77
|
*
|
|
55
78
|
* NOTE: Get space key from devtools or `dx space list --json`
|
|
56
79
|
*/
|
|
57
|
-
export const subscriptionHandler = (
|
|
58
|
-
handler: FunctionHandler<
|
|
59
|
-
): FunctionHandler<
|
|
60
|
-
return ({ event, context, ...rest }) => {
|
|
80
|
+
export const subscriptionHandler = <TMeta>(
|
|
81
|
+
handler: FunctionHandler<SubscriptionData, TMeta>,
|
|
82
|
+
): FunctionHandler<RawSubscriptionData, TMeta> => {
|
|
83
|
+
return ({ event: { data }, context, ...rest }) => {
|
|
61
84
|
const { client } = context;
|
|
62
|
-
const space =
|
|
63
|
-
const objects =
|
|
64
|
-
space
|
|
65
|
-
|
|
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
|
+
: [];
|
|
66
89
|
|
|
67
|
-
if (!!
|
|
68
|
-
log.warn('invalid space', {
|
|
90
|
+
if (!!data.spaceKey && !space) {
|
|
91
|
+
log.warn('invalid space', { data });
|
|
69
92
|
} else {
|
|
70
93
|
log.info('handler', { space: space?.key.truncate(), objects: objects?.length });
|
|
71
94
|
}
|
|
72
95
|
|
|
73
|
-
return handler({ event: { space, objects }, context, ...rest });
|
|
96
|
+
return handler({ event: { data: { ...data, space, objects } }, context, ...rest });
|
|
74
97
|
};
|
|
75
98
|
};
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { expect } from 'chai';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
|
|
8
|
+
import { waitForCondition } from '@dxos/async';
|
|
9
|
+
import { type Client } from '@dxos/client';
|
|
10
|
+
import { TestBuilder } from '@dxos/client/testing';
|
|
11
|
+
import { describe, test } from '@dxos/test';
|
|
12
|
+
|
|
13
|
+
import { DevServer } from './dev-server';
|
|
14
|
+
import { FunctionRegistry } from '../function';
|
|
15
|
+
import { createFunctionRuntime } from '../testing';
|
|
16
|
+
import { type FunctionManifest } from '../types';
|
|
17
|
+
|
|
18
|
+
describe('dev server', () => {
|
|
19
|
+
let client: Client;
|
|
20
|
+
let testBuilder: TestBuilder;
|
|
21
|
+
before(async () => {
|
|
22
|
+
testBuilder = new TestBuilder();
|
|
23
|
+
client = await createFunctionRuntime(testBuilder);
|
|
24
|
+
expect(client.services.services.FunctionRegistryService).to.exist;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
after(async () => {
|
|
28
|
+
await testBuilder.destroy();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('start/stop', async () => {
|
|
32
|
+
const manifest: FunctionManifest = {
|
|
33
|
+
functions: [
|
|
34
|
+
{
|
|
35
|
+
uri: 'example.com/function/test',
|
|
36
|
+
route: 'test',
|
|
37
|
+
handler: 'test',
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const registry = new FunctionRegistry(client);
|
|
43
|
+
const server = new DevServer(client, registry, {
|
|
44
|
+
baseDir: path.join(__dirname, '../testing'),
|
|
45
|
+
});
|
|
46
|
+
const space = await client.spaces.create();
|
|
47
|
+
await registry.register(space, manifest.functions);
|
|
48
|
+
await server.start();
|
|
49
|
+
|
|
50
|
+
// TODO(burdon): Doesn't shut down cleanly.
|
|
51
|
+
// Error: invariant violation [this._client.services.services.FunctionRegistryService]
|
|
52
|
+
testBuilder.ctx.onDispose(() => server.stop());
|
|
53
|
+
expect(server).to.exist;
|
|
54
|
+
|
|
55
|
+
await waitForCondition({ condition: () => server.functions.length > 0 });
|
|
56
|
+
|
|
57
|
+
await server.invoke('test', {});
|
|
58
|
+
expect(server.stats.seq).to.eq(1);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -7,18 +7,19 @@ import { getPort } from 'get-port-please';
|
|
|
7
7
|
import type http from 'http';
|
|
8
8
|
import { join } from 'node:path';
|
|
9
9
|
|
|
10
|
-
import { Trigger } from '@dxos/async';
|
|
10
|
+
import { Event, Trigger } from '@dxos/async';
|
|
11
11
|
import { type Client } from '@dxos/client';
|
|
12
|
+
import { Context } from '@dxos/context';
|
|
12
13
|
import { invariant } from '@dxos/invariant';
|
|
13
14
|
import { log } from '@dxos/log';
|
|
14
15
|
|
|
15
|
-
import { type
|
|
16
|
-
import { type
|
|
16
|
+
import { type FunctionRegistry } from '../function';
|
|
17
|
+
import { type FunctionContext, type FunctionEvent, type FunctionHandler, type FunctionResponse } from '../handler';
|
|
18
|
+
import { type FunctionDef } from '../types';
|
|
17
19
|
|
|
18
20
|
export type DevServerOptions = {
|
|
21
|
+
baseDir: string;
|
|
19
22
|
port?: number;
|
|
20
|
-
directory: string;
|
|
21
|
-
manifest: FunctionManifest;
|
|
22
23
|
reload?: boolean;
|
|
23
24
|
dataDir?: string;
|
|
24
25
|
};
|
|
@@ -27,20 +28,36 @@ export type DevServerOptions = {
|
|
|
27
28
|
* Functions dev server provides a local HTTP server for testing functions.
|
|
28
29
|
*/
|
|
29
30
|
export class DevServer {
|
|
31
|
+
private _ctx = createContext();
|
|
32
|
+
|
|
30
33
|
// Function handlers indexed by name (URL path).
|
|
31
34
|
private readonly _handlers: Record<string, { def: FunctionDef; handler: FunctionHandler<any> }> = {};
|
|
32
35
|
|
|
33
36
|
private _server?: http.Server;
|
|
34
37
|
private _port?: number;
|
|
35
|
-
private
|
|
38
|
+
private _functionServiceRegistration?: string;
|
|
36
39
|
private _proxy?: string;
|
|
37
40
|
private _seq = 0;
|
|
38
41
|
|
|
39
|
-
|
|
42
|
+
public readonly update = new Event<number>();
|
|
43
|
+
|
|
40
44
|
constructor(
|
|
41
45
|
private readonly _client: Client,
|
|
46
|
+
private readonly _functionsRegistry: FunctionRegistry,
|
|
42
47
|
private readonly _options: DevServerOptions,
|
|
43
|
-
) {
|
|
48
|
+
) {
|
|
49
|
+
this._functionsRegistry.registered.on(async ({ added }) => {
|
|
50
|
+
added.forEach((def) => this._load(def));
|
|
51
|
+
await this._safeUpdateRegistration();
|
|
52
|
+
log('new functions loaded', { added });
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get stats() {
|
|
57
|
+
return {
|
|
58
|
+
seq: this._seq,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
44
61
|
|
|
45
62
|
get endpoint() {
|
|
46
63
|
invariant(this._port);
|
|
@@ -55,30 +72,26 @@ export class DevServer {
|
|
|
55
72
|
return Object.values(this._handlers);
|
|
56
73
|
}
|
|
57
74
|
|
|
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
|
-
}
|
|
67
|
-
|
|
68
75
|
async start() {
|
|
76
|
+
invariant(!this._server);
|
|
77
|
+
log.info('starting...');
|
|
78
|
+
this._ctx = createContext();
|
|
79
|
+
|
|
80
|
+
// TODO(burdon): Move to hono.
|
|
69
81
|
const app = express();
|
|
70
82
|
app.use(express.json());
|
|
71
83
|
|
|
72
|
-
app.post('/:
|
|
73
|
-
const {
|
|
84
|
+
app.post('/:path', async (req, res) => {
|
|
85
|
+
const { path } = req.params;
|
|
74
86
|
try {
|
|
75
|
-
log.info('calling', {
|
|
87
|
+
log.info('calling', { path });
|
|
76
88
|
if (this._options.reload) {
|
|
77
|
-
const { def } = this._handlers[
|
|
89
|
+
const { def } = this._handlers['/' + path];
|
|
78
90
|
await this._load(def, true);
|
|
79
91
|
}
|
|
80
92
|
|
|
81
|
-
|
|
93
|
+
// TODO(burdon): Get function context.
|
|
94
|
+
res.statusCode = await this.invoke('/' + path, req.body);
|
|
82
95
|
res.end();
|
|
83
96
|
} catch (err: any) {
|
|
84
97
|
log.catch(err);
|
|
@@ -94,72 +107,110 @@ export class DevServer {
|
|
|
94
107
|
// Register functions.
|
|
95
108
|
const { registrationId, endpoint } = await this._client.services.services.FunctionRegistryService!.register({
|
|
96
109
|
endpoint: this.endpoint,
|
|
97
|
-
functions: this.functions.map(({ def: { name } }) => ({ name })),
|
|
98
110
|
});
|
|
99
111
|
|
|
100
|
-
log.info('registered', {
|
|
101
|
-
this._registrationId = registrationId;
|
|
112
|
+
log.info('registered', { endpoint });
|
|
102
113
|
this._proxy = endpoint;
|
|
114
|
+
this._functionServiceRegistration = registrationId;
|
|
115
|
+
|
|
116
|
+
// Open after registration, so that it can be updated with the list of function definitions.
|
|
117
|
+
await this._functionsRegistry.open(this._ctx);
|
|
103
118
|
} catch (err: any) {
|
|
104
119
|
await this.stop();
|
|
105
120
|
throw new Error('FunctionRegistryService not available (check plugin is configured).');
|
|
106
121
|
}
|
|
122
|
+
|
|
123
|
+
log.info('started', { port: this._port });
|
|
107
124
|
}
|
|
108
125
|
|
|
109
126
|
async stop() {
|
|
127
|
+
invariant(this._server);
|
|
128
|
+
log.info('stopping...');
|
|
129
|
+
|
|
110
130
|
const trigger = new Trigger();
|
|
111
|
-
this._server
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
131
|
+
this._server.close(async () => {
|
|
132
|
+
log.info('server stopped');
|
|
133
|
+
try {
|
|
134
|
+
if (this._functionServiceRegistration) {
|
|
135
|
+
invariant(this._client.services.services.FunctionRegistryService);
|
|
136
|
+
await this._client.services.services.FunctionRegistryService.unregister({
|
|
137
|
+
registrationId: this._functionServiceRegistration,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
log.info('unregistered', { registrationId: this._functionServiceRegistration });
|
|
141
|
+
this._functionServiceRegistration = undefined;
|
|
142
|
+
this._proxy = undefined;
|
|
143
|
+
}
|
|
116
144
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
145
|
+
trigger.wake();
|
|
146
|
+
} catch (err) {
|
|
147
|
+
trigger.throw(err as Error);
|
|
120
148
|
}
|
|
121
|
-
|
|
122
|
-
trigger.wake();
|
|
123
149
|
});
|
|
124
150
|
|
|
125
151
|
await trigger.wait();
|
|
126
152
|
this._port = undefined;
|
|
127
153
|
this._server = undefined;
|
|
154
|
+
log.info('stopped');
|
|
128
155
|
}
|
|
129
156
|
|
|
130
157
|
/**
|
|
131
158
|
* Load function.
|
|
132
159
|
*/
|
|
133
|
-
private async _load(def: FunctionDef,
|
|
134
|
-
const {
|
|
135
|
-
const
|
|
136
|
-
log.info('loading', {
|
|
160
|
+
private async _load(def: FunctionDef, force?: boolean | undefined) {
|
|
161
|
+
const { uri, route, handler } = def;
|
|
162
|
+
const filePath = join(this._options.baseDir, handler);
|
|
163
|
+
log.info('loading', { uri, force });
|
|
137
164
|
|
|
138
165
|
// Remove from cache.
|
|
139
|
-
if (
|
|
166
|
+
if (force) {
|
|
140
167
|
Object.keys(require.cache)
|
|
141
|
-
.filter((key) => key.startsWith(
|
|
142
|
-
.forEach((key) =>
|
|
168
|
+
.filter((key) => key.startsWith(filePath))
|
|
169
|
+
.forEach((key) => {
|
|
170
|
+
delete require.cache[key];
|
|
171
|
+
});
|
|
143
172
|
}
|
|
144
173
|
|
|
174
|
+
// TODO(burdon): Import types.
|
|
145
175
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
146
|
-
const module = require(
|
|
176
|
+
const module = require(filePath);
|
|
147
177
|
if (typeof module.default !== 'function') {
|
|
148
|
-
throw new Error(`Handler must export default function: ${
|
|
178
|
+
throw new Error(`Handler must export default function: ${uri}`);
|
|
149
179
|
}
|
|
150
180
|
|
|
151
|
-
this._handlers[
|
|
181
|
+
this._handlers[route] = { def, handler: module.default };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private async _safeUpdateRegistration(): Promise<void> {
|
|
185
|
+
invariant(this._functionServiceRegistration);
|
|
186
|
+
try {
|
|
187
|
+
await this._client.services.services.FunctionRegistryService!.updateRegistration({
|
|
188
|
+
registrationId: this._functionServiceRegistration,
|
|
189
|
+
functions: this.functions.map(({ def: { id, route } }) => ({ id, route })),
|
|
190
|
+
});
|
|
191
|
+
} catch (e) {
|
|
192
|
+
log.catch(e);
|
|
193
|
+
}
|
|
152
194
|
}
|
|
153
195
|
|
|
154
196
|
/**
|
|
155
|
-
* Invoke function
|
|
197
|
+
* Invoke function.
|
|
156
198
|
*/
|
|
157
|
-
|
|
199
|
+
public async invoke(path: string, data: any): Promise<number> {
|
|
158
200
|
const seq = ++this._seq;
|
|
159
201
|
const now = Date.now();
|
|
160
202
|
|
|
161
|
-
log.info('req', { seq,
|
|
162
|
-
const
|
|
203
|
+
log.info('req', { seq, path });
|
|
204
|
+
const statusCode = await this._invoke(path, { data });
|
|
205
|
+
|
|
206
|
+
log.info('res', { seq, path, statusCode, duration: Date.now() - now });
|
|
207
|
+
this.update.emit(statusCode);
|
|
208
|
+
return statusCode;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private async _invoke(path: string, event: FunctionEvent) {
|
|
212
|
+
const { handler } = this._handlers[path] ?? {};
|
|
213
|
+
invariant(handler, `invalid path: ${path}`);
|
|
163
214
|
|
|
164
215
|
const context: FunctionContext = {
|
|
165
216
|
client: this._client,
|
|
@@ -167,7 +218,7 @@ export class DevServer {
|
|
|
167
218
|
};
|
|
168
219
|
|
|
169
220
|
let statusCode = 200;
|
|
170
|
-
const response:
|
|
221
|
+
const response: FunctionResponse = {
|
|
171
222
|
status: (code: number) => {
|
|
172
223
|
statusCode = code;
|
|
173
224
|
return response;
|
|
@@ -175,8 +226,8 @@ export class DevServer {
|
|
|
175
226
|
};
|
|
176
227
|
|
|
177
228
|
await handler({ context, event, response });
|
|
178
|
-
log.info('res', { seq, name, statusCode, duration: Date.now() - now });
|
|
179
|
-
|
|
180
229
|
return statusCode;
|
|
181
230
|
}
|
|
182
231
|
}
|
|
232
|
+
|
|
233
|
+
const createContext = () => new Context({ name: 'DevServer' });
|