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