@dxos/functions 0.5.3-main.cb47aab → 0.5.3-main.d3c5e1f

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