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