@dxos/functions 0.5.3-main.a3ea5f1 → 0.5.3-main.a7bd8e4
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 +493 -692
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +486 -675
- 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 +14 -30
- 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 +20 -37
- 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/lib/browser/chunk-366QG6IX.mjs +0 -81
- package/dist/lib/browser/chunk-366QG6IX.mjs.map +0 -7
- package/dist/lib/browser/types.mjs +0 -12
- package/dist/lib/browser/types.mjs.map +0 -7
- package/dist/lib/node/chunk-3VSJ57ZZ.cjs +0 -97
- package/dist/lib/node/chunk-3VSJ57ZZ.cjs.map +0 -7
- package/dist/lib/node/types.cjs +0 -33
- package/dist/lib/node/types.cjs.map +0 -7
- 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
|
@@ -1,135 +1,44 @@
|
|
|
1
1
|
import "@dxos/node-std/globals";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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";
|
|
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);
|
|
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
|
+
});
|
|
39
9
|
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
};
|
|
10
|
+
// inject-globals:@inject-globals
|
|
11
|
+
import {
|
|
12
|
+
global,
|
|
13
|
+
Buffer as Buffer2,
|
|
14
|
+
process
|
|
15
|
+
} from "@dxos/node-std/inject-globals";
|
|
107
16
|
|
|
108
17
|
// packages/core/functions/src/handler.ts
|
|
109
|
-
import { PublicKey
|
|
110
|
-
import { log
|
|
18
|
+
import { PublicKey } from "@dxos/client";
|
|
19
|
+
import { log } from "@dxos/log";
|
|
111
20
|
import { nonNullable } from "@dxos/util";
|
|
112
|
-
var
|
|
21
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/functions/src/handler.ts";
|
|
113
22
|
var subscriptionHandler = (handler) => {
|
|
114
23
|
return ({ event: { data }, context, ...rest }) => {
|
|
115
24
|
const { client } = context;
|
|
116
|
-
const space = data.spaceKey ? client.spaces.get(
|
|
25
|
+
const space = data.spaceKey ? client.spaces.get(PublicKey.from(data.spaceKey)) : void 0;
|
|
117
26
|
const objects = space ? data.objects?.map((id) => space.db.getObjectById(id)).filter(nonNullable) : [];
|
|
118
27
|
if (!!data.spaceKey && !space) {
|
|
119
|
-
|
|
28
|
+
log.warn("invalid space", {
|
|
120
29
|
data
|
|
121
30
|
}, {
|
|
122
|
-
F:
|
|
31
|
+
F: __dxlog_file,
|
|
123
32
|
L: 91,
|
|
124
33
|
S: void 0,
|
|
125
34
|
C: (f, a) => f(...a)
|
|
126
35
|
});
|
|
127
36
|
} else {
|
|
128
|
-
|
|
37
|
+
log.info("handler", {
|
|
129
38
|
space: space?.key.truncate(),
|
|
130
39
|
objects: objects?.length
|
|
131
40
|
}, {
|
|
132
|
-
F:
|
|
41
|
+
F: __dxlog_file,
|
|
133
42
|
L: 93,
|
|
134
43
|
S: void 0,
|
|
135
44
|
C: (f, a) => f(...a)
|
|
@@ -153,32 +62,18 @@ var subscriptionHandler = (handler) => {
|
|
|
153
62
|
import express from "express";
|
|
154
63
|
import { getPort } from "get-port-please";
|
|
155
64
|
import { join } from "@dxos/node-std/path";
|
|
156
|
-
import { Event
|
|
157
|
-
import { Context } from "@dxos/context";
|
|
65
|
+
import { Event, Trigger } from "@dxos/async";
|
|
158
66
|
import { invariant } from "@dxos/invariant";
|
|
159
|
-
import { log as
|
|
160
|
-
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";
|
|
161
69
|
var DevServer = class {
|
|
162
|
-
|
|
70
|
+
// prettier-ignore
|
|
71
|
+
constructor(_client, _options) {
|
|
163
72
|
this._client = _client;
|
|
164
|
-
this._functionsRegistry = _functionsRegistry;
|
|
165
73
|
this._options = _options;
|
|
166
|
-
this._ctx = createContext();
|
|
167
74
|
this._handlers = {};
|
|
168
75
|
this._seq = 0;
|
|
169
|
-
this.update = new
|
|
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
|
-
});
|
|
76
|
+
this.update = new Event();
|
|
182
77
|
}
|
|
183
78
|
get stats() {
|
|
184
79
|
return {
|
|
@@ -187,8 +82,8 @@ var DevServer = class {
|
|
|
187
82
|
}
|
|
188
83
|
get endpoint() {
|
|
189
84
|
invariant(this._port, void 0, {
|
|
190
|
-
F:
|
|
191
|
-
L:
|
|
85
|
+
F: __dxlog_file2,
|
|
86
|
+
L: 54,
|
|
192
87
|
S: this,
|
|
193
88
|
A: [
|
|
194
89
|
"this._port",
|
|
@@ -203,32 +98,45 @@ var DevServer = class {
|
|
|
203
98
|
get functions() {
|
|
204
99
|
return Object.values(this._handlers);
|
|
205
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
|
+
}
|
|
206
115
|
async start() {
|
|
207
116
|
invariant(!this._server, void 0, {
|
|
208
|
-
F:
|
|
209
|
-
L:
|
|
117
|
+
F: __dxlog_file2,
|
|
118
|
+
L: 77,
|
|
210
119
|
S: this,
|
|
211
120
|
A: [
|
|
212
121
|
"!this._server",
|
|
213
122
|
""
|
|
214
123
|
]
|
|
215
124
|
});
|
|
216
|
-
|
|
217
|
-
F:
|
|
218
|
-
L:
|
|
125
|
+
log2.info("starting...", void 0, {
|
|
126
|
+
F: __dxlog_file2,
|
|
127
|
+
L: 78,
|
|
219
128
|
S: this,
|
|
220
129
|
C: (f, a) => f(...a)
|
|
221
130
|
});
|
|
222
|
-
this._ctx = createContext();
|
|
223
131
|
const app = express();
|
|
224
132
|
app.use(express.json());
|
|
225
133
|
app.post("/:path", async (req, res) => {
|
|
226
134
|
const { path: path2 } = req.params;
|
|
227
135
|
try {
|
|
228
|
-
|
|
136
|
+
log2.info("calling", {
|
|
229
137
|
path: path2
|
|
230
138
|
}, {
|
|
231
|
-
F:
|
|
139
|
+
F: __dxlog_file2,
|
|
232
140
|
L: 87,
|
|
233
141
|
S: this,
|
|
234
142
|
C: (f, a) => f(...a)
|
|
@@ -240,8 +148,8 @@ var DevServer = class {
|
|
|
240
148
|
res.statusCode = await this.invoke("/" + path2, req.body);
|
|
241
149
|
res.end();
|
|
242
150
|
} catch (err) {
|
|
243
|
-
|
|
244
|
-
F:
|
|
151
|
+
log2.catch(err, void 0, {
|
|
152
|
+
F: __dxlog_file2,
|
|
245
153
|
L: 97,
|
|
246
154
|
S: this,
|
|
247
155
|
C: (f, a) => f(...a)
|
|
@@ -261,61 +169,64 @@ var DevServer = class {
|
|
|
261
169
|
this._server = app.listen(this._port);
|
|
262
170
|
try {
|
|
263
171
|
const { registrationId, endpoint } = await this._client.services.services.FunctionRegistryService.register({
|
|
264
|
-
endpoint: this.endpoint
|
|
172
|
+
endpoint: this.endpoint,
|
|
173
|
+
functions: this.functions.map(({ def: { id, path: path2 } }) => ({
|
|
174
|
+
id,
|
|
175
|
+
path: path2
|
|
176
|
+
}))
|
|
265
177
|
});
|
|
266
|
-
|
|
178
|
+
log2.info("registered", {
|
|
267
179
|
endpoint
|
|
268
180
|
}, {
|
|
269
|
-
F:
|
|
270
|
-
L:
|
|
181
|
+
F: __dxlog_file2,
|
|
182
|
+
L: 113,
|
|
271
183
|
S: this,
|
|
272
184
|
C: (f, a) => f(...a)
|
|
273
185
|
});
|
|
274
186
|
this._proxy = endpoint;
|
|
275
187
|
this._functionServiceRegistration = registrationId;
|
|
276
|
-
await this._functionsRegistry.open(this._ctx);
|
|
277
188
|
} catch (err) {
|
|
278
189
|
await this.stop();
|
|
279
190
|
throw new Error("FunctionRegistryService not available (check plugin is configured).");
|
|
280
191
|
}
|
|
281
|
-
|
|
192
|
+
log2.info("started", {
|
|
282
193
|
port: this._port
|
|
283
194
|
}, {
|
|
284
|
-
F:
|
|
285
|
-
L:
|
|
195
|
+
F: __dxlog_file2,
|
|
196
|
+
L: 121,
|
|
286
197
|
S: this,
|
|
287
198
|
C: (f, a) => f(...a)
|
|
288
199
|
});
|
|
289
200
|
}
|
|
290
201
|
async stop() {
|
|
291
202
|
invariant(this._server, void 0, {
|
|
292
|
-
F:
|
|
293
|
-
L:
|
|
203
|
+
F: __dxlog_file2,
|
|
204
|
+
L: 125,
|
|
294
205
|
S: this,
|
|
295
206
|
A: [
|
|
296
207
|
"this._server",
|
|
297
208
|
""
|
|
298
209
|
]
|
|
299
210
|
});
|
|
300
|
-
|
|
301
|
-
F:
|
|
302
|
-
L:
|
|
211
|
+
log2.info("stopping...", void 0, {
|
|
212
|
+
F: __dxlog_file2,
|
|
213
|
+
L: 126,
|
|
303
214
|
S: this,
|
|
304
215
|
C: (f, a) => f(...a)
|
|
305
216
|
});
|
|
306
217
|
const trigger = new Trigger();
|
|
307
218
|
this._server.close(async () => {
|
|
308
|
-
|
|
309
|
-
F:
|
|
310
|
-
L:
|
|
219
|
+
log2.info("server stopped", void 0, {
|
|
220
|
+
F: __dxlog_file2,
|
|
221
|
+
L: 130,
|
|
311
222
|
S: this,
|
|
312
223
|
C: (f, a) => f(...a)
|
|
313
224
|
});
|
|
314
225
|
try {
|
|
315
226
|
if (this._functionServiceRegistration) {
|
|
316
227
|
invariant(this._client.services.services.FunctionRegistryService, void 0, {
|
|
317
|
-
F:
|
|
318
|
-
L:
|
|
228
|
+
F: __dxlog_file2,
|
|
229
|
+
L: 133,
|
|
319
230
|
S: this,
|
|
320
231
|
A: [
|
|
321
232
|
"this._client.services.services.FunctionRegistryService",
|
|
@@ -325,11 +236,11 @@ var DevServer = class {
|
|
|
325
236
|
await this._client.services.services.FunctionRegistryService.unregister({
|
|
326
237
|
registrationId: this._functionServiceRegistration
|
|
327
238
|
});
|
|
328
|
-
|
|
239
|
+
log2.info("unregistered", {
|
|
329
240
|
registrationId: this._functionServiceRegistration
|
|
330
241
|
}, {
|
|
331
|
-
F:
|
|
332
|
-
L:
|
|
242
|
+
F: __dxlog_file2,
|
|
243
|
+
L: 138,
|
|
333
244
|
S: this,
|
|
334
245
|
C: (f, a) => f(...a)
|
|
335
246
|
});
|
|
@@ -344,9 +255,9 @@ var DevServer = class {
|
|
|
344
255
|
await trigger.wait();
|
|
345
256
|
this._port = void 0;
|
|
346
257
|
this._server = void 0;
|
|
347
|
-
|
|
348
|
-
F:
|
|
349
|
-
L:
|
|
258
|
+
log2.info("stopped", void 0, {
|
|
259
|
+
F: __dxlog_file2,
|
|
260
|
+
L: 152,
|
|
350
261
|
S: this,
|
|
351
262
|
C: (f, a) => f(...a)
|
|
352
263
|
});
|
|
@@ -354,15 +265,15 @@ var DevServer = class {
|
|
|
354
265
|
/**
|
|
355
266
|
* Load function.
|
|
356
267
|
*/
|
|
357
|
-
async _load(def, force) {
|
|
358
|
-
const {
|
|
268
|
+
async _load(def, force = false) {
|
|
269
|
+
const { id, path: path2, handler } = def;
|
|
359
270
|
const filePath = join(this._options.baseDir, handler);
|
|
360
|
-
|
|
361
|
-
|
|
271
|
+
log2.info("loading", {
|
|
272
|
+
id,
|
|
362
273
|
force
|
|
363
274
|
}, {
|
|
364
|
-
F:
|
|
365
|
-
L:
|
|
275
|
+
F: __dxlog_file2,
|
|
276
|
+
L: 161,
|
|
366
277
|
S: this,
|
|
367
278
|
C: (f, a) => f(...a)
|
|
368
279
|
});
|
|
@@ -373,66 +284,39 @@ var DevServer = class {
|
|
|
373
284
|
}
|
|
374
285
|
const module = __require(filePath);
|
|
375
286
|
if (typeof module.default !== "function") {
|
|
376
|
-
throw new Error(`Handler must export default function: ${
|
|
287
|
+
throw new Error(`Handler must export default function: ${id}`);
|
|
377
288
|
}
|
|
378
|
-
this._handlers[
|
|
289
|
+
this._handlers[path2] = {
|
|
379
290
|
def,
|
|
380
291
|
handler: module.default
|
|
381
292
|
};
|
|
382
293
|
}
|
|
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
|
-
}
|
|
410
294
|
/**
|
|
411
295
|
* Invoke function.
|
|
412
296
|
*/
|
|
413
297
|
async invoke(path2, data) {
|
|
414
298
|
const seq = ++this._seq;
|
|
415
299
|
const now = Date.now();
|
|
416
|
-
|
|
300
|
+
log2.info("req", {
|
|
417
301
|
seq,
|
|
418
302
|
path: path2
|
|
419
303
|
}, {
|
|
420
|
-
F:
|
|
421
|
-
L:
|
|
304
|
+
F: __dxlog_file2,
|
|
305
|
+
L: 188,
|
|
422
306
|
S: this,
|
|
423
307
|
C: (f, a) => f(...a)
|
|
424
308
|
});
|
|
425
309
|
const statusCode = await this._invoke(path2, {
|
|
426
310
|
data
|
|
427
311
|
});
|
|
428
|
-
|
|
312
|
+
log2.info("res", {
|
|
429
313
|
seq,
|
|
430
314
|
path: path2,
|
|
431
315
|
statusCode,
|
|
432
316
|
duration: Date.now() - now
|
|
433
317
|
}, {
|
|
434
|
-
F:
|
|
435
|
-
L:
|
|
318
|
+
F: __dxlog_file2,
|
|
319
|
+
L: 191,
|
|
436
320
|
S: this,
|
|
437
321
|
C: (f, a) => f(...a)
|
|
438
322
|
});
|
|
@@ -442,8 +326,8 @@ var DevServer = class {
|
|
|
442
326
|
async _invoke(path2, event) {
|
|
443
327
|
const { handler } = this._handlers[path2] ?? {};
|
|
444
328
|
invariant(handler, `invalid path: ${path2}`, {
|
|
445
|
-
F:
|
|
446
|
-
L:
|
|
329
|
+
F: __dxlog_file2,
|
|
330
|
+
L: 198,
|
|
447
331
|
S: this,
|
|
448
332
|
A: [
|
|
449
333
|
"handler",
|
|
@@ -469,104 +353,125 @@ var DevServer = class {
|
|
|
469
353
|
return statusCode;
|
|
470
354
|
}
|
|
471
355
|
};
|
|
472
|
-
var createContext = () => new Context({
|
|
473
|
-
name: "DevServer"
|
|
474
|
-
});
|
|
475
356
|
|
|
476
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";
|
|
477
361
|
import path from "@dxos/node-std/path";
|
|
478
|
-
import
|
|
479
|
-
import {
|
|
480
|
-
import {
|
|
481
|
-
|
|
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";
|
|
482
371
|
var Scheduler = class {
|
|
483
|
-
constructor(
|
|
484
|
-
this.
|
|
485
|
-
this.
|
|
372
|
+
constructor(_client, _manifest, _options = {}) {
|
|
373
|
+
this._client = _client;
|
|
374
|
+
this._manifest = _manifest;
|
|
486
375
|
this._options = _options;
|
|
487
|
-
this.
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
});
|
|
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
|
+
}, []);
|
|
495
383
|
}
|
|
496
384
|
async start() {
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
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
|
+
});
|
|
501
393
|
}
|
|
502
394
|
async stop() {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
}
|
|
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);
|
|
395
|
+
for (const { id, spaceKey } of this._mounts.keys()) {
|
|
396
|
+
await this.unmount(id, spaceKey);
|
|
397
|
+
}
|
|
511
398
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
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
|
+
]
|
|
515
416
|
});
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
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
|
|
523
426
|
}, {
|
|
524
|
-
F:
|
|
525
|
-
L:
|
|
427
|
+
F: __dxlog_file3,
|
|
428
|
+
L: 82,
|
|
526
429
|
S: this,
|
|
527
430
|
C: (f, a) => f(...a)
|
|
528
431
|
});
|
|
529
|
-
|
|
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
|
+
}
|
|
530
447
|
}
|
|
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
|
-
});
|
|
553
448
|
}
|
|
554
|
-
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) {
|
|
555
461
|
let status = 0;
|
|
556
462
|
try {
|
|
557
|
-
const payload = Object.assign({},
|
|
558
|
-
meta
|
|
463
|
+
const payload = Object.assign({}, {
|
|
464
|
+
meta: trigger.meta
|
|
559
465
|
}, data);
|
|
560
466
|
const { endpoint, callback } = this._options;
|
|
561
467
|
if (endpoint) {
|
|
562
|
-
const url = path.join(endpoint, def.
|
|
563
|
-
|
|
564
|
-
function: def.
|
|
565
|
-
url
|
|
566
|
-
triggerType: trigger.spec.type
|
|
468
|
+
const url = path.join(endpoint, def.path);
|
|
469
|
+
log3.info("exec", {
|
|
470
|
+
function: def.id,
|
|
471
|
+
url
|
|
567
472
|
}, {
|
|
568
|
-
F:
|
|
569
|
-
L:
|
|
473
|
+
F: __dxlog_file3,
|
|
474
|
+
L: 128,
|
|
570
475
|
S: this,
|
|
571
476
|
C: (f, a) => f(...a)
|
|
572
477
|
});
|
|
@@ -579,11 +484,11 @@ var Scheduler = class {
|
|
|
579
484
|
});
|
|
580
485
|
status = response.status;
|
|
581
486
|
} else if (callback) {
|
|
582
|
-
|
|
583
|
-
function: def.
|
|
487
|
+
log3.info("exec", {
|
|
488
|
+
function: def.id
|
|
584
489
|
}, {
|
|
585
|
-
F:
|
|
586
|
-
L:
|
|
490
|
+
F: __dxlog_file3,
|
|
491
|
+
L: 139,
|
|
587
492
|
S: this,
|
|
588
493
|
C: (f, a) => f(...a)
|
|
589
494
|
});
|
|
@@ -592,22 +497,22 @@ var Scheduler = class {
|
|
|
592
497
|
if (status && status >= 400) {
|
|
593
498
|
throw new Error(`Response: ${status}`);
|
|
594
499
|
}
|
|
595
|
-
|
|
596
|
-
function: def.
|
|
500
|
+
log3.info("done", {
|
|
501
|
+
function: def.id,
|
|
597
502
|
status
|
|
598
503
|
}, {
|
|
599
|
-
F:
|
|
600
|
-
L:
|
|
504
|
+
F: __dxlog_file3,
|
|
505
|
+
L: 149,
|
|
601
506
|
S: this,
|
|
602
507
|
C: (f, a) => f(...a)
|
|
603
508
|
});
|
|
604
509
|
} catch (err) {
|
|
605
|
-
|
|
606
|
-
function: def.
|
|
510
|
+
log3.error("error", {
|
|
511
|
+
function: def.id,
|
|
607
512
|
error: err.message
|
|
608
513
|
}, {
|
|
609
|
-
F:
|
|
610
|
-
L:
|
|
514
|
+
F: __dxlog_file3,
|
|
515
|
+
L: 151,
|
|
611
516
|
S: this,
|
|
612
517
|
C: (f, a) => f(...a)
|
|
613
518
|
});
|
|
@@ -615,440 +520,336 @@ var Scheduler = class {
|
|
|
615
520
|
}
|
|
616
521
|
return status;
|
|
617
522
|
}
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
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
|
|
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
|
|
760
533
|
}, {
|
|
761
|
-
F:
|
|
762
|
-
L:
|
|
763
|
-
S:
|
|
534
|
+
F: __dxlog_file3,
|
|
535
|
+
L: 166,
|
|
536
|
+
S: this,
|
|
764
537
|
C: (f, a) => f(...a)
|
|
765
538
|
});
|
|
766
|
-
spec
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
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
|
|
791
|
-
}, {
|
|
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,
|
|
834
|
-
C: (f, a) => f(...a)
|
|
835
|
-
});
|
|
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
|
-
}
|
|
859
|
-
}
|
|
539
|
+
const spec = trigger.timer;
|
|
540
|
+
const task = new DeferredTask(ctx, async () => {
|
|
541
|
+
await this._execFunction(def, trigger, {
|
|
542
|
+
spaceKey: space.key
|
|
543
|
+
});
|
|
860
544
|
});
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
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
|
|
869
559
|
}, {
|
|
870
|
-
F:
|
|
871
|
-
L:
|
|
872
|
-
S:
|
|
560
|
+
F: __dxlog_file3,
|
|
561
|
+
L: 186,
|
|
562
|
+
S: this,
|
|
873
563
|
C: (f, a) => f(...a)
|
|
874
564
|
});
|
|
875
|
-
|
|
565
|
+
task.schedule();
|
|
876
566
|
}
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
|
|
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);
|
|
567
|
+
});
|
|
568
|
+
job.start();
|
|
569
|
+
ctx.onDispose(() => job.stop());
|
|
906
570
|
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
571
|
+
/**
|
|
572
|
+
* Webhook.
|
|
573
|
+
*/
|
|
574
|
+
async _createWebhook(ctx, space, def, trigger) {
|
|
575
|
+
log3.info("webhook", {
|
|
576
|
+
space: space.key,
|
|
910
577
|
trigger
|
|
911
578
|
}, {
|
|
912
|
-
F:
|
|
913
|
-
L:
|
|
579
|
+
F: __dxlog_file3,
|
|
580
|
+
L: 199,
|
|
914
581
|
S: this,
|
|
915
582
|
C: (f, a) => f(...a)
|
|
916
583
|
});
|
|
917
|
-
const
|
|
918
|
-
|
|
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();
|
|
919
594
|
});
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
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();
|
|
930
611
|
});
|
|
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
|
-
}
|
|
939
612
|
}
|
|
940
613
|
/**
|
|
941
|
-
*
|
|
614
|
+
* Websocket.
|
|
615
|
+
* NOTE: The port must be unique, so the same hook cannot be used for multiple spaces.
|
|
942
616
|
*/
|
|
943
|
-
async
|
|
944
|
-
|
|
945
|
-
|
|
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
|
|
946
624
|
}, {
|
|
947
|
-
F:
|
|
948
|
-
L:
|
|
625
|
+
F: __dxlog_file3,
|
|
626
|
+
L: 249,
|
|
949
627
|
S: this,
|
|
950
628
|
C: (f, a) => f(...a)
|
|
951
629
|
});
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
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
|
+
}
|
|
979
703
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
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);
|
|
985
720
|
}
|
|
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);
|
|
991
721
|
}
|
|
722
|
+
}
|
|
723
|
+
ctx.onDispose(() => {
|
|
724
|
+
ws?.close();
|
|
992
725
|
});
|
|
993
|
-
this._ctx.onDispose(() => spaceListSubscription.unsubscribe());
|
|
994
|
-
}
|
|
995
|
-
async _close(_) {
|
|
996
|
-
this._triggersBySpaceKey.clear();
|
|
997
726
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
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)
|
|
1001
739
|
});
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
registered.push(...newRegisteredTriggers);
|
|
1007
|
-
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, {
|
|
1008
744
|
spaceKey: space.key,
|
|
1009
|
-
|
|
1010
|
-
})
|
|
1011
|
-
|
|
1012
|
-
|
|
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,
|
|
1013
756
|
S: this,
|
|
1014
757
|
C: (f, a) => f(...a)
|
|
1015
758
|
});
|
|
1016
|
-
|
|
1017
|
-
|
|
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);
|
|
759
|
+
for (const object of added) {
|
|
760
|
+
objectIds.add(object.id);
|
|
1030
761
|
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
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
|
+
});
|
|
1042
795
|
}
|
|
1043
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
|
+
});
|
|
1044
849
|
export {
|
|
1045
850
|
DevServer,
|
|
1046
|
-
FunctionDef,
|
|
1047
851
|
FunctionManifestSchema,
|
|
1048
|
-
FunctionRegistry,
|
|
1049
|
-
FunctionTrigger,
|
|
1050
852
|
Scheduler,
|
|
1051
|
-
TriggerRegistry,
|
|
1052
853
|
subscriptionHandler
|
|
1053
854
|
};
|
|
1054
855
|
//# sourceMappingURL=index.mjs.map
|