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