@dxos/functions 0.5.3-main.cb47aab → 0.5.3-main.d3c5e1f
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 +280 -299
- 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 +286 -303
- 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/{registry → function}/function-registry.d.ts +4 -4
- package/dist/types/src/function/function-registry.d.ts.map +1 -0
- package/dist/types/src/function/function-registry.test.d.ts.map +1 -0
- package/dist/types/src/function/index.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/runtime/dev-server.d.ts +1 -1
- package/dist/types/src/runtime/dev-server.d.ts.map +1 -1
- package/dist/types/src/runtime/scheduler.d.ts +2 -1
- package/dist/types/src/runtime/scheduler.d.ts.map +1 -1
- package/dist/types/src/trigger/trigger-registry.d.ts.map +1 -1
- package/dist/types/src/trigger/type/subscription-trigger.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +33 -19
- 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 +31 -18
- package/schema/functions.json +18 -9
- package/src/{registry → function}/function-registry.test.ts +10 -10
- package/src/{registry → function}/function-registry.ts +30 -24
- package/src/index.ts +1 -1
- package/src/runtime/dev-server.test.ts +2 -2
- package/src/runtime/dev-server.ts +5 -6
- package/src/runtime/scheduler.test.ts +1 -1
- package/src/runtime/scheduler.ts +16 -8
- package/src/testing/functions-integration.test.ts +1 -1
- package/src/testing/setup.ts +1 -1
- package/src/trigger/trigger-registry.test.ts +60 -34
- package/src/trigger/trigger-registry.ts +18 -5
- package/src/trigger/type/subscription-trigger.ts +17 -10
- package/src/types.ts +12 -10
- package/src/util.test.ts +43 -0
- package/src/util.ts +48 -0
- package/dist/types/src/registry/function-registry.d.ts.map +0 -1
- package/dist/types/src/registry/function-registry.test.d.ts.map +0 -1
- package/dist/types/src/registry/index.d.ts.map +0 -1
- /package/dist/types/src/{registry → function}/function-registry.test.d.ts +0 -0
- /package/dist/types/src/{registry → function}/index.d.ts +0 -0
- /package/src/{registry → function}/index.ts +0 -0
|
@@ -62,9 +62,7 @@ export declare class FunctionDef extends FunctionDef_base {
|
|
|
62
62
|
}
|
|
63
63
|
declare const FunctionTrigger_base: import("@dxos/echo-schema").EchoSchemaClass<{
|
|
64
64
|
function: string;
|
|
65
|
-
meta?:
|
|
66
|
-
readonly [x: string]: any;
|
|
67
|
-
} | undefined;
|
|
65
|
+
meta?: object | undefined;
|
|
68
66
|
spec: {
|
|
69
67
|
readonly filter: readonly {
|
|
70
68
|
readonly type: string;
|
|
@@ -100,26 +98,34 @@ export declare class FunctionTrigger extends FunctionTrigger_base {
|
|
|
100
98
|
* Function manifest file.
|
|
101
99
|
*/
|
|
102
100
|
export declare const FunctionManifestSchema: S.struct<{
|
|
103
|
-
functions: S.PropertySignature<"?:",
|
|
101
|
+
functions: S.PropertySignature<"?:", ({
|
|
104
102
|
handler: string;
|
|
105
103
|
uri: string;
|
|
106
104
|
description?: string | undefined;
|
|
107
105
|
route: string;
|
|
108
106
|
} & {
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
"@meta"?: {
|
|
108
|
+
readonly keys: {
|
|
109
|
+
readonly id: string;
|
|
110
|
+
readonly source: string;
|
|
111
|
+
}[];
|
|
112
|
+
} | undefined;
|
|
113
|
+
})[] | undefined, never, "?:", ({
|
|
111
114
|
handler: string;
|
|
112
115
|
uri: string;
|
|
113
116
|
description?: string | undefined;
|
|
114
117
|
route: string;
|
|
115
118
|
} & {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
readonly [x: string]: any;
|
|
119
|
+
"@meta"?: {
|
|
120
|
+
readonly keys: {
|
|
121
|
+
readonly id: string;
|
|
122
|
+
readonly source: string;
|
|
123
|
+
}[];
|
|
122
124
|
} | undefined;
|
|
125
|
+
})[] | undefined, never>;
|
|
126
|
+
triggers: S.PropertySignature<"?:", ({
|
|
127
|
+
function: string;
|
|
128
|
+
meta?: object | undefined;
|
|
123
129
|
spec: {
|
|
124
130
|
readonly filter: readonly {
|
|
125
131
|
readonly type: string;
|
|
@@ -147,12 +153,15 @@ export declare const FunctionManifestSchema: S.struct<{
|
|
|
147
153
|
} | undefined;
|
|
148
154
|
};
|
|
149
155
|
} & {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
156
|
+
"@meta"?: {
|
|
157
|
+
readonly keys: {
|
|
158
|
+
readonly id: string;
|
|
159
|
+
readonly source: string;
|
|
160
|
+
}[];
|
|
155
161
|
} | undefined;
|
|
162
|
+
})[] | undefined, never, "?:", ({
|
|
163
|
+
function: string;
|
|
164
|
+
meta?: object | undefined;
|
|
156
165
|
spec: {
|
|
157
166
|
readonly filter: readonly {
|
|
158
167
|
readonly type: string;
|
|
@@ -180,8 +189,13 @@ export declare const FunctionManifestSchema: S.struct<{
|
|
|
180
189
|
} | undefined;
|
|
181
190
|
};
|
|
182
191
|
} & {
|
|
183
|
-
|
|
184
|
-
|
|
192
|
+
"@meta"?: {
|
|
193
|
+
readonly keys: {
|
|
194
|
+
readonly id: string;
|
|
195
|
+
readonly source: string;
|
|
196
|
+
}[];
|
|
197
|
+
} | undefined;
|
|
198
|
+
})[] | undefined, never>;
|
|
185
199
|
}>;
|
|
186
200
|
export type FunctionManifest = S.Schema.Type<typeof FunctionManifestSchema>;
|
|
187
201
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAIA,OAAO,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAIA,OAAO,EAAa,CAAC,EAAe,MAAM,mBAAmB,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG,cAAc,GAAG,OAAO,GAAG,SAAS,GAAG,WAAW,CAAC;AAErF,QAAA,MAAM,yBAAyB;;;;;;;;;;;;;;;;;EAiB7B,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAElF,QAAA,MAAM,kBAAkB;;;EAGtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE,QAAA,MAAM,oBAAoB;;;;GAOzB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE,QAAA,MAAM,sBAAsB;;;;;;;;EAI1B,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAS5E,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,cAAc,GAAG,gBAAgB,GAAG,mBAAmB,CAAC;;;;;;;;;AAEjG;;GAEG;AACH,qBAAa,WAAY,SAAQ,gBAS/B;CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEL,qBAAa,eAAgB,SAAQ,oBAQnC;CAAG;AAEL;;GAEG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGjC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type Comparator<A, B = A> = (a: A, b: B) => boolean;
|
|
2
|
+
export type DiffResult<A, B = A> = {
|
|
3
|
+
added: B[];
|
|
4
|
+
updated: A[];
|
|
5
|
+
removed: A[];
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* @param previous
|
|
10
|
+
* @param next
|
|
11
|
+
* @param comparator
|
|
12
|
+
*/
|
|
13
|
+
export declare const diff: <A, B = A>(previous: readonly A[], next: readonly B[], comparator: Comparator<A, B>) => DiffResult<A, B>;
|
|
14
|
+
export declare const intersection: <A, B = A>(a: A[], b: B[], comparator: Comparator<A, B>) => A[];
|
|
15
|
+
//# sourceMappingURL=util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../src/util.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,UAAU,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;AAE3D,MAAM,MAAM,UAAU,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;IACjC,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,OAAO,EAAE,CAAC,EAAE,CAAC;IACb,OAAO,EAAE,CAAC,EAAE,CAAC;CACd,CAAC;AAEF;;;;;GAKG;AAEH,eAAO,MAAM,IAAI,0GAwBhB,CAAC;AAGF,eAAO,MAAM,YAAY,iEACuC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.test.d.ts","sourceRoot":"","sources":["../../../src/util.test.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/functions",
|
|
3
|
-
"version": "0.5.3-main.
|
|
4
|
-
"description": "Functions
|
|
3
|
+
"version": "0.5.3-main.d3c5e1f",
|
|
4
|
+
"description": "Functions API and runtime.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
7
|
"license": "MIT",
|
|
@@ -10,10 +10,24 @@
|
|
|
10
10
|
".": {
|
|
11
11
|
"browser": "./dist/lib/browser/index.mjs",
|
|
12
12
|
"node": "./dist/lib/node/index.cjs",
|
|
13
|
-
"default": "./dist/lib/node/index.cjs"
|
|
13
|
+
"default": "./dist/lib/node/index.cjs",
|
|
14
|
+
"types": "./dist/types/src/index.d.ts"
|
|
15
|
+
},
|
|
16
|
+
"./types": {
|
|
17
|
+
"browser": "./dist/lib/browser/types.mjs",
|
|
18
|
+
"node": "./dist/lib/node/types.cjs",
|
|
19
|
+
"default": "./dist/lib/node/types.cjs",
|
|
20
|
+
"types": "./dist/types/src/types.d.ts"
|
|
14
21
|
}
|
|
15
22
|
},
|
|
16
23
|
"types": "dist/types/src/index.d.ts",
|
|
24
|
+
"typesVersions": {
|
|
25
|
+
"*": {
|
|
26
|
+
"types": [
|
|
27
|
+
"dist/types/src/types.d.ts"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
},
|
|
17
31
|
"files": [
|
|
18
32
|
"dist",
|
|
19
33
|
"schema",
|
|
@@ -26,29 +40,28 @@
|
|
|
26
40
|
"express": "^4.19.2",
|
|
27
41
|
"get-port-please": "^3.1.1",
|
|
28
42
|
"ws": "^8.14.2",
|
|
29
|
-
"@braneframe/types": "0.5.3-main.
|
|
30
|
-
"@dxos/async": "0.5.3-main.
|
|
31
|
-
"@dxos/client": "0.5.3-main.
|
|
32
|
-
"@dxos/context": "0.5.3-main.
|
|
33
|
-
"@dxos/echo-db": "0.5.3-main.
|
|
34
|
-
"@dxos/
|
|
35
|
-
"@dxos/
|
|
36
|
-
"@dxos/
|
|
37
|
-
"@dxos/
|
|
38
|
-
"@dxos/
|
|
39
|
-
"@dxos/
|
|
40
|
-
"@dxos/util": "0.5.3-main.
|
|
43
|
+
"@braneframe/types": "0.5.3-main.d3c5e1f",
|
|
44
|
+
"@dxos/async": "0.5.3-main.d3c5e1f",
|
|
45
|
+
"@dxos/client": "0.5.3-main.d3c5e1f",
|
|
46
|
+
"@dxos/context": "0.5.3-main.d3c5e1f",
|
|
47
|
+
"@dxos/echo-db": "0.5.3-main.d3c5e1f",
|
|
48
|
+
"@dxos/invariant": "0.5.3-main.d3c5e1f",
|
|
49
|
+
"@dxos/keys": "0.5.3-main.d3c5e1f",
|
|
50
|
+
"@dxos/echo-schema": "0.5.3-main.d3c5e1f",
|
|
51
|
+
"@dxos/protocols": "0.5.3-main.d3c5e1f",
|
|
52
|
+
"@dxos/log": "0.5.3-main.d3c5e1f",
|
|
53
|
+
"@dxos/node-std": "0.5.3-main.d3c5e1f",
|
|
54
|
+
"@dxos/util": "0.5.3-main.d3c5e1f"
|
|
41
55
|
},
|
|
42
56
|
"devDependencies": {
|
|
43
57
|
"@types/express": "^4.17.17",
|
|
44
58
|
"@types/ws": "^7.4.0",
|
|
45
|
-
"@dxos/agent": "0.5.3-main.
|
|
59
|
+
"@dxos/agent": "0.5.3-main.d3c5e1f"
|
|
46
60
|
},
|
|
47
61
|
"publishConfig": {
|
|
48
62
|
"access": "public"
|
|
49
63
|
},
|
|
50
64
|
"scripts": {
|
|
51
|
-
"gen-schema": "ts-node ./tools/schema.ts"
|
|
52
|
-
"prebuild": "pnpm gen-schema"
|
|
65
|
+
"gen-schema": "ts-node ./tools/schema.ts"
|
|
53
66
|
}
|
|
54
67
|
}
|
package/schema/functions.json
CHANGED
|
@@ -48,17 +48,11 @@
|
|
|
48
48
|
"properties": {
|
|
49
49
|
"function": {
|
|
50
50
|
"type": "string",
|
|
51
|
-
"description": "Function
|
|
51
|
+
"description": "Function URI.",
|
|
52
52
|
"title": "string"
|
|
53
53
|
},
|
|
54
54
|
"meta": {
|
|
55
|
-
"
|
|
56
|
-
"required": [],
|
|
57
|
-
"properties": {},
|
|
58
|
-
"additionalProperties": {
|
|
59
|
-
"$id": "/schemas/any",
|
|
60
|
-
"title": "any"
|
|
61
|
-
}
|
|
55
|
+
"$ref": "#/$defs/object"
|
|
62
56
|
},
|
|
63
57
|
"spec": {
|
|
64
58
|
"anyOf": [
|
|
@@ -193,5 +187,20 @@
|
|
|
193
187
|
}
|
|
194
188
|
}
|
|
195
189
|
},
|
|
196
|
-
"additionalProperties": false
|
|
190
|
+
"additionalProperties": false,
|
|
191
|
+
"$defs": {
|
|
192
|
+
"object": {
|
|
193
|
+
"$id": "/schemas/object",
|
|
194
|
+
"oneOf": [
|
|
195
|
+
{
|
|
196
|
+
"type": "object"
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"type": "array"
|
|
200
|
+
}
|
|
201
|
+
],
|
|
202
|
+
"description": "an object in the TypeScript meaning, i.e. the `object` type",
|
|
203
|
+
"title": "object"
|
|
204
|
+
}
|
|
205
|
+
}
|
|
197
206
|
}
|
|
@@ -44,7 +44,7 @@ describe('function registry', () => {
|
|
|
44
44
|
const client = (await createInitializedClients(testBuilder))[0];
|
|
45
45
|
const registry = createRegistry(client);
|
|
46
46
|
const space = await client.spaces.create();
|
|
47
|
-
await registry.register(space, testManifest);
|
|
47
|
+
await registry.register(space, testManifest.functions);
|
|
48
48
|
const { objects: definitions } = await space.db.query(Filter.schema(FunctionDef)).run();
|
|
49
49
|
expect(definitions.length).to.eq(1);
|
|
50
50
|
expect(definitions[0].uri).to.eq(testManifest.functions?.[0]?.uri);
|
|
@@ -54,8 +54,8 @@ describe('function registry', () => {
|
|
|
54
54
|
const client = (await createInitializedClients(testBuilder))[0];
|
|
55
55
|
const registry = createRegistry(client);
|
|
56
56
|
const space = await client.spaces.create();
|
|
57
|
-
const existing = space.db.add(create(FunctionDef,
|
|
58
|
-
await registry.register(space, testManifest);
|
|
57
|
+
const existing = space.db.add(create(FunctionDef, testManifest.functions![0]));
|
|
58
|
+
await registry.register(space, testManifest.functions);
|
|
59
59
|
const { objects: definitions } = await space.db.query(Filter.schema(FunctionDef)).run();
|
|
60
60
|
expect(definitions.length).to.eq(1);
|
|
61
61
|
expect(definitions[0].uri).to.eq(existing.uri);
|
|
@@ -67,12 +67,12 @@ describe('function registry', () => {
|
|
|
67
67
|
const client = (await createInitializedClients(testBuilder))[0];
|
|
68
68
|
const registry = createRegistry(client);
|
|
69
69
|
const space = await client.spaces.create();
|
|
70
|
-
const definitions = range(3, () => create(FunctionDef,
|
|
70
|
+
const definitions = range(3, () => create(FunctionDef, testManifest.functions![0]));
|
|
71
71
|
definitions.forEach((def) => space.db.add(def));
|
|
72
72
|
|
|
73
73
|
const functionRegistered = new Trigger<FunctionDef[]>();
|
|
74
|
-
registry.
|
|
75
|
-
functionRegistered.wake(fn.
|
|
74
|
+
registry.registered.on((fn) => {
|
|
75
|
+
functionRegistered.wake(fn.added);
|
|
76
76
|
});
|
|
77
77
|
void registry.open(ctx);
|
|
78
78
|
const functions = await functionRegistered.wait();
|
|
@@ -86,12 +86,12 @@ describe('function registry', () => {
|
|
|
86
86
|
const space = await client.spaces.create();
|
|
87
87
|
|
|
88
88
|
const functionRegistered = new Trigger<FunctionDef>();
|
|
89
|
-
registry.
|
|
90
|
-
expect(fn.
|
|
91
|
-
functionRegistered.wake(fn.
|
|
89
|
+
registry.registered.on((fn) => {
|
|
90
|
+
expect(fn.added.length).to.eq(1);
|
|
91
|
+
functionRegistered.wake(fn.added[0]);
|
|
92
92
|
});
|
|
93
93
|
await registry.open(ctx);
|
|
94
|
-
await registry.register(space, testManifest);
|
|
94
|
+
await registry.register(space, testManifest.functions);
|
|
95
95
|
const registered = await functionRegistered.wait();
|
|
96
96
|
expect(registered.uri).to.eq(testManifest.functions![0].uri);
|
|
97
97
|
});
|
|
@@ -7,19 +7,21 @@ import { type Client } from '@dxos/client';
|
|
|
7
7
|
import { create, Filter, type Space } from '@dxos/client/echo';
|
|
8
8
|
import { type Context, Resource } from '@dxos/context';
|
|
9
9
|
import { PublicKey } from '@dxos/keys';
|
|
10
|
+
import { log } from '@dxos/log';
|
|
10
11
|
import { ComplexMap } from '@dxos/util';
|
|
11
12
|
|
|
12
13
|
import { FunctionDef, type FunctionManifest } from '../types';
|
|
14
|
+
import { diff } from '../util';
|
|
13
15
|
|
|
14
16
|
export type FunctionsRegisteredEvent = {
|
|
15
17
|
space: Space;
|
|
16
|
-
|
|
18
|
+
added: FunctionDef[];
|
|
17
19
|
};
|
|
18
20
|
|
|
19
21
|
export class FunctionRegistry extends Resource {
|
|
20
22
|
private readonly _functionBySpaceKey = new ComplexMap<PublicKey, FunctionDef[]>(PublicKey.hash);
|
|
21
23
|
|
|
22
|
-
public readonly
|
|
24
|
+
public readonly registered = new Event<FunctionsRegisteredEvent>();
|
|
23
25
|
|
|
24
26
|
constructor(private readonly _client: Client) {
|
|
25
27
|
super();
|
|
@@ -30,30 +32,33 @@ export class FunctionRegistry extends Resource {
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
/**
|
|
33
|
-
*
|
|
35
|
+
* Loads function definitions from the manifest into the space.
|
|
34
36
|
* We first load all the definitions from the space to deduplicate by functionId.
|
|
35
37
|
*/
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (!
|
|
38
|
+
public async register(space: Space, functions: FunctionManifest['functions']): Promise<void> {
|
|
39
|
+
log('register', { space: space.key, functions: functions?.length ?? 0 });
|
|
40
|
+
if (!functions?.length) {
|
|
39
41
|
return;
|
|
40
42
|
}
|
|
41
43
|
if (!space.db.graph.runtimeSchemaRegistry.hasSchema(FunctionDef)) {
|
|
42
44
|
space.db.graph.runtimeSchemaRegistry.registerSchema(FunctionDef);
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
|
|
47
|
+
// Sync definitions.
|
|
48
|
+
const { objects: existing } = await space.db.query(Filter.schema(FunctionDef)).run();
|
|
49
|
+
const { added, removed } = diff(existing, functions, (a, b) => a.uri === b.uri);
|
|
50
|
+
added.forEach((def) => space.db.add(create(FunctionDef, def)));
|
|
51
|
+
// TODO(burdon): Update existing templates.
|
|
52
|
+
removed.forEach((def) => space.db.remove(def));
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
protected override async _open(): Promise<void> {
|
|
52
|
-
const
|
|
56
|
+
const spacesSubscription = this._client.spaces.subscribe(async (spaces) => {
|
|
53
57
|
for (const space of spaces) {
|
|
54
58
|
if (this._functionBySpaceKey.has(space.key)) {
|
|
55
59
|
continue;
|
|
56
60
|
}
|
|
61
|
+
|
|
57
62
|
const registered: FunctionDef[] = [];
|
|
58
63
|
this._functionBySpaceKey.set(space.key, registered);
|
|
59
64
|
await space.waitUntilReady();
|
|
@@ -61,24 +66,25 @@ export class FunctionRegistry extends Resource {
|
|
|
61
66
|
break;
|
|
62
67
|
}
|
|
63
68
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
registered
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
// Subscribe to updates.
|
|
70
|
+
this._ctx.onDispose(
|
|
71
|
+
space.db.query(Filter.schema(FunctionDef)).subscribe(({ objects }) => {
|
|
72
|
+
const { added } = diff(registered, objects, (a, b) => a.uri === b.uri);
|
|
73
|
+
// TODO(burdon): Update and remove.
|
|
74
|
+
if (added.length > 0) {
|
|
75
|
+
registered.push(...added);
|
|
76
|
+
this.registered.emit({ space, added });
|
|
77
|
+
}
|
|
78
|
+
}),
|
|
79
|
+
);
|
|
72
80
|
}
|
|
73
81
|
});
|
|
74
|
-
|
|
82
|
+
|
|
83
|
+
// TODO(burdon): API: Normalize unsubscribe methods.
|
|
84
|
+
this._ctx.onDispose(() => spacesSubscription.unsubscribe());
|
|
75
85
|
}
|
|
76
86
|
|
|
77
87
|
protected override async _close(_: Context): Promise<void> {
|
|
78
88
|
this._functionBySpaceKey.clear();
|
|
79
89
|
}
|
|
80
90
|
}
|
|
81
|
-
|
|
82
|
-
const getNewDefinitions = <T extends { uri: string }>(candidateList: T[], existing: FunctionDef[]): T[] => {
|
|
83
|
-
return candidateList.filter((candidate) => existing.find((def) => def.uri === candidate.uri) == null);
|
|
84
|
-
};
|
package/src/index.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { TestBuilder } from '@dxos/client/testing';
|
|
|
11
11
|
import { describe, test } from '@dxos/test';
|
|
12
12
|
|
|
13
13
|
import { DevServer } from './dev-server';
|
|
14
|
-
import { FunctionRegistry } from '../
|
|
14
|
+
import { FunctionRegistry } from '../function';
|
|
15
15
|
import { createFunctionRuntime } from '../testing';
|
|
16
16
|
import { type FunctionManifest } from '../types';
|
|
17
17
|
|
|
@@ -44,7 +44,7 @@ describe('dev server', () => {
|
|
|
44
44
|
baseDir: path.join(__dirname, '../testing'),
|
|
45
45
|
});
|
|
46
46
|
const space = await client.spaces.create();
|
|
47
|
-
await registry.register(space, manifest);
|
|
47
|
+
await registry.register(space, manifest.functions);
|
|
48
48
|
await server.start();
|
|
49
49
|
|
|
50
50
|
// TODO(burdon): Doesn't shut down cleanly.
|
|
@@ -13,8 +13,8 @@ import { Context } from '@dxos/context';
|
|
|
13
13
|
import { invariant } from '@dxos/invariant';
|
|
14
14
|
import { log } from '@dxos/log';
|
|
15
15
|
|
|
16
|
+
import { type FunctionRegistry } from '../function';
|
|
16
17
|
import { type FunctionContext, type FunctionEvent, type FunctionHandler, type FunctionResponse } from '../handler';
|
|
17
|
-
import { type FunctionRegistry } from '../registry';
|
|
18
18
|
import { type FunctionDef } from '../types';
|
|
19
19
|
|
|
20
20
|
export type DevServerOptions = {
|
|
@@ -41,16 +41,15 @@ export class DevServer {
|
|
|
41
41
|
|
|
42
42
|
public readonly update = new Event<number>();
|
|
43
43
|
|
|
44
|
-
// prettier-ignore
|
|
45
44
|
constructor(
|
|
46
45
|
private readonly _client: Client,
|
|
47
46
|
private readonly _functionsRegistry: FunctionRegistry,
|
|
48
47
|
private readonly _options: DevServerOptions,
|
|
49
48
|
) {
|
|
50
|
-
this._functionsRegistry.
|
|
51
|
-
|
|
49
|
+
this._functionsRegistry.registered.on(async ({ added }) => {
|
|
50
|
+
added.forEach((def) => this._load(def));
|
|
52
51
|
await this._safeUpdateRegistration();
|
|
53
|
-
log('new functions loaded', {
|
|
52
|
+
log('new functions loaded', { added });
|
|
54
53
|
});
|
|
55
54
|
}
|
|
56
55
|
|
|
@@ -158,7 +157,7 @@ export class DevServer {
|
|
|
158
157
|
/**
|
|
159
158
|
* Load function.
|
|
160
159
|
*/
|
|
161
|
-
private async _load(def: FunctionDef, force
|
|
160
|
+
private async _load(def: FunctionDef, force?: boolean | undefined) {
|
|
162
161
|
const { uri, route, handler } = def;
|
|
163
162
|
const filePath = join(this._options.baseDir, handler);
|
|
164
163
|
log.info('loading', { uri, force });
|
|
@@ -12,7 +12,7 @@ import { create } from '@dxos/echo-schema';
|
|
|
12
12
|
import { describe, test } from '@dxos/test';
|
|
13
13
|
|
|
14
14
|
import { Scheduler, type SchedulerOptions } from './scheduler';
|
|
15
|
-
import { FunctionRegistry } from '../
|
|
15
|
+
import { FunctionRegistry } from '../function';
|
|
16
16
|
import { createInitializedClients, TestType, triggerWebhook } from '../testing';
|
|
17
17
|
import { TriggerRegistry } from '../trigger';
|
|
18
18
|
import { type FunctionManifest } from '../types';
|
package/src/runtime/scheduler.ts
CHANGED
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
|
|
7
|
+
import { Mutex } from '@dxos/async';
|
|
7
8
|
import { type Space } from '@dxos/client/echo';
|
|
8
9
|
import { Context } from '@dxos/context';
|
|
9
10
|
import { log } from '@dxos/log';
|
|
10
11
|
|
|
12
|
+
import { type FunctionRegistry } from '../function';
|
|
11
13
|
import { type FunctionEventMeta } from '../handler';
|
|
12
|
-
import { type FunctionRegistry } from '../registry';
|
|
13
14
|
import { type TriggerRegistry } from '../trigger';
|
|
14
15
|
import { type FunctionDef, type FunctionManifest, type FunctionTrigger } from '../types';
|
|
15
16
|
|
|
@@ -26,13 +27,15 @@ export type SchedulerOptions = {
|
|
|
26
27
|
export class Scheduler {
|
|
27
28
|
private _ctx = createContext();
|
|
28
29
|
|
|
30
|
+
private readonly _callMutex = new Mutex();
|
|
31
|
+
|
|
29
32
|
constructor(
|
|
30
33
|
public readonly functions: FunctionRegistry,
|
|
31
34
|
public readonly triggers: TriggerRegistry,
|
|
32
35
|
private readonly _options: SchedulerOptions = {},
|
|
33
36
|
) {
|
|
34
|
-
this.functions.
|
|
35
|
-
await this._safeActivateTriggers(space, this.triggers.getInactiveTriggers(space),
|
|
37
|
+
this.functions.registered.on(async ({ space, added }) => {
|
|
38
|
+
await this._safeActivateTriggers(space, this.triggers.getInactiveTriggers(space), added);
|
|
36
39
|
});
|
|
37
40
|
this.triggers.registered.on(async ({ space, triggers }) => {
|
|
38
41
|
await this._safeActivateTriggers(space, triggers, this.functions.getFunctions(space));
|
|
@@ -52,8 +55,9 @@ export class Scheduler {
|
|
|
52
55
|
await this.triggers.close();
|
|
53
56
|
}
|
|
54
57
|
|
|
58
|
+
// TODO(burdon): Remove and update registries directly.
|
|
55
59
|
public async register(space: Space, manifest: FunctionManifest) {
|
|
56
|
-
await this.functions.register(space, manifest);
|
|
60
|
+
await this.functions.register(space, manifest.functions);
|
|
57
61
|
await this.triggers.register(space, manifest);
|
|
58
62
|
}
|
|
59
63
|
|
|
@@ -76,16 +80,20 @@ export class Scheduler {
|
|
|
76
80
|
}
|
|
77
81
|
|
|
78
82
|
await this.triggers.activate({ space }, fnTrigger, async (args) => {
|
|
79
|
-
return this.
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
return this._callMutex.executeSynchronized(() => {
|
|
84
|
+
return this._execFunction(definition, fnTrigger, {
|
|
85
|
+
meta: fnTrigger.meta,
|
|
86
|
+
data: { ...args, spaceKey: space.key },
|
|
87
|
+
});
|
|
82
88
|
});
|
|
83
89
|
});
|
|
90
|
+
|
|
84
91
|
log('activated trigger', { space: space.key, trigger: fnTrigger });
|
|
85
92
|
}
|
|
86
93
|
|
|
87
94
|
private async _execFunction<TData, TMeta>(
|
|
88
95
|
def: FunctionDef,
|
|
96
|
+
trigger: FunctionTrigger,
|
|
89
97
|
{ data, meta }: { data: TData; meta?: TMeta },
|
|
90
98
|
): Promise<number> {
|
|
91
99
|
let status = 0;
|
|
@@ -97,7 +105,7 @@ export class Scheduler {
|
|
|
97
105
|
if (endpoint) {
|
|
98
106
|
// TODO(burdon): Move out of scheduler (generalize as callback).
|
|
99
107
|
const url = path.join(endpoint, def.route);
|
|
100
|
-
log.info('exec', { function: def.uri, url });
|
|
108
|
+
log.info('exec', { function: def.uri, url, triggerType: trigger.spec.type });
|
|
101
109
|
const response = await fetch(url, {
|
|
102
110
|
method: 'POST',
|
|
103
111
|
headers: {
|
|
@@ -13,7 +13,7 @@ import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
|
13
13
|
import { describe, test } from '@dxos/test';
|
|
14
14
|
|
|
15
15
|
import { setTestCallHandler } from './test/handler';
|
|
16
|
-
import { FunctionRegistry } from '../
|
|
16
|
+
import { FunctionRegistry } from '../function';
|
|
17
17
|
import { DevServer, Scheduler } from '../runtime';
|
|
18
18
|
import { createFunctionRuntime, createInitializedClients, TestType } from '../testing';
|
|
19
19
|
import { TriggerRegistry } from '../trigger';
|
package/src/testing/setup.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { range } from '@dxos/util';
|
|
|
10
10
|
import { TestType } from './types';
|
|
11
11
|
import { FunctionDef, FunctionTrigger } from '../types';
|
|
12
12
|
|
|
13
|
-
// TODO(burdon): Create TestBuilder.
|
|
13
|
+
// TODO(burdon): Create new or extend existing TestBuilder.
|
|
14
14
|
|
|
15
15
|
export const createInitializedClients = async (testBuilder: TestBuilder, count: number = 1, config?: Config) => {
|
|
16
16
|
const clients = range(count).map(() => new Client({ config, services: testBuilder.createLocalClientServices() }));
|