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