@dxos/functions 0.5.3-main.d7fe7b5 → 0.5.3-main.e38fceb

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