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