@dxos/functions 0.6.10 → 0.6.11-staging.30cf5ba

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