@dxos/functions 0.5.3-main.25e4f82 → 0.5.3-main.2ad0afc
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 +692 -493
- 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 +675 -486
- 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/index.d.ts +2 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/runtime/dev-server.d.ts +7 -10
- package/dist/types/src/runtime/dev-server.d.ts.map +1 -1
- package/dist/types/src/runtime/scheduler.d.ts +11 -59
- 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 +1 -0
- package/dist/types/src/testing/test/handler.d.ts.map +1 -1
- 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 +131 -111
- 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 +30 -14
- package/schema/functions.json +139 -116
- 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/index.ts +2 -0
- package/src/runtime/dev-server.test.ts +15 -35
- package/src/runtime/dev-server.ts +37 -20
- package/src/runtime/scheduler.test.ts +54 -75
- package/src/runtime/scheduler.ts +66 -298
- 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 +8 -2
- 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 +58 -42
- package/src/util.test.ts +43 -0
- package/src/util.ts +48 -0
|
@@ -1,44 +1,135 @@
|
|
|
1
1
|
import "@dxos/node-std/globals";
|
|
2
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
-
}) : x)(function(x) {
|
|
5
|
-
if (typeof require !== "undefined")
|
|
6
|
-
return require.apply(this, arguments);
|
|
7
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
// inject-globals:@inject-globals
|
|
11
2
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
3
|
+
FunctionDef,
|
|
4
|
+
FunctionManifestSchema,
|
|
5
|
+
FunctionTrigger,
|
|
6
|
+
__require
|
|
7
|
+
} from "./chunk-366QG6IX.mjs";
|
|
16
8
|
|
|
17
|
-
// packages/core/functions/src/
|
|
18
|
-
import {
|
|
9
|
+
// packages/core/functions/src/function/function-registry.ts
|
|
10
|
+
import { Event } from "@dxos/async";
|
|
11
|
+
import { create, Filter } from "@dxos/client/echo";
|
|
12
|
+
import { Resource } from "@dxos/context";
|
|
13
|
+
import { PublicKey } from "@dxos/keys";
|
|
19
14
|
import { log } from "@dxos/log";
|
|
15
|
+
import { ComplexMap } from "@dxos/util";
|
|
16
|
+
|
|
17
|
+
// packages/core/functions/src/util.ts
|
|
18
|
+
var diff = (previous, next, comparator) => {
|
|
19
|
+
const remaining = [
|
|
20
|
+
...previous
|
|
21
|
+
];
|
|
22
|
+
const result = {
|
|
23
|
+
added: [],
|
|
24
|
+
updated: [],
|
|
25
|
+
removed: remaining
|
|
26
|
+
};
|
|
27
|
+
for (const object of next) {
|
|
28
|
+
const index = remaining.findIndex((item) => comparator(item, object));
|
|
29
|
+
if (index === -1) {
|
|
30
|
+
result.added.push(object);
|
|
31
|
+
} else {
|
|
32
|
+
result.updated.push(remaining[index]);
|
|
33
|
+
remaining.splice(index, 1);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
var intersection = (a, b, comparator) => a.filter((a2) => b.find((b2) => comparator(a2, b2)) !== void 0);
|
|
39
|
+
|
|
40
|
+
// packages/core/functions/src/function/function-registry.ts
|
|
41
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/functions/src/function/function-registry.ts";
|
|
42
|
+
var FunctionRegistry = class extends Resource {
|
|
43
|
+
constructor(_client) {
|
|
44
|
+
super();
|
|
45
|
+
this._client = _client;
|
|
46
|
+
this._functionBySpaceKey = new ComplexMap(PublicKey.hash);
|
|
47
|
+
this.registered = new Event();
|
|
48
|
+
}
|
|
49
|
+
getFunctions(space) {
|
|
50
|
+
return this._functionBySpaceKey.get(space.key) ?? [];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Loads function definitions from the manifest into the space.
|
|
54
|
+
* We first load all the definitions from the space to deduplicate by functionId.
|
|
55
|
+
*/
|
|
56
|
+
async register(space, functions) {
|
|
57
|
+
log("register", {
|
|
58
|
+
space: space.key,
|
|
59
|
+
functions: functions?.length ?? 0
|
|
60
|
+
}, {
|
|
61
|
+
F: __dxlog_file,
|
|
62
|
+
L: 39,
|
|
63
|
+
S: this,
|
|
64
|
+
C: (f, a) => f(...a)
|
|
65
|
+
});
|
|
66
|
+
if (!functions?.length) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!space.db.graph.runtimeSchemaRegistry.hasSchema(FunctionDef)) {
|
|
70
|
+
space.db.graph.runtimeSchemaRegistry.registerSchema(FunctionDef);
|
|
71
|
+
}
|
|
72
|
+
const { objects: existing } = await space.db.query(Filter.schema(FunctionDef)).run();
|
|
73
|
+
const { added, removed } = diff(existing, functions, (a, b) => a.uri === b.uri);
|
|
74
|
+
added.forEach((def) => space.db.add(create(FunctionDef, def)));
|
|
75
|
+
removed.forEach((def) => space.db.remove(def));
|
|
76
|
+
}
|
|
77
|
+
async _open() {
|
|
78
|
+
const spacesSubscription = this._client.spaces.subscribe(async (spaces) => {
|
|
79
|
+
for (const space of spaces) {
|
|
80
|
+
if (this._functionBySpaceKey.has(space.key)) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const registered = [];
|
|
84
|
+
this._functionBySpaceKey.set(space.key, registered);
|
|
85
|
+
await space.waitUntilReady();
|
|
86
|
+
if (this._ctx.disposed) {
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
this._ctx.onDispose(space.db.query(Filter.schema(FunctionDef)).subscribe(({ objects }) => {
|
|
90
|
+
const { added } = diff(registered, objects, (a, b) => a.uri === b.uri);
|
|
91
|
+
if (added.length > 0) {
|
|
92
|
+
registered.push(...added);
|
|
93
|
+
this.registered.emit({
|
|
94
|
+
space,
|
|
95
|
+
added
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
this._ctx.onDispose(() => spacesSubscription.unsubscribe());
|
|
102
|
+
}
|
|
103
|
+
async _close(_) {
|
|
104
|
+
this._functionBySpaceKey.clear();
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// packages/core/functions/src/handler.ts
|
|
109
|
+
import { PublicKey as PublicKey2 } from "@dxos/client";
|
|
110
|
+
import { log as log2 } from "@dxos/log";
|
|
20
111
|
import { nonNullable } from "@dxos/util";
|
|
21
|
-
var
|
|
112
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/functions/src/handler.ts";
|
|
22
113
|
var subscriptionHandler = (handler) => {
|
|
23
114
|
return ({ event: { data }, context, ...rest }) => {
|
|
24
115
|
const { client } = context;
|
|
25
|
-
const space = data.spaceKey ? client.spaces.get(
|
|
116
|
+
const space = data.spaceKey ? client.spaces.get(PublicKey2.from(data.spaceKey)) : void 0;
|
|
26
117
|
const objects = space ? data.objects?.map((id) => space.db.getObjectById(id)).filter(nonNullable) : [];
|
|
27
118
|
if (!!data.spaceKey && !space) {
|
|
28
|
-
|
|
119
|
+
log2.warn("invalid space", {
|
|
29
120
|
data
|
|
30
121
|
}, {
|
|
31
|
-
F:
|
|
122
|
+
F: __dxlog_file2,
|
|
32
123
|
L: 91,
|
|
33
124
|
S: void 0,
|
|
34
125
|
C: (f, a) => f(...a)
|
|
35
126
|
});
|
|
36
127
|
} else {
|
|
37
|
-
|
|
128
|
+
log2.info("handler", {
|
|
38
129
|
space: space?.key.truncate(),
|
|
39
130
|
objects: objects?.length
|
|
40
131
|
}, {
|
|
41
|
-
F:
|
|
132
|
+
F: __dxlog_file2,
|
|
42
133
|
L: 93,
|
|
43
134
|
S: void 0,
|
|
44
135
|
C: (f, a) => f(...a)
|
|
@@ -62,18 +153,32 @@ var subscriptionHandler = (handler) => {
|
|
|
62
153
|
import express from "express";
|
|
63
154
|
import { getPort } from "get-port-please";
|
|
64
155
|
import { join } from "@dxos/node-std/path";
|
|
65
|
-
import { Event, Trigger } from "@dxos/async";
|
|
156
|
+
import { Event as Event2, Trigger } from "@dxos/async";
|
|
157
|
+
import { Context } from "@dxos/context";
|
|
66
158
|
import { invariant } from "@dxos/invariant";
|
|
67
|
-
import { log as
|
|
68
|
-
var
|
|
159
|
+
import { log as log3 } from "@dxos/log";
|
|
160
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/dev-server.ts";
|
|
69
161
|
var DevServer = class {
|
|
70
|
-
|
|
71
|
-
constructor(_client, _options) {
|
|
162
|
+
constructor(_client, _functionsRegistry, _options) {
|
|
72
163
|
this._client = _client;
|
|
164
|
+
this._functionsRegistry = _functionsRegistry;
|
|
73
165
|
this._options = _options;
|
|
166
|
+
this._ctx = createContext();
|
|
74
167
|
this._handlers = {};
|
|
75
168
|
this._seq = 0;
|
|
76
|
-
this.update = new
|
|
169
|
+
this.update = new Event2();
|
|
170
|
+
this._functionsRegistry.registered.on(async ({ added }) => {
|
|
171
|
+
added.forEach((def) => this._load(def));
|
|
172
|
+
await this._safeUpdateRegistration();
|
|
173
|
+
log3("new functions loaded", {
|
|
174
|
+
added
|
|
175
|
+
}, {
|
|
176
|
+
F: __dxlog_file3,
|
|
177
|
+
L: 52,
|
|
178
|
+
S: this,
|
|
179
|
+
C: (f, a) => f(...a)
|
|
180
|
+
});
|
|
181
|
+
});
|
|
77
182
|
}
|
|
78
183
|
get stats() {
|
|
79
184
|
return {
|
|
@@ -82,8 +187,8 @@ var DevServer = class {
|
|
|
82
187
|
}
|
|
83
188
|
get endpoint() {
|
|
84
189
|
invariant(this._port, void 0, {
|
|
85
|
-
F:
|
|
86
|
-
L:
|
|
190
|
+
F: __dxlog_file3,
|
|
191
|
+
L: 63,
|
|
87
192
|
S: this,
|
|
88
193
|
A: [
|
|
89
194
|
"this._port",
|
|
@@ -98,45 +203,32 @@ var DevServer = class {
|
|
|
98
203
|
get functions() {
|
|
99
204
|
return Object.values(this._handlers);
|
|
100
205
|
}
|
|
101
|
-
async initialize() {
|
|
102
|
-
for (const def of this._options.manifest.functions) {
|
|
103
|
-
try {
|
|
104
|
-
await this._load(def);
|
|
105
|
-
} catch (err) {
|
|
106
|
-
log2.error("parsing function (check manifest)", err, {
|
|
107
|
-
F: __dxlog_file2,
|
|
108
|
-
L: 71,
|
|
109
|
-
S: this,
|
|
110
|
-
C: (f, a) => f(...a)
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
206
|
async start() {
|
|
116
207
|
invariant(!this._server, void 0, {
|
|
117
|
-
F:
|
|
118
|
-
L:
|
|
208
|
+
F: __dxlog_file3,
|
|
209
|
+
L: 76,
|
|
119
210
|
S: this,
|
|
120
211
|
A: [
|
|
121
212
|
"!this._server",
|
|
122
213
|
""
|
|
123
214
|
]
|
|
124
215
|
});
|
|
125
|
-
|
|
126
|
-
F:
|
|
127
|
-
L:
|
|
216
|
+
log3.info("starting...", void 0, {
|
|
217
|
+
F: __dxlog_file3,
|
|
218
|
+
L: 77,
|
|
128
219
|
S: this,
|
|
129
220
|
C: (f, a) => f(...a)
|
|
130
221
|
});
|
|
222
|
+
this._ctx = createContext();
|
|
131
223
|
const app = express();
|
|
132
224
|
app.use(express.json());
|
|
133
225
|
app.post("/:path", async (req, res) => {
|
|
134
226
|
const { path: path2 } = req.params;
|
|
135
227
|
try {
|
|
136
|
-
|
|
228
|
+
log3.info("calling", {
|
|
137
229
|
path: path2
|
|
138
230
|
}, {
|
|
139
|
-
F:
|
|
231
|
+
F: __dxlog_file3,
|
|
140
232
|
L: 87,
|
|
141
233
|
S: this,
|
|
142
234
|
C: (f, a) => f(...a)
|
|
@@ -148,8 +240,8 @@ var DevServer = class {
|
|
|
148
240
|
res.statusCode = await this.invoke("/" + path2, req.body);
|
|
149
241
|
res.end();
|
|
150
242
|
} catch (err) {
|
|
151
|
-
|
|
152
|
-
F:
|
|
243
|
+
log3.catch(err, void 0, {
|
|
244
|
+
F: __dxlog_file3,
|
|
153
245
|
L: 97,
|
|
154
246
|
S: this,
|
|
155
247
|
C: (f, a) => f(...a)
|
|
@@ -169,64 +261,61 @@ var DevServer = class {
|
|
|
169
261
|
this._server = app.listen(this._port);
|
|
170
262
|
try {
|
|
171
263
|
const { registrationId, endpoint } = await this._client.services.services.FunctionRegistryService.register({
|
|
172
|
-
endpoint: this.endpoint
|
|
173
|
-
functions: this.functions.map(({ def: { id, path: path2 } }) => ({
|
|
174
|
-
id,
|
|
175
|
-
path: path2
|
|
176
|
-
}))
|
|
264
|
+
endpoint: this.endpoint
|
|
177
265
|
});
|
|
178
|
-
|
|
266
|
+
log3.info("registered", {
|
|
179
267
|
endpoint
|
|
180
268
|
}, {
|
|
181
|
-
F:
|
|
182
|
-
L:
|
|
269
|
+
F: __dxlog_file3,
|
|
270
|
+
L: 112,
|
|
183
271
|
S: this,
|
|
184
272
|
C: (f, a) => f(...a)
|
|
185
273
|
});
|
|
186
274
|
this._proxy = endpoint;
|
|
187
275
|
this._functionServiceRegistration = registrationId;
|
|
276
|
+
await this._functionsRegistry.open(this._ctx);
|
|
188
277
|
} catch (err) {
|
|
189
278
|
await this.stop();
|
|
190
279
|
throw new Error("FunctionRegistryService not available (check plugin is configured).");
|
|
191
280
|
}
|
|
192
|
-
|
|
281
|
+
log3.info("started", {
|
|
193
282
|
port: this._port
|
|
194
283
|
}, {
|
|
195
|
-
F:
|
|
196
|
-
L:
|
|
284
|
+
F: __dxlog_file3,
|
|
285
|
+
L: 123,
|
|
197
286
|
S: this,
|
|
198
287
|
C: (f, a) => f(...a)
|
|
199
288
|
});
|
|
200
289
|
}
|
|
201
290
|
async stop() {
|
|
202
291
|
invariant(this._server, void 0, {
|
|
203
|
-
F:
|
|
204
|
-
L:
|
|
292
|
+
F: __dxlog_file3,
|
|
293
|
+
L: 127,
|
|
205
294
|
S: this,
|
|
206
295
|
A: [
|
|
207
296
|
"this._server",
|
|
208
297
|
""
|
|
209
298
|
]
|
|
210
299
|
});
|
|
211
|
-
|
|
212
|
-
F:
|
|
213
|
-
L:
|
|
300
|
+
log3.info("stopping...", void 0, {
|
|
301
|
+
F: __dxlog_file3,
|
|
302
|
+
L: 128,
|
|
214
303
|
S: this,
|
|
215
304
|
C: (f, a) => f(...a)
|
|
216
305
|
});
|
|
217
306
|
const trigger = new Trigger();
|
|
218
307
|
this._server.close(async () => {
|
|
219
|
-
|
|
220
|
-
F:
|
|
221
|
-
L:
|
|
308
|
+
log3.info("server stopped", void 0, {
|
|
309
|
+
F: __dxlog_file3,
|
|
310
|
+
L: 132,
|
|
222
311
|
S: this,
|
|
223
312
|
C: (f, a) => f(...a)
|
|
224
313
|
});
|
|
225
314
|
try {
|
|
226
315
|
if (this._functionServiceRegistration) {
|
|
227
316
|
invariant(this._client.services.services.FunctionRegistryService, void 0, {
|
|
228
|
-
F:
|
|
229
|
-
L:
|
|
317
|
+
F: __dxlog_file3,
|
|
318
|
+
L: 135,
|
|
230
319
|
S: this,
|
|
231
320
|
A: [
|
|
232
321
|
"this._client.services.services.FunctionRegistryService",
|
|
@@ -236,11 +325,11 @@ var DevServer = class {
|
|
|
236
325
|
await this._client.services.services.FunctionRegistryService.unregister({
|
|
237
326
|
registrationId: this._functionServiceRegistration
|
|
238
327
|
});
|
|
239
|
-
|
|
328
|
+
log3.info("unregistered", {
|
|
240
329
|
registrationId: this._functionServiceRegistration
|
|
241
330
|
}, {
|
|
242
|
-
F:
|
|
243
|
-
L:
|
|
331
|
+
F: __dxlog_file3,
|
|
332
|
+
L: 140,
|
|
244
333
|
S: this,
|
|
245
334
|
C: (f, a) => f(...a)
|
|
246
335
|
});
|
|
@@ -255,9 +344,9 @@ var DevServer = class {
|
|
|
255
344
|
await trigger.wait();
|
|
256
345
|
this._port = void 0;
|
|
257
346
|
this._server = void 0;
|
|
258
|
-
|
|
259
|
-
F:
|
|
260
|
-
L:
|
|
347
|
+
log3.info("stopped", void 0, {
|
|
348
|
+
F: __dxlog_file3,
|
|
349
|
+
L: 154,
|
|
261
350
|
S: this,
|
|
262
351
|
C: (f, a) => f(...a)
|
|
263
352
|
});
|
|
@@ -265,15 +354,15 @@ var DevServer = class {
|
|
|
265
354
|
/**
|
|
266
355
|
* Load function.
|
|
267
356
|
*/
|
|
268
|
-
async _load(def, force
|
|
269
|
-
const {
|
|
357
|
+
async _load(def, force) {
|
|
358
|
+
const { uri, route, handler } = def;
|
|
270
359
|
const filePath = join(this._options.baseDir, handler);
|
|
271
|
-
|
|
272
|
-
|
|
360
|
+
log3.info("loading", {
|
|
361
|
+
uri,
|
|
273
362
|
force
|
|
274
363
|
}, {
|
|
275
|
-
F:
|
|
276
|
-
L:
|
|
364
|
+
F: __dxlog_file3,
|
|
365
|
+
L: 163,
|
|
277
366
|
S: this,
|
|
278
367
|
C: (f, a) => f(...a)
|
|
279
368
|
});
|
|
@@ -284,39 +373,66 @@ var DevServer = class {
|
|
|
284
373
|
}
|
|
285
374
|
const module = __require(filePath);
|
|
286
375
|
if (typeof module.default !== "function") {
|
|
287
|
-
throw new Error(`Handler must export default function: ${
|
|
376
|
+
throw new Error(`Handler must export default function: ${uri}`);
|
|
288
377
|
}
|
|
289
|
-
this._handlers[
|
|
378
|
+
this._handlers[route] = {
|
|
290
379
|
def,
|
|
291
380
|
handler: module.default
|
|
292
381
|
};
|
|
293
382
|
}
|
|
383
|
+
async _safeUpdateRegistration() {
|
|
384
|
+
invariant(this._functionServiceRegistration, void 0, {
|
|
385
|
+
F: __dxlog_file3,
|
|
386
|
+
L: 185,
|
|
387
|
+
S: this,
|
|
388
|
+
A: [
|
|
389
|
+
"this._functionServiceRegistration",
|
|
390
|
+
""
|
|
391
|
+
]
|
|
392
|
+
});
|
|
393
|
+
try {
|
|
394
|
+
await this._client.services.services.FunctionRegistryService.updateRegistration({
|
|
395
|
+
registrationId: this._functionServiceRegistration,
|
|
396
|
+
functions: this.functions.map(({ def: { id, route } }) => ({
|
|
397
|
+
id,
|
|
398
|
+
route
|
|
399
|
+
}))
|
|
400
|
+
});
|
|
401
|
+
} catch (e) {
|
|
402
|
+
log3.catch(e, void 0, {
|
|
403
|
+
F: __dxlog_file3,
|
|
404
|
+
L: 192,
|
|
405
|
+
S: this,
|
|
406
|
+
C: (f, a) => f(...a)
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
}
|
|
294
410
|
/**
|
|
295
411
|
* Invoke function.
|
|
296
412
|
*/
|
|
297
413
|
async invoke(path2, data) {
|
|
298
414
|
const seq = ++this._seq;
|
|
299
415
|
const now = Date.now();
|
|
300
|
-
|
|
416
|
+
log3.info("req", {
|
|
301
417
|
seq,
|
|
302
418
|
path: path2
|
|
303
419
|
}, {
|
|
304
|
-
F:
|
|
305
|
-
L:
|
|
420
|
+
F: __dxlog_file3,
|
|
421
|
+
L: 203,
|
|
306
422
|
S: this,
|
|
307
423
|
C: (f, a) => f(...a)
|
|
308
424
|
});
|
|
309
425
|
const statusCode = await this._invoke(path2, {
|
|
310
426
|
data
|
|
311
427
|
});
|
|
312
|
-
|
|
428
|
+
log3.info("res", {
|
|
313
429
|
seq,
|
|
314
430
|
path: path2,
|
|
315
431
|
statusCode,
|
|
316
432
|
duration: Date.now() - now
|
|
317
433
|
}, {
|
|
318
|
-
F:
|
|
319
|
-
L:
|
|
434
|
+
F: __dxlog_file3,
|
|
435
|
+
L: 206,
|
|
320
436
|
S: this,
|
|
321
437
|
C: (f, a) => f(...a)
|
|
322
438
|
});
|
|
@@ -326,8 +442,8 @@ var DevServer = class {
|
|
|
326
442
|
async _invoke(path2, event) {
|
|
327
443
|
const { handler } = this._handlers[path2] ?? {};
|
|
328
444
|
invariant(handler, `invalid path: ${path2}`, {
|
|
329
|
-
F:
|
|
330
|
-
L:
|
|
445
|
+
F: __dxlog_file3,
|
|
446
|
+
L: 213,
|
|
331
447
|
S: this,
|
|
332
448
|
A: [
|
|
333
449
|
"handler",
|
|
@@ -353,125 +469,104 @@ var DevServer = class {
|
|
|
353
469
|
return statusCode;
|
|
354
470
|
}
|
|
355
471
|
};
|
|
472
|
+
var createContext = () => new Context({
|
|
473
|
+
name: "DevServer"
|
|
474
|
+
});
|
|
356
475
|
|
|
357
476
|
// packages/core/functions/src/runtime/scheduler.ts
|
|
358
|
-
import { CronJob } from "cron";
|
|
359
|
-
import { getPort as getPort2 } from "get-port-please";
|
|
360
|
-
import http from "@dxos/node-std/http";
|
|
361
477
|
import path from "@dxos/node-std/path";
|
|
362
|
-
import
|
|
363
|
-
import {
|
|
364
|
-
import {
|
|
365
|
-
|
|
366
|
-
import { Context } from "@dxos/context";
|
|
367
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
368
|
-
import { log as log3 } from "@dxos/log";
|
|
369
|
-
import { ComplexMap } from "@dxos/util";
|
|
370
|
-
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/scheduler.ts";
|
|
478
|
+
import { Mutex } from "@dxos/async";
|
|
479
|
+
import { Context as Context2 } from "@dxos/context";
|
|
480
|
+
import { log as log4 } from "@dxos/log";
|
|
481
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/scheduler.ts";
|
|
371
482
|
var Scheduler = class {
|
|
372
|
-
constructor(
|
|
373
|
-
this.
|
|
374
|
-
this.
|
|
483
|
+
constructor(functions, triggers, _options = {}) {
|
|
484
|
+
this.functions = functions;
|
|
485
|
+
this.triggers = triggers;
|
|
375
486
|
this._options = _options;
|
|
376
|
-
this.
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
487
|
+
this._ctx = createContext2();
|
|
488
|
+
this._callMutex = new Mutex();
|
|
489
|
+
this.functions.registered.on(async ({ space, added }) => {
|
|
490
|
+
await this._safeActivateTriggers(space, this.triggers.getInactiveTriggers(space), added);
|
|
491
|
+
});
|
|
492
|
+
this.triggers.registered.on(async ({ space, triggers: triggers2 }) => {
|
|
493
|
+
await this._safeActivateTriggers(space, triggers2, this.functions.getFunctions(space));
|
|
494
|
+
});
|
|
383
495
|
}
|
|
384
496
|
async start() {
|
|
385
|
-
this.
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
await this.mount(new Context(), space, trigger);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
});
|
|
497
|
+
await this._ctx.dispose();
|
|
498
|
+
this._ctx = createContext2();
|
|
499
|
+
await this.functions.open(this._ctx);
|
|
500
|
+
await this.triggers.open(this._ctx);
|
|
393
501
|
}
|
|
394
502
|
async stop() {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
503
|
+
await this._ctx.dispose();
|
|
504
|
+
await this.functions.close();
|
|
505
|
+
await this.triggers.close();
|
|
398
506
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const def = this._manifest.functions.find((config) => config.id === trigger.function);
|
|
408
|
-
invariant2(def, `Function not found: ${trigger.function}`, {
|
|
409
|
-
F: __dxlog_file3,
|
|
410
|
-
L: 76,
|
|
411
|
-
S: this,
|
|
412
|
-
A: [
|
|
413
|
-
"def",
|
|
414
|
-
"`Function not found: ${trigger.function}`"
|
|
415
|
-
]
|
|
507
|
+
// TODO(burdon): Remove and update registries directly.
|
|
508
|
+
async register(space, manifest) {
|
|
509
|
+
await this.functions.register(space, manifest.functions);
|
|
510
|
+
await this.triggers.register(space, manifest);
|
|
511
|
+
}
|
|
512
|
+
async _safeActivateTriggers(space, triggers, functions) {
|
|
513
|
+
const mountTasks = triggers.map((trigger) => {
|
|
514
|
+
return this.activate(space, functions, trigger);
|
|
416
515
|
});
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
space: space.key,
|
|
425
|
-
trigger
|
|
516
|
+
await Promise.all(mountTasks).catch(log4.catch);
|
|
517
|
+
}
|
|
518
|
+
async activate(space, functions, fnTrigger) {
|
|
519
|
+
const definition = functions.find((def) => def.uri === fnTrigger.function);
|
|
520
|
+
if (!definition) {
|
|
521
|
+
log4.info("function is not found for trigger", {
|
|
522
|
+
fnTrigger
|
|
426
523
|
}, {
|
|
427
|
-
F:
|
|
428
|
-
L:
|
|
524
|
+
F: __dxlog_file4,
|
|
525
|
+
L: 78,
|
|
429
526
|
S: this,
|
|
430
527
|
C: (f, a) => f(...a)
|
|
431
528
|
});
|
|
432
|
-
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
if (trigger.timer) {
|
|
436
|
-
await this._createTimer(ctx, space, def, trigger);
|
|
437
|
-
}
|
|
438
|
-
if (trigger.webhook) {
|
|
439
|
-
await this._createWebhook(ctx, space, def, trigger);
|
|
440
|
-
}
|
|
441
|
-
if (trigger.websocket) {
|
|
442
|
-
await this._createWebsocket(ctx, space, def, trigger);
|
|
443
|
-
}
|
|
444
|
-
if (trigger.subscription) {
|
|
445
|
-
await this._createSubscription(ctx, space, def, trigger);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
async unmount(id, spaceKey) {
|
|
450
|
-
const key = {
|
|
451
|
-
id,
|
|
452
|
-
spaceKey
|
|
453
|
-
};
|
|
454
|
-
const { ctx } = this._mounts.get(key) ?? {};
|
|
455
|
-
if (ctx) {
|
|
456
|
-
this._mounts.delete(key);
|
|
457
|
-
await ctx.dispose();
|
|
529
|
+
return;
|
|
458
530
|
}
|
|
531
|
+
await this.triggers.activate({
|
|
532
|
+
space
|
|
533
|
+
}, fnTrigger, async (args) => {
|
|
534
|
+
return this._callMutex.executeSynchronized(() => {
|
|
535
|
+
return this._execFunction(definition, fnTrigger, {
|
|
536
|
+
meta: fnTrigger.meta,
|
|
537
|
+
data: {
|
|
538
|
+
...args,
|
|
539
|
+
spaceKey: space.key
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
log4("activated trigger", {
|
|
545
|
+
space: space.key,
|
|
546
|
+
trigger: fnTrigger
|
|
547
|
+
}, {
|
|
548
|
+
F: __dxlog_file4,
|
|
549
|
+
L: 91,
|
|
550
|
+
S: this,
|
|
551
|
+
C: (f, a) => f(...a)
|
|
552
|
+
});
|
|
459
553
|
}
|
|
460
|
-
async _execFunction(def, trigger, data) {
|
|
554
|
+
async _execFunction(def, trigger, { data, meta }) {
|
|
461
555
|
let status = 0;
|
|
462
556
|
try {
|
|
463
|
-
const payload = Object.assign({}, {
|
|
464
|
-
meta
|
|
557
|
+
const payload = Object.assign({}, meta && {
|
|
558
|
+
meta
|
|
465
559
|
}, data);
|
|
466
560
|
const { endpoint, callback } = this._options;
|
|
467
561
|
if (endpoint) {
|
|
468
|
-
const url = path.join(endpoint, def.
|
|
469
|
-
|
|
470
|
-
function: def.
|
|
471
|
-
url
|
|
562
|
+
const url = path.join(endpoint, def.route);
|
|
563
|
+
log4.info("exec", {
|
|
564
|
+
function: def.uri,
|
|
565
|
+
url,
|
|
566
|
+
triggerType: trigger.spec.type
|
|
472
567
|
}, {
|
|
473
|
-
F:
|
|
474
|
-
L:
|
|
568
|
+
F: __dxlog_file4,
|
|
569
|
+
L: 108,
|
|
475
570
|
S: this,
|
|
476
571
|
C: (f, a) => f(...a)
|
|
477
572
|
});
|
|
@@ -484,11 +579,11 @@ var Scheduler = class {
|
|
|
484
579
|
});
|
|
485
580
|
status = response.status;
|
|
486
581
|
} else if (callback) {
|
|
487
|
-
|
|
488
|
-
function: def.
|
|
582
|
+
log4.info("exec", {
|
|
583
|
+
function: def.uri
|
|
489
584
|
}, {
|
|
490
|
-
F:
|
|
491
|
-
L:
|
|
585
|
+
F: __dxlog_file4,
|
|
586
|
+
L: 119,
|
|
492
587
|
S: this,
|
|
493
588
|
C: (f, a) => f(...a)
|
|
494
589
|
});
|
|
@@ -497,22 +592,22 @@ var Scheduler = class {
|
|
|
497
592
|
if (status && status >= 400) {
|
|
498
593
|
throw new Error(`Response: ${status}`);
|
|
499
594
|
}
|
|
500
|
-
|
|
501
|
-
function: def.
|
|
595
|
+
log4.info("done", {
|
|
596
|
+
function: def.uri,
|
|
502
597
|
status
|
|
503
598
|
}, {
|
|
504
|
-
F:
|
|
505
|
-
L:
|
|
599
|
+
F: __dxlog_file4,
|
|
600
|
+
L: 129,
|
|
506
601
|
S: this,
|
|
507
602
|
C: (f, a) => f(...a)
|
|
508
603
|
});
|
|
509
604
|
} catch (err) {
|
|
510
|
-
|
|
511
|
-
function: def.
|
|
605
|
+
log4.error("error", {
|
|
606
|
+
function: def.uri,
|
|
512
607
|
error: err.message
|
|
513
608
|
}, {
|
|
514
|
-
F:
|
|
515
|
-
L:
|
|
609
|
+
F: __dxlog_file4,
|
|
610
|
+
L: 131,
|
|
516
611
|
S: this,
|
|
517
612
|
C: (f, a) => f(...a)
|
|
518
613
|
});
|
|
@@ -520,336 +615,440 @@ var Scheduler = class {
|
|
|
520
615
|
}
|
|
521
616
|
return status;
|
|
522
617
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
618
|
+
};
|
|
619
|
+
var createContext2 = () => new Context2({
|
|
620
|
+
name: "FunctionScheduler"
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
// packages/core/functions/src/trigger/trigger-registry.ts
|
|
624
|
+
import { Event as Event3 } from "@dxos/async";
|
|
625
|
+
import { create as create2, Filter as Filter3, getMeta } from "@dxos/client/echo";
|
|
626
|
+
import { Context as Context3, Resource as Resource2 } from "@dxos/context";
|
|
627
|
+
import { ECHO_ATTR_META, foreignKey, foreignKeyEquals, splitMeta } from "@dxos/echo-schema";
|
|
628
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
629
|
+
import { PublicKey as PublicKey3 } from "@dxos/keys";
|
|
630
|
+
import { log as log9 } from "@dxos/log";
|
|
631
|
+
import { ComplexMap as ComplexMap2 } from "@dxos/util";
|
|
632
|
+
|
|
633
|
+
// packages/core/functions/src/trigger/type/subscription-trigger.ts
|
|
634
|
+
import { TextV0Type } from "@braneframe/types";
|
|
635
|
+
import { debounce, UpdateScheduler } from "@dxos/async";
|
|
636
|
+
import { createSubscription, Filter as Filter2, getAutomergeObjectCore } from "@dxos/echo-db";
|
|
637
|
+
import { log as log5 } from "@dxos/log";
|
|
638
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/functions/src/trigger/type/subscription-trigger.ts";
|
|
639
|
+
var createSubscriptionTrigger = async (ctx, triggerCtx, spec, callback) => {
|
|
640
|
+
const objectIds = /* @__PURE__ */ new Set();
|
|
641
|
+
const task = new UpdateScheduler(ctx, async () => {
|
|
642
|
+
if (objectIds.size > 0) {
|
|
643
|
+
const objects = Array.from(objectIds);
|
|
644
|
+
objectIds.clear();
|
|
645
|
+
await callback({
|
|
646
|
+
objects
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
}, {
|
|
650
|
+
maxFrequency: 4
|
|
651
|
+
});
|
|
652
|
+
const subscriptions = [];
|
|
653
|
+
const subscription = createSubscription(({ added, updated }) => {
|
|
654
|
+
const sizeBefore = objectIds.size;
|
|
655
|
+
for (const object of added) {
|
|
656
|
+
objectIds.add(object.id);
|
|
657
|
+
}
|
|
658
|
+
for (const object of updated) {
|
|
659
|
+
objectIds.add(object.id);
|
|
660
|
+
}
|
|
661
|
+
if (objectIds.size > sizeBefore) {
|
|
662
|
+
log5.info("updated", {
|
|
663
|
+
added: added.length,
|
|
664
|
+
updated: updated.length
|
|
665
|
+
}, {
|
|
666
|
+
F: __dxlog_file5,
|
|
667
|
+
L: 45,
|
|
668
|
+
S: void 0,
|
|
669
|
+
C: (f, a) => f(...a)
|
|
670
|
+
});
|
|
671
|
+
task.trigger();
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
subscriptions.push(() => subscription.unsubscribe());
|
|
675
|
+
const { filter, options: { deep, delay } = {} } = spec;
|
|
676
|
+
const update = ({ objects }) => {
|
|
677
|
+
subscription.update(objects);
|
|
678
|
+
if (deep) {
|
|
679
|
+
log5.info("update", {
|
|
680
|
+
objects: objects.length
|
|
681
|
+
}, {
|
|
682
|
+
F: __dxlog_file5,
|
|
683
|
+
L: 59,
|
|
684
|
+
S: void 0,
|
|
685
|
+
C: (f, a) => f(...a)
|
|
686
|
+
});
|
|
687
|
+
for (const object of objects) {
|
|
688
|
+
const content = object.content;
|
|
689
|
+
if (content instanceof TextV0Type) {
|
|
690
|
+
subscriptions.push(getAutomergeObjectCore(content).updates.on(debounce(() => subscription.update([
|
|
691
|
+
object
|
|
692
|
+
]), 1e3)));
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
const query = triggerCtx.space.db.query(Filter2.or(filter.map(({ type, props }) => Filter2.typename(type, props))));
|
|
698
|
+
subscriptions.push(query.subscribe(delay ? debounce(update, delay) : update));
|
|
699
|
+
ctx.onDispose(() => {
|
|
700
|
+
subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
701
|
+
});
|
|
702
|
+
};
|
|
703
|
+
|
|
704
|
+
// packages/core/functions/src/trigger/type/timer-trigger.ts
|
|
705
|
+
import { CronJob } from "cron";
|
|
706
|
+
import { DeferredTask } from "@dxos/async";
|
|
707
|
+
import { log as log6 } from "@dxos/log";
|
|
708
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/core/functions/src/trigger/type/timer-trigger.ts";
|
|
709
|
+
var createTimerTrigger = async (ctx, triggerContext, spec, callback) => {
|
|
710
|
+
const task = new DeferredTask(ctx, async () => {
|
|
711
|
+
await callback({});
|
|
712
|
+
});
|
|
713
|
+
let last = 0;
|
|
714
|
+
let run = 0;
|
|
715
|
+
const job = CronJob.from({
|
|
716
|
+
cronTime: spec.cron,
|
|
717
|
+
runOnInit: false,
|
|
718
|
+
onTick: () => {
|
|
719
|
+
const now = Date.now();
|
|
720
|
+
const delta = last ? now - last : 0;
|
|
721
|
+
last = now;
|
|
722
|
+
run++;
|
|
723
|
+
log6.info("tick", {
|
|
724
|
+
space: triggerContext.space.key.truncate(),
|
|
725
|
+
count: run,
|
|
726
|
+
delta
|
|
727
|
+
}, {
|
|
728
|
+
F: __dxlog_file6,
|
|
729
|
+
L: 37,
|
|
730
|
+
S: void 0,
|
|
731
|
+
C: (f, a) => f(...a)
|
|
732
|
+
});
|
|
733
|
+
task.schedule();
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
job.start();
|
|
737
|
+
ctx.onDispose(() => job.stop());
|
|
738
|
+
};
|
|
739
|
+
|
|
740
|
+
// packages/core/functions/src/trigger/type/webhook-trigger.ts
|
|
741
|
+
import { getPort as getPort2 } from "get-port-please";
|
|
742
|
+
import http from "@dxos/node-std/http";
|
|
743
|
+
import { log as log7 } from "@dxos/log";
|
|
744
|
+
var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/core/functions/src/trigger/type/webhook-trigger.ts";
|
|
745
|
+
var createWebhookTrigger = async (ctx, _, spec, callback) => {
|
|
746
|
+
const server = http.createServer(async (req, res) => {
|
|
747
|
+
if (req.method !== spec.method) {
|
|
748
|
+
res.statusCode = 405;
|
|
749
|
+
return res.end();
|
|
750
|
+
}
|
|
751
|
+
res.statusCode = await callback({});
|
|
752
|
+
res.end();
|
|
753
|
+
});
|
|
754
|
+
const port = await getPort2({
|
|
755
|
+
random: true
|
|
756
|
+
});
|
|
757
|
+
server.listen(port, () => {
|
|
758
|
+
log7.info("started webhook", {
|
|
759
|
+
port
|
|
533
760
|
}, {
|
|
534
|
-
F:
|
|
535
|
-
L:
|
|
536
|
-
S:
|
|
761
|
+
F: __dxlog_file7,
|
|
762
|
+
L: 40,
|
|
763
|
+
S: void 0,
|
|
537
764
|
C: (f, a) => f(...a)
|
|
538
765
|
});
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
766
|
+
spec.port = port;
|
|
767
|
+
});
|
|
768
|
+
ctx.onDispose(() => {
|
|
769
|
+
server.close();
|
|
770
|
+
});
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
// packages/core/functions/src/trigger/type/websocket-trigger.ts
|
|
774
|
+
import WebSocket from "ws";
|
|
775
|
+
import { sleep, Trigger as Trigger2 } from "@dxos/async";
|
|
776
|
+
import { log as log8 } from "@dxos/log";
|
|
777
|
+
var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/core/functions/src/trigger/type/websocket-trigger.ts";
|
|
778
|
+
var createWebsocketTrigger = async (ctx, triggerCtx, spec, callback, options = {
|
|
779
|
+
retryDelay: 2,
|
|
780
|
+
maxAttempts: 5
|
|
781
|
+
}) => {
|
|
782
|
+
const { url, init } = spec;
|
|
783
|
+
let ws;
|
|
784
|
+
for (let attempt = 1; attempt <= options.maxAttempts; attempt++) {
|
|
785
|
+
const open = new Trigger2();
|
|
786
|
+
ws = new WebSocket(url);
|
|
787
|
+
Object.assign(ws, {
|
|
788
|
+
onopen: () => {
|
|
789
|
+
log8.info("opened", {
|
|
790
|
+
url
|
|
559
791
|
}, {
|
|
560
|
-
F:
|
|
561
|
-
L:
|
|
562
|
-
S:
|
|
792
|
+
F: __dxlog_file8,
|
|
793
|
+
L: 39,
|
|
794
|
+
S: void 0,
|
|
795
|
+
C: (f, a) => f(...a)
|
|
796
|
+
});
|
|
797
|
+
if (spec.init) {
|
|
798
|
+
ws.send(new TextEncoder().encode(JSON.stringify(init)));
|
|
799
|
+
}
|
|
800
|
+
open.wake(true);
|
|
801
|
+
},
|
|
802
|
+
onclose: (event) => {
|
|
803
|
+
log8.info("closed", {
|
|
804
|
+
url,
|
|
805
|
+
code: event.code
|
|
806
|
+
}, {
|
|
807
|
+
F: __dxlog_file8,
|
|
808
|
+
L: 48,
|
|
809
|
+
S: void 0,
|
|
810
|
+
C: (f, a) => f(...a)
|
|
811
|
+
});
|
|
812
|
+
if (event.code === 1006) {
|
|
813
|
+
setTimeout(async () => {
|
|
814
|
+
log8.info(`reconnecting in ${options.retryDelay}s...`, {
|
|
815
|
+
url
|
|
816
|
+
}, {
|
|
817
|
+
F: __dxlog_file8,
|
|
818
|
+
L: 53,
|
|
819
|
+
S: void 0,
|
|
820
|
+
C: (f, a) => f(...a)
|
|
821
|
+
});
|
|
822
|
+
await createWebsocketTrigger(ctx, triggerCtx, spec, callback, options);
|
|
823
|
+
}, options.retryDelay * 1e3);
|
|
824
|
+
}
|
|
825
|
+
open.wake(false);
|
|
826
|
+
},
|
|
827
|
+
onerror: (event) => {
|
|
828
|
+
log8.catch(event.error, {
|
|
829
|
+
url
|
|
830
|
+
}, {
|
|
831
|
+
F: __dxlog_file8,
|
|
832
|
+
L: 62,
|
|
833
|
+
S: void 0,
|
|
563
834
|
C: (f, a) => f(...a)
|
|
564
835
|
});
|
|
565
|
-
|
|
836
|
+
},
|
|
837
|
+
onmessage: async (event) => {
|
|
838
|
+
try {
|
|
839
|
+
log8.info("message", void 0, {
|
|
840
|
+
F: __dxlog_file8,
|
|
841
|
+
L: 67,
|
|
842
|
+
S: void 0,
|
|
843
|
+
C: (f, a) => f(...a)
|
|
844
|
+
});
|
|
845
|
+
const data = JSON.parse(new TextDecoder().decode(event.data));
|
|
846
|
+
await callback({
|
|
847
|
+
data
|
|
848
|
+
});
|
|
849
|
+
} catch (err) {
|
|
850
|
+
log8.catch(err, {
|
|
851
|
+
url
|
|
852
|
+
}, {
|
|
853
|
+
F: __dxlog_file8,
|
|
854
|
+
L: 71,
|
|
855
|
+
S: void 0,
|
|
856
|
+
C: (f, a) => f(...a)
|
|
857
|
+
});
|
|
858
|
+
}
|
|
566
859
|
}
|
|
567
860
|
});
|
|
568
|
-
|
|
569
|
-
|
|
861
|
+
const isOpen = await open.wait();
|
|
862
|
+
if (isOpen) {
|
|
863
|
+
break;
|
|
864
|
+
} else {
|
|
865
|
+
const wait = Math.pow(attempt, 2) * options.retryDelay;
|
|
866
|
+
if (attempt < options.maxAttempts) {
|
|
867
|
+
log8.warn(`failed to connect; trying again in ${wait}s`, {
|
|
868
|
+
attempt
|
|
869
|
+
}, {
|
|
870
|
+
F: __dxlog_file8,
|
|
871
|
+
L: 82,
|
|
872
|
+
S: void 0,
|
|
873
|
+
C: (f, a) => f(...a)
|
|
874
|
+
});
|
|
875
|
+
await sleep(wait * 1e3);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
570
878
|
}
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
879
|
+
ctx.onDispose(() => {
|
|
880
|
+
ws?.close();
|
|
881
|
+
});
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
// packages/core/functions/src/trigger/trigger-registry.ts
|
|
885
|
+
var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/core/functions/src/trigger/trigger-registry.ts";
|
|
886
|
+
var triggerHandlers = {
|
|
887
|
+
subscription: createSubscriptionTrigger,
|
|
888
|
+
timer: createTimerTrigger,
|
|
889
|
+
webhook: createWebhookTrigger,
|
|
890
|
+
websocket: createWebsocketTrigger
|
|
891
|
+
};
|
|
892
|
+
var TriggerRegistry = class extends Resource2 {
|
|
893
|
+
constructor(_client, _options) {
|
|
894
|
+
super();
|
|
895
|
+
this._client = _client;
|
|
896
|
+
this._options = _options;
|
|
897
|
+
this._triggersBySpaceKey = new ComplexMap2(PublicKey3.hash);
|
|
898
|
+
this.registered = new Event3();
|
|
899
|
+
this.removed = new Event3();
|
|
900
|
+
}
|
|
901
|
+
getActiveTriggers(space) {
|
|
902
|
+
return this._getTriggers(space, (t) => t.activationCtx != null);
|
|
903
|
+
}
|
|
904
|
+
getInactiveTriggers(space) {
|
|
905
|
+
return this._getTriggers(space, (t) => t.activationCtx == null);
|
|
906
|
+
}
|
|
907
|
+
async activate(triggerCtx, trigger, callback) {
|
|
908
|
+
log9("activate", {
|
|
909
|
+
space: triggerCtx.space.key,
|
|
577
910
|
trigger
|
|
578
911
|
}, {
|
|
579
|
-
F:
|
|
580
|
-
L:
|
|
912
|
+
F: __dxlog_file9,
|
|
913
|
+
L: 75,
|
|
581
914
|
S: this,
|
|
582
915
|
C: (f, a) => f(...a)
|
|
583
916
|
});
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
if (req.method !== spec.method) {
|
|
587
|
-
res.statusCode = 405;
|
|
588
|
-
return res.end();
|
|
589
|
-
}
|
|
590
|
-
res.statusCode = await this._execFunction(def, trigger, {
|
|
591
|
-
spaceKey: space.key
|
|
592
|
-
});
|
|
593
|
-
res.end();
|
|
594
|
-
});
|
|
595
|
-
const port = await getPort2({
|
|
596
|
-
random: true
|
|
917
|
+
const activationCtx = new Context3({
|
|
918
|
+
name: `trigger_${trigger.function}`
|
|
597
919
|
});
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
});
|
|
609
|
-
ctx.onDispose(() => {
|
|
610
|
-
server.close();
|
|
920
|
+
this._ctx.onDispose(() => activationCtx.dispose());
|
|
921
|
+
const registeredTrigger = this._triggersBySpaceKey.get(triggerCtx.space.key)?.find((reg) => reg.trigger.id === trigger.id);
|
|
922
|
+
invariant2(registeredTrigger, `Trigger is not registered: ${trigger.function}`, {
|
|
923
|
+
F: __dxlog_file9,
|
|
924
|
+
L: 81,
|
|
925
|
+
S: this,
|
|
926
|
+
A: [
|
|
927
|
+
"registeredTrigger",
|
|
928
|
+
"`Trigger is not registered: ${trigger.function}`"
|
|
929
|
+
]
|
|
611
930
|
});
|
|
931
|
+
registeredTrigger.activationCtx = activationCtx;
|
|
932
|
+
try {
|
|
933
|
+
const options = this._options?.[trigger.spec.type];
|
|
934
|
+
await triggerHandlers[trigger.spec.type](activationCtx, triggerCtx, trigger.spec, callback, options);
|
|
935
|
+
} catch (err) {
|
|
936
|
+
delete registeredTrigger.activationCtx;
|
|
937
|
+
throw err;
|
|
938
|
+
}
|
|
612
939
|
}
|
|
613
940
|
/**
|
|
614
|
-
*
|
|
615
|
-
* NOTE: The port must be unique, so the same hook cannot be used for multiple spaces.
|
|
941
|
+
* Loads triggers from the manifest into the space.
|
|
616
942
|
*/
|
|
617
|
-
async
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
}) {
|
|
621
|
-
log3.info("websocket", {
|
|
622
|
-
space: space.key,
|
|
623
|
-
trigger
|
|
943
|
+
async register(space, manifest) {
|
|
944
|
+
log9("register", {
|
|
945
|
+
space: space.key
|
|
624
946
|
}, {
|
|
625
|
-
F:
|
|
626
|
-
L:
|
|
947
|
+
F: __dxlog_file9,
|
|
948
|
+
L: 97,
|
|
627
949
|
S: this,
|
|
628
950
|
C: (f, a) => f(...a)
|
|
629
951
|
});
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
L: 269,
|
|
658
|
-
S: this,
|
|
659
|
-
C: (f, a) => f(...a)
|
|
660
|
-
});
|
|
661
|
-
if (event.code === 1006) {
|
|
662
|
-
setTimeout(async () => {
|
|
663
|
-
log3.info(`reconnecting in ${options.retryDelay}s...`, {
|
|
664
|
-
url
|
|
665
|
-
}, {
|
|
666
|
-
F: __dxlog_file3,
|
|
667
|
-
L: 274,
|
|
668
|
-
S: this,
|
|
669
|
-
C: (f, a) => f(...a)
|
|
670
|
-
});
|
|
671
|
-
await this._createWebsocket(ctx, space, def, trigger, options);
|
|
672
|
-
}, options.retryDelay * 1e3);
|
|
673
|
-
}
|
|
674
|
-
open.wake(false);
|
|
675
|
-
},
|
|
676
|
-
onerror: (event) => {
|
|
677
|
-
log3.catch(event.error, {
|
|
678
|
-
url
|
|
679
|
-
}, {
|
|
680
|
-
F: __dxlog_file3,
|
|
681
|
-
L: 283,
|
|
682
|
-
S: this,
|
|
683
|
-
C: (f, a) => f(...a)
|
|
684
|
-
});
|
|
685
|
-
},
|
|
686
|
-
onmessage: async (event) => {
|
|
687
|
-
try {
|
|
688
|
-
const data = JSON.parse(new TextDecoder().decode(event.data));
|
|
689
|
-
await this._execFunction(def, trigger, {
|
|
690
|
-
spaceKey: space.key,
|
|
691
|
-
data
|
|
692
|
-
});
|
|
693
|
-
} catch (err) {
|
|
694
|
-
log3.catch(err, {
|
|
695
|
-
url
|
|
696
|
-
}, {
|
|
697
|
-
F: __dxlog_file3,
|
|
698
|
-
L: 291,
|
|
699
|
-
S: this,
|
|
700
|
-
C: (f, a) => f(...a)
|
|
701
|
-
});
|
|
702
|
-
}
|
|
952
|
+
if (!manifest.triggers?.length) {
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
if (!space.db.graph.runtimeSchemaRegistry.hasSchema(FunctionTrigger)) {
|
|
956
|
+
space.db.graph.runtimeSchemaRegistry.registerSchema(FunctionTrigger);
|
|
957
|
+
}
|
|
958
|
+
const { objects: existing } = await space.db.query(Filter3.schema(FunctionTrigger)).run();
|
|
959
|
+
const { added, removed } = diff(existing, manifest.triggers, (a, b) => {
|
|
960
|
+
const keys = b[ECHO_ATTR_META]?.keys ?? [
|
|
961
|
+
foreignKey("manifest", [
|
|
962
|
+
b.function,
|
|
963
|
+
b.spec.type
|
|
964
|
+
].join("-"))
|
|
965
|
+
];
|
|
966
|
+
return intersection(getMeta(a)?.keys ?? [], keys, foreignKeyEquals).length > 0;
|
|
967
|
+
});
|
|
968
|
+
added.forEach((trigger) => {
|
|
969
|
+
const { meta, object } = splitMeta(trigger);
|
|
970
|
+
space.db.add(create2(FunctionTrigger, object, meta));
|
|
971
|
+
});
|
|
972
|
+
removed.forEach((trigger) => space.db.remove(trigger));
|
|
973
|
+
}
|
|
974
|
+
async _open() {
|
|
975
|
+
const spaceListSubscription = this._client.spaces.subscribe(async (spaces) => {
|
|
976
|
+
for (const space of spaces) {
|
|
977
|
+
if (this._triggersBySpaceKey.has(space.key)) {
|
|
978
|
+
continue;
|
|
703
979
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
const wait = Math.pow(attempt, 2) * options.retryDelay;
|
|
710
|
-
if (attempt < options.maxAttempts) {
|
|
711
|
-
log3.warn(`failed to connect; trying again in ${wait}s`, {
|
|
712
|
-
attempt
|
|
713
|
-
}, {
|
|
714
|
-
F: __dxlog_file3,
|
|
715
|
-
L: 302,
|
|
716
|
-
S: this,
|
|
717
|
-
C: (f, a) => f(...a)
|
|
718
|
-
});
|
|
719
|
-
await sleep(wait * 1e3);
|
|
980
|
+
const registered = [];
|
|
981
|
+
this._triggersBySpaceKey.set(space.key, registered);
|
|
982
|
+
await space.waitUntilReady();
|
|
983
|
+
if (this._ctx.disposed) {
|
|
984
|
+
break;
|
|
720
985
|
}
|
|
986
|
+
const functionsSubscription = space.db.query(Filter3.schema(FunctionTrigger)).subscribe(async (triggers) => {
|
|
987
|
+
await this._handleRemovedTriggers(space, triggers.objects, registered);
|
|
988
|
+
this._handleNewTriggers(space, triggers.objects, registered);
|
|
989
|
+
});
|
|
990
|
+
this._ctx.onDispose(functionsSubscription);
|
|
721
991
|
}
|
|
722
|
-
}
|
|
723
|
-
ctx.onDispose(() => {
|
|
724
|
-
ws?.close();
|
|
725
992
|
});
|
|
993
|
+
this._ctx.onDispose(() => spaceListSubscription.unsubscribe());
|
|
726
994
|
}
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
trigger
|
|
734
|
-
}, {
|
|
735
|
-
F: __dxlog_file3,
|
|
736
|
-
L: 317,
|
|
737
|
-
S: this,
|
|
738
|
-
C: (f, a) => f(...a)
|
|
995
|
+
async _close(_) {
|
|
996
|
+
this._triggersBySpaceKey.clear();
|
|
997
|
+
}
|
|
998
|
+
_handleNewTriggers(space, allTriggers, registered) {
|
|
999
|
+
const newTriggers = allTriggers.filter((candidate) => {
|
|
1000
|
+
return registered.find((reg) => reg.trigger.id === candidate.id) == null;
|
|
739
1001
|
});
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
1002
|
+
if (newTriggers.length > 0) {
|
|
1003
|
+
const newRegisteredTriggers = newTriggers.map((trigger) => ({
|
|
1004
|
+
trigger
|
|
1005
|
+
}));
|
|
1006
|
+
registered.push(...newRegisteredTriggers);
|
|
1007
|
+
log9("registered new triggers", () => ({
|
|
744
1008
|
spaceKey: space.key,
|
|
745
|
-
|
|
746
|
-
})
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
const subscription = createSubscription(({ added, updated }) => {
|
|
750
|
-
log3.info("updated", {
|
|
751
|
-
added: added.length,
|
|
752
|
-
updated: updated.length
|
|
753
|
-
}, {
|
|
754
|
-
F: __dxlog_file3,
|
|
755
|
-
L: 329,
|
|
1009
|
+
functions: newTriggers.map((t) => t.function)
|
|
1010
|
+
}), {
|
|
1011
|
+
F: __dxlog_file9,
|
|
1012
|
+
L: 159,
|
|
756
1013
|
S: this,
|
|
757
1014
|
C: (f, a) => f(...a)
|
|
758
1015
|
});
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
objects: objects.length
|
|
774
|
-
}, {
|
|
775
|
-
F: __dxlog_file3,
|
|
776
|
-
L: 349,
|
|
777
|
-
S: this,
|
|
778
|
-
C: (f, a) => f(...a)
|
|
779
|
-
});
|
|
780
|
-
for (const object of objects) {
|
|
781
|
-
const content = object.content;
|
|
782
|
-
if (content instanceof TextV0Type) {
|
|
783
|
-
subscriptions.push(getAutomergeObjectCore(content).updates.on(debounce(() => subscription.update([
|
|
784
|
-
object
|
|
785
|
-
]), 1e3)));
|
|
786
|
-
}
|
|
787
|
-
}
|
|
1016
|
+
this.registered.emit({
|
|
1017
|
+
space,
|
|
1018
|
+
triggers: newTriggers
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
async _handleRemovedTriggers(space, allTriggers, registered) {
|
|
1023
|
+
const removed = [];
|
|
1024
|
+
for (let i = registered.length - 1; i >= 0; i--) {
|
|
1025
|
+
const wasRemoved = allTriggers.find((trigger) => trigger.id === registered[i].trigger.id) == null;
|
|
1026
|
+
if (wasRemoved) {
|
|
1027
|
+
const unregistered = registered.splice(i, 1)[0];
|
|
1028
|
+
await unregistered.activationCtx?.dispose();
|
|
1029
|
+
removed.push(unregistered.trigger);
|
|
788
1030
|
}
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
1031
|
+
}
|
|
1032
|
+
if (removed.length > 0) {
|
|
1033
|
+
this.removed.emit({
|
|
1034
|
+
space,
|
|
1035
|
+
triggers: removed
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
_getTriggers(space, predicate) {
|
|
1040
|
+
const allSpaceTriggers = this._triggersBySpaceKey.get(space.key) ?? [];
|
|
1041
|
+
return allSpaceTriggers.filter(predicate).map((trigger) => trigger.trigger);
|
|
795
1042
|
}
|
|
796
1043
|
};
|
|
797
|
-
|
|
798
|
-
// packages/core/functions/src/types.ts
|
|
799
|
-
import * as S from "@effect/schema/Schema";
|
|
800
|
-
var TimerTriggerSchema = S.struct({
|
|
801
|
-
cron: S.string
|
|
802
|
-
});
|
|
803
|
-
var WebhookTriggerSchema = S.mutable(S.struct({
|
|
804
|
-
method: S.string,
|
|
805
|
-
// Assigned port.
|
|
806
|
-
port: S.optional(S.number)
|
|
807
|
-
}));
|
|
808
|
-
var WebsocketTriggerSchema = S.struct({
|
|
809
|
-
url: S.string,
|
|
810
|
-
init: S.optional(S.record(S.string, S.any))
|
|
811
|
-
});
|
|
812
|
-
var SubscriptionTriggerSchema = S.struct({
|
|
813
|
-
spaceKey: S.optional(S.string),
|
|
814
|
-
// TODO(burdon): Define query DSL.
|
|
815
|
-
filter: S.array(S.struct({
|
|
816
|
-
type: S.string,
|
|
817
|
-
props: S.optional(S.record(S.string, S.any))
|
|
818
|
-
})),
|
|
819
|
-
options: S.optional(S.struct({
|
|
820
|
-
// Watch changes to object (not just creation).
|
|
821
|
-
deep: S.optional(S.boolean),
|
|
822
|
-
// Debounce changes (delay in ms).
|
|
823
|
-
delay: S.optional(S.number)
|
|
824
|
-
}))
|
|
825
|
-
});
|
|
826
|
-
var FunctionTriggerSchema = S.struct({
|
|
827
|
-
function: S.string.pipe(S.description("Function ID/URI.")),
|
|
828
|
-
// Context passed to function.
|
|
829
|
-
meta: S.optional(S.record(S.string, S.any)),
|
|
830
|
-
// Triggers.
|
|
831
|
-
timer: S.optional(TimerTriggerSchema),
|
|
832
|
-
webhook: S.optional(WebhookTriggerSchema),
|
|
833
|
-
websocket: S.optional(WebsocketTriggerSchema),
|
|
834
|
-
subscription: S.optional(SubscriptionTriggerSchema)
|
|
835
|
-
});
|
|
836
|
-
var FunctionDefSchema = S.struct({
|
|
837
|
-
id: S.string,
|
|
838
|
-
// name: S.string,
|
|
839
|
-
description: S.optional(S.string),
|
|
840
|
-
// TODO(burdon): Rename route?
|
|
841
|
-
path: S.string,
|
|
842
|
-
// TODO(burdon): NPM/GitHub/Docker/CF URL?
|
|
843
|
-
handler: S.string
|
|
844
|
-
});
|
|
845
|
-
var FunctionManifestSchema = S.struct({
|
|
846
|
-
functions: S.mutable(S.array(FunctionDefSchema)),
|
|
847
|
-
triggers: S.optional(S.mutable(S.array(FunctionTriggerSchema)))
|
|
848
|
-
});
|
|
849
1044
|
export {
|
|
850
1045
|
DevServer,
|
|
1046
|
+
FunctionDef,
|
|
851
1047
|
FunctionManifestSchema,
|
|
1048
|
+
FunctionRegistry,
|
|
1049
|
+
FunctionTrigger,
|
|
852
1050
|
Scheduler,
|
|
1051
|
+
TriggerRegistry,
|
|
853
1052
|
subscriptionHandler
|
|
854
1053
|
};
|
|
855
1054
|
//# sourceMappingURL=index.mjs.map
|