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