@dxos/functions 0.5.3-main.2ad0afc → 0.5.3-main.3456876
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 +490 -712
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +483 -695
- 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 -32
- 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 +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 +112 -140
- package/src/handler.ts +27 -50
- package/src/index.ts +0 -2
- package/src/runtime/dev-server.test.ts +35 -15
- package/src/runtime/dev-server.ts +24 -41
- package/src/runtime/scheduler.test.ts +75 -54
- package/src/runtime/scheduler.ts +300 -75
- package/src/testing/test/handler.ts +2 -8
- package/src/types.ts +40 -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,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.spaceKey ? client.spaces.get(PublicKey.from(event.spaceKey)) : void 0;
|
|
26
|
+
const objects = space && event.objects?.map((id) => space.db.getObjectById(id)).filter(nonNullable);
|
|
27
|
+
if (!!event.spaceKey && !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,32 +59,18 @@ 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 { Event
|
|
157
|
-
import { Context } from "@dxos/context";
|
|
62
|
+
import { Event, 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
|
|
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
|
-
});
|
|
73
|
+
this.update = new Event();
|
|
182
74
|
}
|
|
183
75
|
get stats() {
|
|
184
76
|
return {
|
|
@@ -187,8 +79,8 @@ var DevServer = class {
|
|
|
187
79
|
}
|
|
188
80
|
get endpoint() {
|
|
189
81
|
invariant(this._port, void 0, {
|
|
190
|
-
F:
|
|
191
|
-
L:
|
|
82
|
+
F: __dxlog_file2,
|
|
83
|
+
L: 54,
|
|
192
84
|
S: this,
|
|
193
85
|
A: [
|
|
194
86
|
"this._port",
|
|
@@ -203,32 +95,45 @@ var DevServer = class {
|
|
|
203
95
|
get functions() {
|
|
204
96
|
return Object.values(this._handlers);
|
|
205
97
|
}
|
|
98
|
+
async initialize() {
|
|
99
|
+
for (const def of this._options.manifest.functions) {
|
|
100
|
+
try {
|
|
101
|
+
await this._load(def);
|
|
102
|
+
} catch (err) {
|
|
103
|
+
log2.error("parsing function (check manifest)", err, {
|
|
104
|
+
F: __dxlog_file2,
|
|
105
|
+
L: 71,
|
|
106
|
+
S: this,
|
|
107
|
+
C: (f, a) => f(...a)
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
206
112
|
async start() {
|
|
207
113
|
invariant(!this._server, void 0, {
|
|
208
|
-
F:
|
|
209
|
-
L:
|
|
114
|
+
F: __dxlog_file2,
|
|
115
|
+
L: 77,
|
|
210
116
|
S: this,
|
|
211
117
|
A: [
|
|
212
118
|
"!this._server",
|
|
213
119
|
""
|
|
214
120
|
]
|
|
215
121
|
});
|
|
216
|
-
|
|
217
|
-
F:
|
|
218
|
-
L:
|
|
122
|
+
log2.info("starting...", void 0, {
|
|
123
|
+
F: __dxlog_file2,
|
|
124
|
+
L: 78,
|
|
219
125
|
S: this,
|
|
220
126
|
C: (f, a) => f(...a)
|
|
221
127
|
});
|
|
222
|
-
this._ctx = createContext();
|
|
223
128
|
const app = express();
|
|
224
129
|
app.use(express.json());
|
|
225
130
|
app.post("/:path", async (req, res) => {
|
|
226
131
|
const { path: path2 } = req.params;
|
|
227
132
|
try {
|
|
228
|
-
|
|
133
|
+
log2.info("calling", {
|
|
229
134
|
path: path2
|
|
230
135
|
}, {
|
|
231
|
-
F:
|
|
136
|
+
F: __dxlog_file2,
|
|
232
137
|
L: 87,
|
|
233
138
|
S: this,
|
|
234
139
|
C: (f, a) => f(...a)
|
|
@@ -240,8 +145,8 @@ var DevServer = class {
|
|
|
240
145
|
res.statusCode = await this.invoke("/" + path2, req.body);
|
|
241
146
|
res.end();
|
|
242
147
|
} catch (err) {
|
|
243
|
-
|
|
244
|
-
F:
|
|
148
|
+
log2.catch(err, void 0, {
|
|
149
|
+
F: __dxlog_file2,
|
|
245
150
|
L: 97,
|
|
246
151
|
S: this,
|
|
247
152
|
C: (f, a) => f(...a)
|
|
@@ -261,61 +166,64 @@ var DevServer = class {
|
|
|
261
166
|
this._server = app.listen(this._port);
|
|
262
167
|
try {
|
|
263
168
|
const { registrationId, endpoint } = await this._client.services.services.FunctionRegistryService.register({
|
|
264
|
-
endpoint: this.endpoint
|
|
169
|
+
endpoint: this.endpoint,
|
|
170
|
+
functions: this.functions.map(({ def: { id, path: path2 } }) => ({
|
|
171
|
+
id,
|
|
172
|
+
path: path2
|
|
173
|
+
}))
|
|
265
174
|
});
|
|
266
|
-
|
|
175
|
+
log2.info("registered", {
|
|
267
176
|
endpoint
|
|
268
177
|
}, {
|
|
269
|
-
F:
|
|
270
|
-
L:
|
|
178
|
+
F: __dxlog_file2,
|
|
179
|
+
L: 113,
|
|
271
180
|
S: this,
|
|
272
181
|
C: (f, a) => f(...a)
|
|
273
182
|
});
|
|
274
183
|
this._proxy = endpoint;
|
|
275
184
|
this._functionServiceRegistration = registrationId;
|
|
276
|
-
await this._functionsRegistry.open(this._ctx);
|
|
277
185
|
} catch (err) {
|
|
278
186
|
await this.stop();
|
|
279
187
|
throw new Error("FunctionRegistryService not available (check plugin is configured).");
|
|
280
188
|
}
|
|
281
|
-
|
|
189
|
+
log2.info("started", {
|
|
282
190
|
port: this._port
|
|
283
191
|
}, {
|
|
284
|
-
F:
|
|
285
|
-
L:
|
|
192
|
+
F: __dxlog_file2,
|
|
193
|
+
L: 121,
|
|
286
194
|
S: this,
|
|
287
195
|
C: (f, a) => f(...a)
|
|
288
196
|
});
|
|
289
197
|
}
|
|
290
198
|
async stop() {
|
|
291
199
|
invariant(this._server, void 0, {
|
|
292
|
-
F:
|
|
293
|
-
L:
|
|
200
|
+
F: __dxlog_file2,
|
|
201
|
+
L: 125,
|
|
294
202
|
S: this,
|
|
295
203
|
A: [
|
|
296
204
|
"this._server",
|
|
297
205
|
""
|
|
298
206
|
]
|
|
299
207
|
});
|
|
300
|
-
|
|
301
|
-
F:
|
|
302
|
-
L:
|
|
208
|
+
log2.info("stopping...", void 0, {
|
|
209
|
+
F: __dxlog_file2,
|
|
210
|
+
L: 126,
|
|
303
211
|
S: this,
|
|
304
212
|
C: (f, a) => f(...a)
|
|
305
213
|
});
|
|
306
214
|
const trigger = new Trigger();
|
|
307
215
|
this._server.close(async () => {
|
|
308
|
-
|
|
309
|
-
F:
|
|
310
|
-
L:
|
|
216
|
+
log2.info("server stopped", void 0, {
|
|
217
|
+
F: __dxlog_file2,
|
|
218
|
+
L: 130,
|
|
311
219
|
S: this,
|
|
312
220
|
C: (f, a) => f(...a)
|
|
313
221
|
});
|
|
314
222
|
try {
|
|
315
223
|
if (this._functionServiceRegistration) {
|
|
316
224
|
invariant(this._client.services.services.FunctionRegistryService, void 0, {
|
|
317
|
-
F:
|
|
318
|
-
L:
|
|
225
|
+
F: __dxlog_file2,
|
|
226
|
+
L: 133,
|
|
319
227
|
S: this,
|
|
320
228
|
A: [
|
|
321
229
|
"this._client.services.services.FunctionRegistryService",
|
|
@@ -325,11 +233,11 @@ var DevServer = class {
|
|
|
325
233
|
await this._client.services.services.FunctionRegistryService.unregister({
|
|
326
234
|
registrationId: this._functionServiceRegistration
|
|
327
235
|
});
|
|
328
|
-
|
|
236
|
+
log2.info("unregistered", {
|
|
329
237
|
registrationId: this._functionServiceRegistration
|
|
330
238
|
}, {
|
|
331
|
-
F:
|
|
332
|
-
L:
|
|
239
|
+
F: __dxlog_file2,
|
|
240
|
+
L: 138,
|
|
333
241
|
S: this,
|
|
334
242
|
C: (f, a) => f(...a)
|
|
335
243
|
});
|
|
@@ -344,9 +252,9 @@ var DevServer = class {
|
|
|
344
252
|
await trigger.wait();
|
|
345
253
|
this._port = void 0;
|
|
346
254
|
this._server = void 0;
|
|
347
|
-
|
|
348
|
-
F:
|
|
349
|
-
L:
|
|
255
|
+
log2.info("stopped", void 0, {
|
|
256
|
+
F: __dxlog_file2,
|
|
257
|
+
L: 152,
|
|
350
258
|
S: this,
|
|
351
259
|
C: (f, a) => f(...a)
|
|
352
260
|
});
|
|
@@ -354,15 +262,15 @@ var DevServer = class {
|
|
|
354
262
|
/**
|
|
355
263
|
* Load function.
|
|
356
264
|
*/
|
|
357
|
-
async _load(def, force) {
|
|
358
|
-
const {
|
|
265
|
+
async _load(def, force = false) {
|
|
266
|
+
const { id, path: path2, handler } = def;
|
|
359
267
|
const filePath = join(this._options.baseDir, handler);
|
|
360
|
-
|
|
361
|
-
|
|
268
|
+
log2.info("loading", {
|
|
269
|
+
id,
|
|
362
270
|
force
|
|
363
271
|
}, {
|
|
364
|
-
F:
|
|
365
|
-
L:
|
|
272
|
+
F: __dxlog_file2,
|
|
273
|
+
L: 161,
|
|
366
274
|
S: this,
|
|
367
275
|
C: (f, a) => f(...a)
|
|
368
276
|
});
|
|
@@ -373,66 +281,37 @@ var DevServer = class {
|
|
|
373
281
|
}
|
|
374
282
|
const module = __require(filePath);
|
|
375
283
|
if (typeof module.default !== "function") {
|
|
376
|
-
throw new Error(`Handler must export default function: ${
|
|
284
|
+
throw new Error(`Handler must export default function: ${id}`);
|
|
377
285
|
}
|
|
378
|
-
this._handlers[
|
|
286
|
+
this._handlers[path2] = {
|
|
379
287
|
def,
|
|
380
288
|
handler: module.default
|
|
381
289
|
};
|
|
382
290
|
}
|
|
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
291
|
/**
|
|
411
292
|
* Invoke function.
|
|
412
293
|
*/
|
|
413
294
|
async invoke(path2, data) {
|
|
414
295
|
const seq = ++this._seq;
|
|
415
296
|
const now = Date.now();
|
|
416
|
-
|
|
297
|
+
log2.info("req", {
|
|
417
298
|
seq,
|
|
418
299
|
path: path2
|
|
419
300
|
}, {
|
|
420
|
-
F:
|
|
421
|
-
L:
|
|
301
|
+
F: __dxlog_file2,
|
|
302
|
+
L: 188,
|
|
422
303
|
S: this,
|
|
423
304
|
C: (f, a) => f(...a)
|
|
424
305
|
});
|
|
425
|
-
const statusCode = await this._invoke(path2,
|
|
426
|
-
|
|
427
|
-
});
|
|
428
|
-
log3.info("res", {
|
|
306
|
+
const statusCode = await this._invoke(path2, data);
|
|
307
|
+
log2.info("res", {
|
|
429
308
|
seq,
|
|
430
309
|
path: path2,
|
|
431
310
|
statusCode,
|
|
432
311
|
duration: Date.now() - now
|
|
433
312
|
}, {
|
|
434
|
-
F:
|
|
435
|
-
L:
|
|
313
|
+
F: __dxlog_file2,
|
|
314
|
+
L: 191,
|
|
436
315
|
S: this,
|
|
437
316
|
C: (f, a) => f(...a)
|
|
438
317
|
});
|
|
@@ -442,8 +321,8 @@ var DevServer = class {
|
|
|
442
321
|
async _invoke(path2, event) {
|
|
443
322
|
const { handler } = this._handlers[path2] ?? {};
|
|
444
323
|
invariant(handler, `invalid path: ${path2}`, {
|
|
445
|
-
F:
|
|
446
|
-
L:
|
|
324
|
+
F: __dxlog_file2,
|
|
325
|
+
L: 198,
|
|
447
326
|
S: this,
|
|
448
327
|
A: [
|
|
449
328
|
"handler",
|
|
@@ -469,104 +348,123 @@ var DevServer = class {
|
|
|
469
348
|
return statusCode;
|
|
470
349
|
}
|
|
471
350
|
};
|
|
472
|
-
var createContext = () => new Context({
|
|
473
|
-
name: "DevServer"
|
|
474
|
-
});
|
|
475
351
|
|
|
476
352
|
// packages/core/functions/src/runtime/scheduler.ts
|
|
353
|
+
import { CronJob } from "cron";
|
|
354
|
+
import { getPort as getPort2 } from "get-port-please";
|
|
355
|
+
import http from "@dxos/node-std/http";
|
|
477
356
|
import path from "@dxos/node-std/path";
|
|
478
|
-
import
|
|
479
|
-
import {
|
|
480
|
-
import {
|
|
481
|
-
|
|
357
|
+
import WebSocket from "ws";
|
|
358
|
+
import { TextV0Type } from "@braneframe/types";
|
|
359
|
+
import { debounce, DeferredTask, sleep, Trigger as Trigger2 } from "@dxos/async";
|
|
360
|
+
import { createSubscription, Filter, getAutomergeObjectCore } from "@dxos/client/echo";
|
|
361
|
+
import { Context } from "@dxos/context";
|
|
362
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
363
|
+
import { log as log3 } from "@dxos/log";
|
|
364
|
+
import { ComplexMap } from "@dxos/util";
|
|
365
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/scheduler.ts";
|
|
482
366
|
var Scheduler = class {
|
|
483
|
-
constructor(
|
|
484
|
-
this.
|
|
485
|
-
this.
|
|
367
|
+
constructor(_client, _manifest, _options = {}) {
|
|
368
|
+
this._client = _client;
|
|
369
|
+
this._manifest = _manifest;
|
|
486
370
|
this._options = _options;
|
|
487
|
-
this.
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
});
|
|
371
|
+
this._mounts = new ComplexMap(({ spaceKey, id }) => `${spaceKey.toHex()}:${id}`);
|
|
372
|
+
}
|
|
373
|
+
get mounts() {
|
|
374
|
+
return Array.from(this._mounts.values()).reduce((acc, { trigger }) => {
|
|
375
|
+
acc.push(trigger);
|
|
376
|
+
return acc;
|
|
377
|
+
}, []);
|
|
495
378
|
}
|
|
496
379
|
async start() {
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
380
|
+
this._client.spaces.subscribe(async (spaces) => {
|
|
381
|
+
for (const space of spaces) {
|
|
382
|
+
await space.waitUntilReady();
|
|
383
|
+
for (const trigger of this._manifest.triggers ?? []) {
|
|
384
|
+
await this.mount(new Context(), space, trigger);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
});
|
|
501
388
|
}
|
|
502
389
|
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);
|
|
390
|
+
for (const { id, spaceKey } of this._mounts.keys()) {
|
|
391
|
+
await this.unmount(id, spaceKey);
|
|
392
|
+
}
|
|
511
393
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
394
|
+
/**
|
|
395
|
+
* Mount trigger.
|
|
396
|
+
*/
|
|
397
|
+
async mount(ctx, space, trigger) {
|
|
398
|
+
const key = {
|
|
399
|
+
spaceKey: space.key,
|
|
400
|
+
id: trigger.function
|
|
401
|
+
};
|
|
402
|
+
const def = this._manifest.functions.find((config) => config.id === trigger.function);
|
|
403
|
+
invariant2(def, `Function not found: ${trigger.function}`, {
|
|
404
|
+
F: __dxlog_file3,
|
|
405
|
+
L: 83,
|
|
406
|
+
S: this,
|
|
407
|
+
A: [
|
|
408
|
+
"def",
|
|
409
|
+
"`Function not found: ${trigger.function}`"
|
|
410
|
+
]
|
|
515
411
|
});
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
412
|
+
const exists = this._mounts.get(key);
|
|
413
|
+
if (!exists) {
|
|
414
|
+
this._mounts.set(key, {
|
|
415
|
+
ctx,
|
|
416
|
+
trigger
|
|
417
|
+
});
|
|
418
|
+
log3("mount", {
|
|
419
|
+
space: space.key,
|
|
420
|
+
trigger
|
|
523
421
|
}, {
|
|
524
|
-
F:
|
|
525
|
-
L:
|
|
422
|
+
F: __dxlog_file3,
|
|
423
|
+
L: 89,
|
|
526
424
|
S: this,
|
|
527
425
|
C: (f, a) => f(...a)
|
|
528
426
|
});
|
|
529
|
-
|
|
427
|
+
if (ctx.disposed) {
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
if (trigger.timer) {
|
|
431
|
+
await this._createTimer(ctx, space, def, trigger.timer);
|
|
432
|
+
}
|
|
433
|
+
if (trigger.webhook) {
|
|
434
|
+
await this._createWebhook(ctx, space, def, trigger.webhook);
|
|
435
|
+
}
|
|
436
|
+
if (trigger.websocket) {
|
|
437
|
+
await this._createWebsocket(ctx, space, def, trigger.websocket);
|
|
438
|
+
}
|
|
439
|
+
if (trigger.subscription) {
|
|
440
|
+
await this._createSubscription(ctx, space, def, trigger.subscription);
|
|
441
|
+
}
|
|
530
442
|
}
|
|
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
443
|
}
|
|
554
|
-
async
|
|
555
|
-
|
|
444
|
+
async unmount(id, spaceKey) {
|
|
445
|
+
const key = {
|
|
446
|
+
id,
|
|
447
|
+
spaceKey
|
|
448
|
+
};
|
|
449
|
+
const { ctx } = this._mounts.get(key) ?? {};
|
|
450
|
+
if (ctx) {
|
|
451
|
+
this._mounts.delete(key);
|
|
452
|
+
await ctx.dispose();
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
// TODO(burdon): Pass in Space key (common context).
|
|
456
|
+
async _execFunction(def, data) {
|
|
556
457
|
try {
|
|
557
|
-
|
|
558
|
-
meta
|
|
559
|
-
}, data);
|
|
458
|
+
let status = 0;
|
|
560
459
|
const { endpoint, callback } = this._options;
|
|
561
460
|
if (endpoint) {
|
|
562
|
-
const url = path.join(endpoint, def.
|
|
563
|
-
|
|
564
|
-
function: def.
|
|
565
|
-
url
|
|
566
|
-
triggerType: trigger.spec.type
|
|
461
|
+
const url = path.join(endpoint, def.path);
|
|
462
|
+
log3.info("exec", {
|
|
463
|
+
function: def.id,
|
|
464
|
+
url
|
|
567
465
|
}, {
|
|
568
|
-
F:
|
|
569
|
-
L:
|
|
466
|
+
F: __dxlog_file3,
|
|
467
|
+
L: 133,
|
|
570
468
|
S: this,
|
|
571
469
|
C: (f, a) => f(...a)
|
|
572
470
|
});
|
|
@@ -575,480 +473,360 @@ var Scheduler = class {
|
|
|
575
473
|
headers: {
|
|
576
474
|
"Content-Type": "application/json"
|
|
577
475
|
},
|
|
578
|
-
body: JSON.stringify(
|
|
476
|
+
body: JSON.stringify(data)
|
|
579
477
|
});
|
|
580
478
|
status = response.status;
|
|
581
479
|
} else if (callback) {
|
|
582
|
-
|
|
583
|
-
function: def.
|
|
480
|
+
log3.info("exec", {
|
|
481
|
+
function: def.id
|
|
584
482
|
}, {
|
|
585
|
-
F:
|
|
586
|
-
L:
|
|
483
|
+
F: __dxlog_file3,
|
|
484
|
+
L: 144,
|
|
587
485
|
S: this,
|
|
588
486
|
C: (f, a) => f(...a)
|
|
589
487
|
});
|
|
590
|
-
status = await callback(
|
|
488
|
+
status = await callback(data) ?? 200;
|
|
591
489
|
}
|
|
592
490
|
if (status && status >= 400) {
|
|
593
491
|
throw new Error(`Response: ${status}`);
|
|
594
492
|
}
|
|
595
|
-
|
|
596
|
-
function: def.
|
|
493
|
+
log3.info("done", {
|
|
494
|
+
function: def.id,
|
|
597
495
|
status
|
|
598
496
|
}, {
|
|
599
|
-
F:
|
|
600
|
-
L:
|
|
497
|
+
F: __dxlog_file3,
|
|
498
|
+
L: 154,
|
|
601
499
|
S: this,
|
|
602
500
|
C: (f, a) => f(...a)
|
|
603
501
|
});
|
|
502
|
+
return status;
|
|
604
503
|
} catch (err) {
|
|
605
|
-
|
|
606
|
-
function: def.
|
|
504
|
+
log3.error("error", {
|
|
505
|
+
function: def.id,
|
|
607
506
|
error: err.message
|
|
608
507
|
}, {
|
|
609
|
-
F:
|
|
610
|
-
L:
|
|
508
|
+
F: __dxlog_file3,
|
|
509
|
+
L: 157,
|
|
611
510
|
S: this,
|
|
612
511
|
C: (f, a) => f(...a)
|
|
613
512
|
});
|
|
614
|
-
|
|
513
|
+
return 500;
|
|
615
514
|
}
|
|
616
|
-
return status;
|
|
617
515
|
}
|
|
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
|
|
516
|
+
//
|
|
517
|
+
// Triggers
|
|
518
|
+
//
|
|
519
|
+
/**
|
|
520
|
+
* Cron timer.
|
|
521
|
+
*/
|
|
522
|
+
async _createTimer(ctx, space, def, trigger) {
|
|
523
|
+
log3.info("timer", {
|
|
524
|
+
space: space.key,
|
|
525
|
+
trigger
|
|
760
526
|
}, {
|
|
761
|
-
F:
|
|
762
|
-
L:
|
|
763
|
-
S:
|
|
527
|
+
F: __dxlog_file3,
|
|
528
|
+
L: 170,
|
|
529
|
+
S: this,
|
|
764
530
|
C: (f, a) => f(...a)
|
|
765
531
|
});
|
|
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
|
-
}
|
|
532
|
+
const { cron } = trigger;
|
|
533
|
+
const task = new DeferredTask(ctx, async () => {
|
|
534
|
+
await this._execFunction(def, {
|
|
535
|
+
spaceKey: space.key
|
|
536
|
+
});
|
|
860
537
|
});
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
538
|
+
let last = 0;
|
|
539
|
+
let run = 0;
|
|
540
|
+
const job = CronJob.from({
|
|
541
|
+
cronTime: cron,
|
|
542
|
+
runOnInit: false,
|
|
543
|
+
onTick: () => {
|
|
544
|
+
const now = Date.now();
|
|
545
|
+
const delta = last ? now - last : 0;
|
|
546
|
+
last = now;
|
|
547
|
+
run++;
|
|
548
|
+
log3.info("tick", {
|
|
549
|
+
space: space.key.truncate(),
|
|
550
|
+
count: run,
|
|
551
|
+
delta
|
|
869
552
|
}, {
|
|
870
|
-
F:
|
|
871
|
-
L:
|
|
872
|
-
S:
|
|
553
|
+
F: __dxlog_file3,
|
|
554
|
+
L: 190,
|
|
555
|
+
S: this,
|
|
873
556
|
C: (f, a) => f(...a)
|
|
874
557
|
});
|
|
875
|
-
|
|
558
|
+
task.schedule();
|
|
876
559
|
}
|
|
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);
|
|
560
|
+
});
|
|
561
|
+
job.start();
|
|
562
|
+
ctx.onDispose(() => job.stop());
|
|
906
563
|
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
564
|
+
/**
|
|
565
|
+
* Webhook.
|
|
566
|
+
*/
|
|
567
|
+
async _createWebhook(ctx, space, def, trigger) {
|
|
568
|
+
log3.info("webhook", {
|
|
569
|
+
space: space.key,
|
|
910
570
|
trigger
|
|
911
571
|
}, {
|
|
912
|
-
F:
|
|
913
|
-
L:
|
|
572
|
+
F: __dxlog_file3,
|
|
573
|
+
L: 203,
|
|
914
574
|
S: this,
|
|
915
575
|
C: (f, a) => f(...a)
|
|
916
576
|
});
|
|
917
|
-
const
|
|
918
|
-
|
|
577
|
+
const server = http.createServer(async (req, res) => {
|
|
578
|
+
if (req.method !== trigger.method) {
|
|
579
|
+
res.statusCode = 405;
|
|
580
|
+
return res.end();
|
|
581
|
+
}
|
|
582
|
+
res.statusCode = await this._execFunction(def, {
|
|
583
|
+
spaceKey: space.key
|
|
584
|
+
});
|
|
585
|
+
res.end();
|
|
919
586
|
});
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
587
|
+
const port = await getPort2({
|
|
588
|
+
random: true
|
|
589
|
+
});
|
|
590
|
+
server.listen(port, () => {
|
|
591
|
+
log3.info("started webhook", {
|
|
592
|
+
port
|
|
593
|
+
}, {
|
|
594
|
+
F: __dxlog_file3,
|
|
595
|
+
L: 226,
|
|
596
|
+
S: this,
|
|
597
|
+
C: (f, a) => f(...a)
|
|
598
|
+
});
|
|
599
|
+
trigger.port = port;
|
|
600
|
+
});
|
|
601
|
+
ctx.onDispose(() => {
|
|
602
|
+
server.close();
|
|
930
603
|
});
|
|
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
604
|
}
|
|
940
605
|
/**
|
|
941
|
-
*
|
|
606
|
+
* Websocket.
|
|
607
|
+
* NOTE: The port must be unique, so the same hook cannot be used for multiple spaces.
|
|
942
608
|
*/
|
|
943
|
-
async
|
|
944
|
-
|
|
945
|
-
|
|
609
|
+
async _createWebsocket(ctx, space, def, trigger, options = {
|
|
610
|
+
retryDelay: 2,
|
|
611
|
+
maxAttempts: 5
|
|
612
|
+
}) {
|
|
613
|
+
log3.info("websocket", {
|
|
614
|
+
space: space.key,
|
|
615
|
+
trigger
|
|
946
616
|
}, {
|
|
947
|
-
F:
|
|
948
|
-
L:
|
|
617
|
+
F: __dxlog_file3,
|
|
618
|
+
L: 252,
|
|
949
619
|
S: this,
|
|
950
620
|
C: (f, a) => f(...a)
|
|
951
621
|
});
|
|
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
|
-
|
|
622
|
+
const { url } = trigger;
|
|
623
|
+
let ws;
|
|
624
|
+
for (let attempt = 1; attempt <= options.maxAttempts; attempt++) {
|
|
625
|
+
const open = new Trigger2();
|
|
626
|
+
ws = new WebSocket(url);
|
|
627
|
+
Object.assign(ws, {
|
|
628
|
+
onopen: () => {
|
|
629
|
+
log3.info("opened", {
|
|
630
|
+
url
|
|
631
|
+
}, {
|
|
632
|
+
F: __dxlog_file3,
|
|
633
|
+
L: 262,
|
|
634
|
+
S: this,
|
|
635
|
+
C: (f, a) => f(...a)
|
|
636
|
+
});
|
|
637
|
+
if (trigger.init) {
|
|
638
|
+
ws.send(new TextEncoder().encode(JSON.stringify(trigger.init)));
|
|
639
|
+
}
|
|
640
|
+
open.wake(true);
|
|
641
|
+
},
|
|
642
|
+
// TODO(burdon): Config retry if server closes?
|
|
643
|
+
onclose: (event) => {
|
|
644
|
+
log3.info("closed", {
|
|
645
|
+
url,
|
|
646
|
+
code: event.code
|
|
647
|
+
}, {
|
|
648
|
+
F: __dxlog_file3,
|
|
649
|
+
L: 272,
|
|
650
|
+
S: this,
|
|
651
|
+
C: (f, a) => f(...a)
|
|
652
|
+
});
|
|
653
|
+
open.wake(false);
|
|
654
|
+
},
|
|
655
|
+
onerror: (event) => {
|
|
656
|
+
log3.catch(event.error, {
|
|
657
|
+
url
|
|
658
|
+
}, {
|
|
659
|
+
F: __dxlog_file3,
|
|
660
|
+
L: 277,
|
|
661
|
+
S: this,
|
|
662
|
+
C: (f, a) => f(...a)
|
|
663
|
+
});
|
|
664
|
+
},
|
|
665
|
+
onmessage: async (event) => {
|
|
666
|
+
try {
|
|
667
|
+
const data = JSON.parse(new TextDecoder().decode(event.data));
|
|
668
|
+
await this._execFunction(def, {
|
|
669
|
+
spaceKey: space.key,
|
|
670
|
+
data
|
|
671
|
+
});
|
|
672
|
+
} catch (err) {
|
|
673
|
+
log3.catch(err, {
|
|
674
|
+
url
|
|
675
|
+
}, {
|
|
676
|
+
F: __dxlog_file3,
|
|
677
|
+
L: 285,
|
|
678
|
+
S: this,
|
|
679
|
+
C: (f, a) => f(...a)
|
|
680
|
+
});
|
|
681
|
+
}
|
|
979
682
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
683
|
+
});
|
|
684
|
+
const isOpen = await open.wait();
|
|
685
|
+
if (isOpen) {
|
|
686
|
+
break;
|
|
687
|
+
} else {
|
|
688
|
+
const wait = Math.pow(attempt, 2) * options.retryDelay;
|
|
689
|
+
if (attempt < options.maxAttempts) {
|
|
690
|
+
log3.warn(`failed to connect; trying again in ${wait}s`, {
|
|
691
|
+
attempt
|
|
692
|
+
}, {
|
|
693
|
+
F: __dxlog_file3,
|
|
694
|
+
L: 296,
|
|
695
|
+
S: this,
|
|
696
|
+
C: (f, a) => f(...a)
|
|
697
|
+
});
|
|
698
|
+
await sleep(wait * 1e3);
|
|
985
699
|
}
|
|
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
700
|
}
|
|
701
|
+
}
|
|
702
|
+
ctx.onDispose(() => {
|
|
703
|
+
ws?.close();
|
|
992
704
|
});
|
|
993
|
-
this._ctx.onDispose(() => spaceListSubscription.unsubscribe());
|
|
994
|
-
}
|
|
995
|
-
async _close(_) {
|
|
996
|
-
this._triggersBySpaceKey.clear();
|
|
997
705
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
706
|
+
/**
|
|
707
|
+
* ECHO subscription.
|
|
708
|
+
*/
|
|
709
|
+
async _createSubscription(ctx, space, def, trigger) {
|
|
710
|
+
log3.info("subscription", {
|
|
711
|
+
space: space.key,
|
|
712
|
+
trigger
|
|
713
|
+
}, {
|
|
714
|
+
F: __dxlog_file3,
|
|
715
|
+
L: 311,
|
|
716
|
+
S: this,
|
|
717
|
+
C: (f, a) => f(...a)
|
|
1001
718
|
});
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
}));
|
|
1006
|
-
registered.push(...newRegisteredTriggers);
|
|
1007
|
-
log9("registered new triggers", () => ({
|
|
719
|
+
const objectIds = /* @__PURE__ */ new Set();
|
|
720
|
+
const task = new DeferredTask(ctx, async () => {
|
|
721
|
+
await this._execFunction(def, {
|
|
1008
722
|
spaceKey: space.key,
|
|
1009
|
-
|
|
1010
|
-
})
|
|
1011
|
-
|
|
1012
|
-
|
|
723
|
+
objects: Array.from(objectIds)
|
|
724
|
+
});
|
|
725
|
+
});
|
|
726
|
+
const subscriptions = [];
|
|
727
|
+
const subscription = createSubscription(({ added, updated }) => {
|
|
728
|
+
log3.info("updated", {
|
|
729
|
+
added: added.length,
|
|
730
|
+
updated: updated.length
|
|
731
|
+
}, {
|
|
732
|
+
F: __dxlog_file3,
|
|
733
|
+
L: 321,
|
|
1013
734
|
S: this,
|
|
1014
735
|
C: (f, a) => f(...a)
|
|
1015
736
|
});
|
|
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);
|
|
737
|
+
for (const object of added) {
|
|
738
|
+
objectIds.add(object.id);
|
|
1030
739
|
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
740
|
+
for (const object of updated) {
|
|
741
|
+
objectIds.add(object.id);
|
|
742
|
+
}
|
|
743
|
+
task.schedule();
|
|
744
|
+
});
|
|
745
|
+
subscriptions.push(() => subscription.unsubscribe());
|
|
746
|
+
const { filter, options: { deep, delay } = {} } = trigger;
|
|
747
|
+
const update = ({ objects }) => {
|
|
748
|
+
subscription.update(objects);
|
|
749
|
+
if (deep) {
|
|
750
|
+
log3.info("update", {
|
|
751
|
+
objects: objects.length
|
|
752
|
+
}, {
|
|
753
|
+
F: __dxlog_file3,
|
|
754
|
+
L: 342,
|
|
755
|
+
S: this,
|
|
756
|
+
C: (f, a) => f(...a)
|
|
757
|
+
});
|
|
758
|
+
for (const object of objects) {
|
|
759
|
+
const content = object.content;
|
|
760
|
+
if (content instanceof TextV0Type) {
|
|
761
|
+
subscriptions.push(getAutomergeObjectCore(content).updates.on(debounce(() => subscription.update([
|
|
762
|
+
object
|
|
763
|
+
]), 1e3)));
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
};
|
|
768
|
+
const query = space.db.query(Filter.or(filter.map(({ type, props }) => Filter.typename(type, props))));
|
|
769
|
+
subscriptions.push(query.subscribe(delay ? debounce(update, delay) : update));
|
|
770
|
+
ctx.onDispose(() => {
|
|
771
|
+
subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
772
|
+
});
|
|
1042
773
|
}
|
|
1043
774
|
};
|
|
775
|
+
|
|
776
|
+
// packages/core/functions/src/types.ts
|
|
777
|
+
import * as S from "@effect/schema/Schema";
|
|
778
|
+
var TimerTriggerSchema = S.struct({
|
|
779
|
+
cron: S.string
|
|
780
|
+
});
|
|
781
|
+
var WebhookTriggerSchema = S.mutable(S.struct({
|
|
782
|
+
method: S.string,
|
|
783
|
+
// Assigned port.
|
|
784
|
+
port: S.optional(S.number)
|
|
785
|
+
}));
|
|
786
|
+
var WebsocketTriggerSchema = S.struct({
|
|
787
|
+
url: S.string,
|
|
788
|
+
init: S.optional(S.record(S.string, S.any))
|
|
789
|
+
});
|
|
790
|
+
var SubscriptionTriggerSchema = S.struct({
|
|
791
|
+
spaceKey: S.optional(S.string),
|
|
792
|
+
// TODO(burdon): Define query DSL.
|
|
793
|
+
filter: S.array(S.struct({
|
|
794
|
+
type: S.string,
|
|
795
|
+
props: S.optional(S.record(S.string, S.any))
|
|
796
|
+
})),
|
|
797
|
+
options: S.optional(S.struct({
|
|
798
|
+
// Watch changes to object (not just creation).
|
|
799
|
+
deep: S.optional(S.boolean),
|
|
800
|
+
// Debounce changes (delay in ms).
|
|
801
|
+
delay: S.optional(S.number)
|
|
802
|
+
}))
|
|
803
|
+
});
|
|
804
|
+
var FunctionTriggerSchema = S.struct({
|
|
805
|
+
function: S.string.pipe(S.description("Function ID/URI.")),
|
|
806
|
+
// Context passed to function.
|
|
807
|
+
context: S.optional(S.record(S.string, S.any)),
|
|
808
|
+
// Triggers.
|
|
809
|
+
timer: S.optional(TimerTriggerSchema),
|
|
810
|
+
webhook: S.optional(WebhookTriggerSchema),
|
|
811
|
+
websocket: S.optional(WebsocketTriggerSchema),
|
|
812
|
+
subscription: S.optional(SubscriptionTriggerSchema)
|
|
813
|
+
});
|
|
814
|
+
var FunctionDefSchema = S.struct({
|
|
815
|
+
id: S.string,
|
|
816
|
+
// name: S.string,
|
|
817
|
+
description: S.optional(S.string),
|
|
818
|
+
path: S.string,
|
|
819
|
+
// TODO(burdon): NPM/GitHub/Docker/CF URL?
|
|
820
|
+
handler: S.string
|
|
821
|
+
});
|
|
822
|
+
var FunctionManifestSchema = S.struct({
|
|
823
|
+
functions: S.mutable(S.array(FunctionDefSchema)),
|
|
824
|
+
triggers: S.optional(S.mutable(S.array(FunctionTriggerSchema)))
|
|
825
|
+
});
|
|
1044
826
|
export {
|
|
1045
827
|
DevServer,
|
|
1046
|
-
FunctionDef,
|
|
1047
828
|
FunctionManifestSchema,
|
|
1048
|
-
FunctionRegistry,
|
|
1049
|
-
FunctionTrigger,
|
|
1050
829
|
Scheduler,
|
|
1051
|
-
TriggerRegistry,
|
|
1052
830
|
subscriptionHandler
|
|
1053
831
|
};
|
|
1054
832
|
//# sourceMappingURL=index.mjs.map
|