@dxos/functions 0.5.3-main.37bbd91 → 0.5.3-main.3b535c7
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 +471 -825
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +461 -805
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/handler.d.ts +12 -33
- package/dist/types/src/handler.d.ts.map +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 +13 -16
- package/dist/types/src/runtime/dev-server.d.ts.map +1 -1
- package/dist/types/src/runtime/scheduler.d.ts +27 -13
- package/dist/types/src/runtime/scheduler.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +101 -143
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +15 -33
- package/schema/functions.json +104 -140
- package/src/handler.ts +31 -54
- package/src/index.ts +0 -2
- package/src/runtime/dev-server.ts +53 -104
- package/src/runtime/scheduler.test.ts +73 -56
- package/src/runtime/scheduler.ts +271 -87
- package/src/types.ts +32 -59
- 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/runtime/dev-server.test.d.ts +0 -2
- package/dist/types/src/runtime/dev-server.test.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/test/handler.d.ts +0 -4
- package/dist/types/src/testing/test/handler.d.ts.map +0 -1
- package/dist/types/src/testing/test/index.d.ts +0 -3
- package/dist/types/src/testing/test/index.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/runtime/dev-server.test.ts +0 -60
- 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/test/handler.ts +0 -15
- package/src/testing/test/index.ts +0 -7
- 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,147 +1,53 @@
|
|
|
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
|
-
return ({ event
|
|
23
|
+
return ({ event, context, ...rest }) => {
|
|
115
24
|
const { client } = context;
|
|
116
|
-
const space =
|
|
117
|
-
const objects = space
|
|
118
|
-
if (!!
|
|
119
|
-
|
|
120
|
-
|
|
25
|
+
const space = event.space ? client.spaces.get(PublicKey.from(event.space)) : void 0;
|
|
26
|
+
const objects = space && event.objects?.map((id) => space.db.getObjectById(id)).filter(nonNullable);
|
|
27
|
+
if (!!event.space && !space) {
|
|
28
|
+
log.warn("invalid space", {
|
|
29
|
+
event
|
|
121
30
|
}, {
|
|
122
|
-
F:
|
|
123
|
-
L:
|
|
31
|
+
F: __dxlog_file,
|
|
32
|
+
L: 68,
|
|
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:
|
|
133
|
-
L:
|
|
41
|
+
F: __dxlog_file,
|
|
42
|
+
L: 70,
|
|
134
43
|
S: void 0,
|
|
135
44
|
C: (f, a) => f(...a)
|
|
136
45
|
});
|
|
137
46
|
}
|
|
138
47
|
return handler({
|
|
139
48
|
event: {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
space,
|
|
143
|
-
objects
|
|
144
|
-
}
|
|
49
|
+
space,
|
|
50
|
+
objects
|
|
145
51
|
},
|
|
146
52
|
context,
|
|
147
53
|
...rest
|
|
@@ -153,42 +59,22 @@ var subscriptionHandler = (handler) => {
|
|
|
153
59
|
import express from "express";
|
|
154
60
|
import { getPort } from "get-port-please";
|
|
155
61
|
import { join } from "@dxos/node-std/path";
|
|
156
|
-
import {
|
|
157
|
-
import { Context } from "@dxos/context";
|
|
62
|
+
import { Trigger } from "@dxos/async";
|
|
158
63
|
import { invariant } from "@dxos/invariant";
|
|
159
|
-
import { log as
|
|
160
|
-
var
|
|
64
|
+
import { log as log2 } from "@dxos/log";
|
|
65
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/dev-server.ts";
|
|
161
66
|
var DevServer = class {
|
|
162
|
-
|
|
67
|
+
// prettier-ignore
|
|
68
|
+
constructor(_client, _options) {
|
|
163
69
|
this._client = _client;
|
|
164
|
-
this._functionsRegistry = _functionsRegistry;
|
|
165
70
|
this._options = _options;
|
|
166
|
-
this._ctx = createContext();
|
|
167
71
|
this._handlers = {};
|
|
168
72
|
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
|
-
};
|
|
187
73
|
}
|
|
188
74
|
get endpoint() {
|
|
189
75
|
invariant(this._port, void 0, {
|
|
190
|
-
F:
|
|
191
|
-
L:
|
|
76
|
+
F: __dxlog_file2,
|
|
77
|
+
L: 46,
|
|
192
78
|
S: this,
|
|
193
79
|
A: [
|
|
194
80
|
"this._port",
|
|
@@ -203,46 +89,44 @@ var DevServer = class {
|
|
|
203
89
|
get functions() {
|
|
204
90
|
return Object.values(this._handlers);
|
|
205
91
|
}
|
|
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
|
+
}
|
|
206
106
|
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();
|
|
223
107
|
const app = express();
|
|
224
108
|
app.use(express.json());
|
|
225
|
-
app.post("/:
|
|
226
|
-
const {
|
|
109
|
+
app.post("/:name", async (req, res) => {
|
|
110
|
+
const { name } = req.params;
|
|
227
111
|
try {
|
|
228
|
-
|
|
229
|
-
|
|
112
|
+
log2.info("calling", {
|
|
113
|
+
name
|
|
230
114
|
}, {
|
|
231
|
-
F:
|
|
232
|
-
L:
|
|
115
|
+
F: __dxlog_file2,
|
|
116
|
+
L: 75,
|
|
233
117
|
S: this,
|
|
234
118
|
C: (f, a) => f(...a)
|
|
235
119
|
});
|
|
236
120
|
if (this._options.reload) {
|
|
237
|
-
const { def } = this._handlers[
|
|
121
|
+
const { def } = this._handlers[name];
|
|
238
122
|
await this._load(def, true);
|
|
239
123
|
}
|
|
240
|
-
res.statusCode = await this.
|
|
124
|
+
res.statusCode = await this._invoke(name, req.body);
|
|
241
125
|
res.end();
|
|
242
126
|
} catch (err) {
|
|
243
|
-
|
|
244
|
-
F:
|
|
245
|
-
L:
|
|
127
|
+
log2.catch(err, void 0, {
|
|
128
|
+
F: __dxlog_file2,
|
|
129
|
+
L: 84,
|
|
246
130
|
S: this,
|
|
247
131
|
C: (f, a) => f(...a)
|
|
248
132
|
});
|
|
@@ -261,195 +145,93 @@ var DevServer = class {
|
|
|
261
145
|
this._server = app.listen(this._port);
|
|
262
146
|
try {
|
|
263
147
|
const { registrationId, endpoint } = await this._client.services.services.FunctionRegistryService.register({
|
|
264
|
-
endpoint: this.endpoint
|
|
148
|
+
endpoint: this.endpoint,
|
|
149
|
+
functions: this.functions.map(({ def: { name } }) => ({
|
|
150
|
+
name
|
|
151
|
+
}))
|
|
265
152
|
});
|
|
266
|
-
|
|
153
|
+
log2.info("registered", {
|
|
154
|
+
registrationId,
|
|
267
155
|
endpoint
|
|
268
156
|
}, {
|
|
269
|
-
F:
|
|
270
|
-
L:
|
|
157
|
+
F: __dxlog_file2,
|
|
158
|
+
L: 100,
|
|
271
159
|
S: this,
|
|
272
160
|
C: (f, a) => f(...a)
|
|
273
161
|
});
|
|
162
|
+
this._registrationId = registrationId;
|
|
274
163
|
this._proxy = endpoint;
|
|
275
|
-
this._functionServiceRegistration = registrationId;
|
|
276
|
-
await this._functionsRegistry.open(this._ctx);
|
|
277
164
|
} catch (err) {
|
|
278
165
|
await this.stop();
|
|
279
166
|
throw new Error("FunctionRegistryService not available (check plugin is configured).");
|
|
280
167
|
}
|
|
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
|
-
});
|
|
289
168
|
}
|
|
290
169
|
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
|
-
});
|
|
306
170
|
const trigger = new Trigger();
|
|
307
|
-
this._server
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
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);
|
|
171
|
+
this._server?.close(async () => {
|
|
172
|
+
if (this._registrationId) {
|
|
173
|
+
await this._client.services.services.FunctionRegistryService.unregister({
|
|
174
|
+
registrationId: this._registrationId
|
|
175
|
+
});
|
|
176
|
+
log2.info("unregistered", {
|
|
177
|
+
registrationId: this._registrationId
|
|
178
|
+
}, {
|
|
179
|
+
F: __dxlog_file2,
|
|
180
|
+
L: 117,
|
|
181
|
+
S: this,
|
|
182
|
+
C: (f, a) => f(...a)
|
|
183
|
+
});
|
|
184
|
+
this._registrationId = void 0;
|
|
185
|
+
this._proxy = void 0;
|
|
342
186
|
}
|
|
187
|
+
trigger.wake();
|
|
343
188
|
});
|
|
344
189
|
await trigger.wait();
|
|
345
190
|
this._port = void 0;
|
|
346
191
|
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
|
-
});
|
|
353
192
|
}
|
|
354
193
|
/**
|
|
355
194
|
* Load function.
|
|
356
195
|
*/
|
|
357
|
-
async _load(def,
|
|
358
|
-
const {
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
force
|
|
196
|
+
async _load(def, flush = false) {
|
|
197
|
+
const { id, name, handler } = def;
|
|
198
|
+
const path = join(this._options.directory, handler);
|
|
199
|
+
log2.info("loading", {
|
|
200
|
+
id
|
|
363
201
|
}, {
|
|
364
|
-
F:
|
|
365
|
-
L:
|
|
202
|
+
F: __dxlog_file2,
|
|
203
|
+
L: 136,
|
|
366
204
|
S: this,
|
|
367
205
|
C: (f, a) => f(...a)
|
|
368
206
|
});
|
|
369
|
-
if (
|
|
370
|
-
Object.keys(__require.cache).filter((key) => key.startsWith(
|
|
371
|
-
delete __require.cache[key];
|
|
372
|
-
});
|
|
207
|
+
if (flush) {
|
|
208
|
+
Object.keys(__require.cache).filter((key) => key.startsWith(path)).forEach((key) => delete __require.cache[key]);
|
|
373
209
|
}
|
|
374
|
-
const module = __require(
|
|
210
|
+
const module = __require(path);
|
|
375
211
|
if (typeof module.default !== "function") {
|
|
376
|
-
throw new Error(`Handler must export default function: ${
|
|
212
|
+
throw new Error(`Handler must export default function: ${id}`);
|
|
377
213
|
}
|
|
378
|
-
this._handlers[
|
|
214
|
+
this._handlers[name] = {
|
|
379
215
|
def,
|
|
380
216
|
handler: module.default
|
|
381
217
|
};
|
|
382
218
|
}
|
|
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
219
|
/**
|
|
411
|
-
* Invoke function.
|
|
220
|
+
* Invoke function handler.
|
|
412
221
|
*/
|
|
413
|
-
async
|
|
222
|
+
async _invoke(name, event) {
|
|
414
223
|
const seq = ++this._seq;
|
|
415
224
|
const now = Date.now();
|
|
416
|
-
|
|
225
|
+
log2.info("req", {
|
|
417
226
|
seq,
|
|
418
|
-
|
|
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
|
|
227
|
+
name
|
|
433
228
|
}, {
|
|
434
|
-
F:
|
|
435
|
-
L:
|
|
229
|
+
F: __dxlog_file2,
|
|
230
|
+
L: 161,
|
|
436
231
|
S: this,
|
|
437
232
|
C: (f, a) => f(...a)
|
|
438
233
|
});
|
|
439
|
-
this.
|
|
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
|
-
});
|
|
234
|
+
const { handler } = this._handlers[name];
|
|
453
235
|
const context = {
|
|
454
236
|
client: this._client,
|
|
455
237
|
dataDir: this._options.dataDir
|
|
@@ -466,589 +248,453 @@ var DevServer = class {
|
|
|
466
248
|
event,
|
|
467
249
|
response
|
|
468
250
|
});
|
|
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
|
+
});
|
|
469
262
|
return statusCode;
|
|
470
263
|
}
|
|
471
264
|
};
|
|
472
|
-
var createContext = () => new Context({
|
|
473
|
-
name: "DevServer"
|
|
474
|
-
});
|
|
475
265
|
|
|
476
266
|
// packages/core/functions/src/runtime/scheduler.ts
|
|
477
|
-
import
|
|
478
|
-
import
|
|
479
|
-
import
|
|
480
|
-
import {
|
|
481
|
-
|
|
267
|
+
import { CronJob } from "cron";
|
|
268
|
+
import http from "@dxos/node-std/http";
|
|
269
|
+
import WebSocket from "ws";
|
|
270
|
+
import { TextV0Type } from "@braneframe/types";
|
|
271
|
+
import { debounce, DeferredTask, sleep, Trigger as Trigger2 } from "@dxos/async";
|
|
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";
|
|
482
278
|
var Scheduler = class {
|
|
483
|
-
constructor(
|
|
484
|
-
this.
|
|
485
|
-
this.
|
|
279
|
+
constructor(_client, _manifest, _options = {}) {
|
|
280
|
+
this._client = _client;
|
|
281
|
+
this._manifest = _manifest;
|
|
486
282
|
this._options = _options;
|
|
487
|
-
this.
|
|
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
|
-
});
|
|
283
|
+
this._mounts = new ComplexMap(({ id, spaceKey }) => `${spaceKey.toHex()}:${id}`);
|
|
495
284
|
}
|
|
496
285
|
async start() {
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
286
|
+
this._client.spaces.subscribe(async (spaces) => {
|
|
287
|
+
for (const space of spaces) {
|
|
288
|
+
await space.waitUntilReady();
|
|
289
|
+
for (const trigger of this._manifest.triggers ?? []) {
|
|
290
|
+
await this.mount(new Context(), space, trigger);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
});
|
|
501
294
|
}
|
|
502
295
|
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);
|
|
296
|
+
for (const { id, spaceKey } of this._mounts.keys()) {
|
|
297
|
+
await this.unmount(id, spaceKey);
|
|
298
|
+
}
|
|
511
299
|
}
|
|
512
|
-
async
|
|
513
|
-
const
|
|
514
|
-
|
|
300
|
+
async mount(ctx, space, trigger) {
|
|
301
|
+
const key = {
|
|
302
|
+
id: trigger.function,
|
|
303
|
+
spaceKey: space.key
|
|
304
|
+
};
|
|
305
|
+
const def = this._manifest.functions.find((config) => config.id === trigger.function);
|
|
306
|
+
invariant2(def, `Function not found: ${trigger.function}`, {
|
|
307
|
+
F: __dxlog_file3,
|
|
308
|
+
L: 72,
|
|
309
|
+
S: this,
|
|
310
|
+
A: [
|
|
311
|
+
"def",
|
|
312
|
+
"`Function not found: ${trigger.function}`"
|
|
313
|
+
]
|
|
515
314
|
});
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
315
|
+
const exists = this._mounts.get(key);
|
|
316
|
+
if (!exists) {
|
|
317
|
+
this._mounts.set(key, {
|
|
318
|
+
ctx,
|
|
319
|
+
trigger
|
|
320
|
+
});
|
|
321
|
+
log3("mount", {
|
|
322
|
+
space: space.key,
|
|
323
|
+
trigger
|
|
523
324
|
}, {
|
|
524
|
-
F:
|
|
325
|
+
F: __dxlog_file3,
|
|
525
326
|
L: 78,
|
|
526
327
|
S: this,
|
|
527
328
|
C: (f, a) => f(...a)
|
|
528
329
|
});
|
|
529
|
-
|
|
330
|
+
if (ctx.disposed) {
|
|
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
|
+
}
|
|
530
345
|
}
|
|
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
346
|
}
|
|
554
|
-
async
|
|
555
|
-
|
|
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();
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
// TODO(burdon): Pass in Space key (common context).
|
|
359
|
+
async _execFunction(def, data) {
|
|
556
360
|
try {
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
},
|
|
361
|
+
log3.info("exec", {
|
|
362
|
+
function: def.id
|
|
363
|
+
}, {
|
|
364
|
+
F: __dxlog_file3,
|
|
365
|
+
L: 117,
|
|
366
|
+
S: this,
|
|
367
|
+
C: (f, a) => f(...a)
|
|
368
|
+
});
|
|
560
369
|
const { endpoint, callback } = this._options;
|
|
561
370
|
if (endpoint) {
|
|
562
|
-
|
|
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, {
|
|
371
|
+
await fetch(`${this._options.endpoint}/${def.name}`, {
|
|
574
372
|
method: "POST",
|
|
575
373
|
headers: {
|
|
576
374
|
"Content-Type": "application/json"
|
|
577
375
|
},
|
|
578
|
-
body: JSON.stringify(
|
|
376
|
+
body: JSON.stringify(data)
|
|
579
377
|
});
|
|
580
|
-
status = response.status;
|
|
581
378
|
} else if (callback) {
|
|
582
|
-
|
|
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}`);
|
|
379
|
+
await callback(data);
|
|
594
380
|
}
|
|
595
|
-
|
|
596
|
-
function: def.
|
|
597
|
-
status
|
|
381
|
+
log3.info("done", {
|
|
382
|
+
function: def.id
|
|
598
383
|
}, {
|
|
599
|
-
F:
|
|
600
|
-
L:
|
|
384
|
+
F: __dxlog_file3,
|
|
385
|
+
L: 133,
|
|
601
386
|
S: this,
|
|
602
387
|
C: (f, a) => f(...a)
|
|
603
388
|
});
|
|
604
389
|
} catch (err) {
|
|
605
|
-
|
|
606
|
-
function: def.
|
|
390
|
+
log3.error("error", {
|
|
391
|
+
function: def.id,
|
|
607
392
|
error: err.message
|
|
608
393
|
}, {
|
|
609
|
-
F:
|
|
610
|
-
L:
|
|
394
|
+
F: __dxlog_file3,
|
|
395
|
+
L: 135,
|
|
611
396
|
S: this,
|
|
612
397
|
C: (f, a) => f(...a)
|
|
613
398
|
});
|
|
614
|
-
status = 500;
|
|
615
399
|
}
|
|
616
|
-
return status;
|
|
617
400
|
}
|
|
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
|
|
401
|
+
//
|
|
402
|
+
// Triggers
|
|
403
|
+
//
|
|
404
|
+
/**
|
|
405
|
+
* Cron timer.
|
|
406
|
+
*/
|
|
407
|
+
async _createTimer(ctx, space, def, trigger) {
|
|
408
|
+
log3.info("timer", {
|
|
409
|
+
space: space.key,
|
|
410
|
+
trigger
|
|
760
411
|
}, {
|
|
761
|
-
F:
|
|
762
|
-
L:
|
|
763
|
-
S:
|
|
412
|
+
F: __dxlog_file3,
|
|
413
|
+
L: 147,
|
|
414
|
+
S: this,
|
|
764
415
|
C: (f, a) => f(...a)
|
|
765
416
|
});
|
|
766
|
-
|
|
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
|
-
}
|
|
417
|
+
const { cron } = trigger;
|
|
418
|
+
const task = new DeferredTask(ctx, async () => {
|
|
419
|
+
await this._execFunction(def, {
|
|
420
|
+
space: space.key
|
|
421
|
+
});
|
|
860
422
|
});
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
423
|
+
let last = 0;
|
|
424
|
+
let run = 0;
|
|
425
|
+
const job = CronJob.from({
|
|
426
|
+
cronTime: cron,
|
|
427
|
+
runOnInit: false,
|
|
428
|
+
onTick: () => {
|
|
429
|
+
const now = Date.now();
|
|
430
|
+
const delta = last ? now - last : 0;
|
|
431
|
+
last = now;
|
|
432
|
+
run++;
|
|
433
|
+
log3.info("tick", {
|
|
434
|
+
space: space.key.truncate(),
|
|
435
|
+
count: run,
|
|
436
|
+
delta
|
|
869
437
|
}, {
|
|
870
|
-
F:
|
|
871
|
-
L:
|
|
872
|
-
S:
|
|
438
|
+
F: __dxlog_file3,
|
|
439
|
+
L: 167,
|
|
440
|
+
S: this,
|
|
873
441
|
C: (f, a) => f(...a)
|
|
874
442
|
});
|
|
875
|
-
|
|
443
|
+
task.schedule();
|
|
876
444
|
}
|
|
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);
|
|
445
|
+
});
|
|
446
|
+
job.start();
|
|
447
|
+
ctx.onDispose(() => job.stop());
|
|
906
448
|
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
449
|
+
/**
|
|
450
|
+
* Webhook.
|
|
451
|
+
*/
|
|
452
|
+
async _createWebhook(ctx, space, def, trigger) {
|
|
453
|
+
log3.info("webhook", {
|
|
454
|
+
space: space.key,
|
|
910
455
|
trigger
|
|
911
456
|
}, {
|
|
912
|
-
F:
|
|
913
|
-
L:
|
|
457
|
+
F: __dxlog_file3,
|
|
458
|
+
L: 180,
|
|
914
459
|
S: this,
|
|
915
460
|
C: (f, a) => f(...a)
|
|
916
461
|
});
|
|
917
|
-
const
|
|
918
|
-
|
|
462
|
+
const { port } = trigger;
|
|
463
|
+
const server = http.createServer(async (req, res) => {
|
|
464
|
+
await this._execFunction(def, {
|
|
465
|
+
space: space.key
|
|
466
|
+
});
|
|
919
467
|
});
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
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
|
+
});
|
|
477
|
+
});
|
|
478
|
+
ctx.onDispose(() => {
|
|
479
|
+
server.close();
|
|
930
480
|
});
|
|
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
481
|
}
|
|
940
482
|
/**
|
|
941
|
-
*
|
|
483
|
+
* Websocket.
|
|
942
484
|
*/
|
|
943
|
-
async
|
|
944
|
-
|
|
945
|
-
|
|
485
|
+
async _createWebsocket(ctx, space, def, trigger, options = {
|
|
486
|
+
retryDelay: 2,
|
|
487
|
+
maxAttempts: 5
|
|
488
|
+
}) {
|
|
489
|
+
log3.info("websocket", {
|
|
490
|
+
space: space.key,
|
|
491
|
+
trigger
|
|
946
492
|
}, {
|
|
947
|
-
F:
|
|
948
|
-
L:
|
|
493
|
+
F: __dxlog_file3,
|
|
494
|
+
L: 213,
|
|
949
495
|
S: this,
|
|
950
496
|
C: (f, a) => f(...a)
|
|
951
497
|
});
|
|
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
|
-
|
|
498
|
+
const { url } = trigger;
|
|
499
|
+
let ws;
|
|
500
|
+
for (let attempt = 1; attempt <= options.maxAttempts; attempt++) {
|
|
501
|
+
const open = new Trigger2();
|
|
502
|
+
ws = new WebSocket(url);
|
|
503
|
+
Object.assign(ws, {
|
|
504
|
+
onopen: () => {
|
|
505
|
+
log3.info("opened", {
|
|
506
|
+
url
|
|
507
|
+
}, {
|
|
508
|
+
F: __dxlog_file3,
|
|
509
|
+
L: 223,
|
|
510
|
+
S: this,
|
|
511
|
+
C: (f, a) => f(...a)
|
|
512
|
+
});
|
|
513
|
+
if (trigger.init) {
|
|
514
|
+
ws.send(new TextEncoder().encode(JSON.stringify(trigger.init)));
|
|
515
|
+
}
|
|
516
|
+
open.wake(true);
|
|
517
|
+
},
|
|
518
|
+
onclose: () => {
|
|
519
|
+
log3.info("closed", {
|
|
520
|
+
url
|
|
521
|
+
}, {
|
|
522
|
+
F: __dxlog_file3,
|
|
523
|
+
L: 232,
|
|
524
|
+
S: this,
|
|
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
|
+
}
|
|
979
556
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
557
|
+
});
|
|
558
|
+
const isOpen = await open.wait();
|
|
559
|
+
if (isOpen) {
|
|
560
|
+
break;
|
|
561
|
+
} else {
|
|
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);
|
|
985
573
|
}
|
|
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
574
|
}
|
|
575
|
+
}
|
|
576
|
+
ctx.onDispose(() => {
|
|
577
|
+
ws?.close();
|
|
992
578
|
});
|
|
993
|
-
this._ctx.onDispose(() => spaceListSubscription.unsubscribe());
|
|
994
|
-
}
|
|
995
|
-
async _close(_) {
|
|
996
|
-
this._triggersBySpaceKey.clear();
|
|
997
579
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
580
|
+
/**
|
|
581
|
+
* ECHO subscription.
|
|
582
|
+
*/
|
|
583
|
+
async _createSubscription(ctx, space, def, trigger) {
|
|
584
|
+
log3.info("subscription", {
|
|
585
|
+
space: space.key,
|
|
586
|
+
trigger
|
|
587
|
+
}, {
|
|
588
|
+
F: __dxlog_file3,
|
|
589
|
+
L: 271,
|
|
590
|
+
S: this,
|
|
591
|
+
C: (f, a) => f(...a)
|
|
1001
592
|
});
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
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
|
+
});
|
|
599
|
+
});
|
|
600
|
+
const subscriptions = [];
|
|
601
|
+
const subscription = createSubscription(({ added, updated }) => {
|
|
602
|
+
log3.info("updated", {
|
|
603
|
+
added: added.length,
|
|
604
|
+
updated: updated.length
|
|
605
|
+
}, {
|
|
606
|
+
F: __dxlog_file3,
|
|
607
|
+
L: 281,
|
|
1013
608
|
S: this,
|
|
1014
609
|
C: (f, a) => f(...a)
|
|
1015
610
|
});
|
|
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);
|
|
611
|
+
for (const object of added) {
|
|
612
|
+
objectIds.add(object.id);
|
|
1030
613
|
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
614
|
+
for (const object of updated) {
|
|
615
|
+
objectIds.add(object.id);
|
|
616
|
+
}
|
|
617
|
+
task.schedule();
|
|
618
|
+
});
|
|
619
|
+
subscriptions.push(() => subscription.unsubscribe());
|
|
620
|
+
const { filter, options: { deep, delay } = {} } = trigger;
|
|
621
|
+
const update = ({ objects }) => {
|
|
622
|
+
subscription.update(objects);
|
|
623
|
+
if (deep) {
|
|
624
|
+
log3.info("update", {
|
|
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
|
+
}
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
const query = space.db.query(Filter.or(filter.map(({ type, props }) => Filter.typename(type, props))));
|
|
643
|
+
subscriptions.push(query.subscribe(delay ? debounce(update, delay) : update));
|
|
644
|
+
ctx.onDispose(() => {
|
|
645
|
+
subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
646
|
+
});
|
|
1042
647
|
}
|
|
1043
648
|
};
|
|
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
|
+
});
|
|
1044
694
|
export {
|
|
1045
695
|
DevServer,
|
|
1046
|
-
FunctionDef,
|
|
1047
696
|
FunctionManifestSchema,
|
|
1048
|
-
FunctionRegistry,
|
|
1049
|
-
FunctionTrigger,
|
|
1050
697
|
Scheduler,
|
|
1051
|
-
TriggerRegistry,
|
|
1052
698
|
subscriptionHandler
|
|
1053
699
|
};
|
|
1054
700
|
//# sourceMappingURL=index.mjs.map
|