@dxos/functions 0.3.9-main.7b9e2ad → 0.3.9-main.8045d90

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.
@@ -17,34 +17,12 @@ import {
17
17
  // packages/core/functions/src/handler.ts
18
18
  import { PublicKey } from "@dxos/client";
19
19
  import { isTypedObject } from "@dxos/echo-schema";
20
- import { log } from "@dxos/log";
21
20
  import { nonNullable } from "@dxos/util";
22
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/functions/src/handler.ts";
23
21
  var subscriptionHandler = (handler) => {
24
22
  return ({ event, context, ...rest }) => {
25
23
  const { client } = context;
26
24
  const space = event.space ? client.spaces.get(PublicKey.from(event.space)) : void 0;
27
25
  const objects = space && event.objects?.map((id) => space.db.getObjectById(id)).filter(nonNullable).filter(isTypedObject);
28
- if (!!event.space && !space) {
29
- log.warn("invalid space", {
30
- event
31
- }, {
32
- F: __dxlog_file,
33
- L: 64,
34
- S: void 0,
35
- C: (f, a) => f(...a)
36
- });
37
- } else {
38
- log.info("handler", {
39
- space: space?.key.truncate(),
40
- objects: objects?.length
41
- }, {
42
- F: __dxlog_file,
43
- L: 66,
44
- S: void 0,
45
- C: (f, a) => f(...a)
46
- });
47
- }
48
26
  return handler({
49
27
  event: {
50
28
  space,
@@ -62,8 +40,8 @@ import { getPort } from "get-port-please";
62
40
  import { join } from "@dxos/node-std/path";
63
41
  import { Trigger } from "@dxos/async";
64
42
  import { invariant } from "@dxos/invariant";
65
- import { log as log2 } from "@dxos/log";
66
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/dev-server.ts";
43
+ import { log } from "@dxos/log";
44
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/dev-server.ts";
67
45
  var DevServer = class {
68
46
  // prettier-ignore
69
47
  constructor(_client, _options) {
@@ -74,7 +52,7 @@ var DevServer = class {
74
52
  }
75
53
  get endpoint() {
76
54
  invariant(this._port, void 0, {
77
- F: __dxlog_file2,
55
+ F: __dxlog_file,
78
56
  L: 46,
79
57
  S: this,
80
58
  A: [
@@ -95,8 +73,8 @@ var DevServer = class {
95
73
  try {
96
74
  await this._load(def);
97
75
  } catch (err) {
98
- log2.error("parsing function (check manifest)", err, {
99
- F: __dxlog_file2,
76
+ log.error("parsing function (check manifest)", err, {
77
+ F: __dxlog_file,
100
78
  L: 63,
101
79
  S: this,
102
80
  C: (f, a) => f(...a)
@@ -117,8 +95,8 @@ var DevServer = class {
117
95
  res.statusCode = await this._invoke(name, req.body);
118
96
  res.end();
119
97
  } catch (err) {
120
- log2.error(`Function failed: ${name}`, err, {
121
- F: __dxlog_file2,
98
+ log.catch(err, void 0, {
99
+ F: __dxlog_file,
122
100
  L: 83,
123
101
  S: this,
124
102
  C: (f, a) => f(...a)
@@ -143,11 +121,11 @@ var DevServer = class {
143
121
  name
144
122
  }))
145
123
  });
146
- log2.info("registered", {
124
+ log.info("registered", {
147
125
  registrationId,
148
126
  endpoint
149
127
  }, {
150
- F: __dxlog_file2,
128
+ F: __dxlog_file,
151
129
  L: 99,
152
130
  S: this,
153
131
  C: (f, a) => f(...a)
@@ -166,10 +144,10 @@ var DevServer = class {
166
144
  await this._client.services.services.FunctionRegistryService.unregister({
167
145
  registrationId: this._registrationId
168
146
  });
169
- log2.info("unregistered", {
147
+ log.info("unregistered", {
170
148
  registrationId: this._registrationId
171
149
  }, {
172
- F: __dxlog_file2,
150
+ F: __dxlog_file,
173
151
  L: 116,
174
152
  S: this,
175
153
  C: (f, a) => f(...a)
@@ -189,10 +167,10 @@ var DevServer = class {
189
167
  async _load(def, flush = false) {
190
168
  const { id, name, handler } = def;
191
169
  const path = join(this._options.directory, handler);
192
- log2.info("loading", {
170
+ log.info("loading", {
193
171
  id
194
172
  }, {
195
- F: __dxlog_file2,
173
+ F: __dxlog_file,
196
174
  L: 135,
197
175
  S: this,
198
176
  C: (f, a) => f(...a)
@@ -215,11 +193,11 @@ var DevServer = class {
215
193
  async _invoke(name, event) {
216
194
  const seq = ++this._seq;
217
195
  const now = Date.now();
218
- log2.info("req", {
196
+ log.info("req", {
219
197
  seq,
220
198
  name
221
199
  }, {
222
- F: __dxlog_file2,
200
+ F: __dxlog_file,
223
201
  L: 160,
224
202
  S: this,
225
203
  C: (f, a) => f(...a)
@@ -241,13 +219,13 @@ var DevServer = class {
241
219
  event,
242
220
  response
243
221
  });
244
- log2.info("res", {
222
+ log.info("res", {
245
223
  seq,
246
224
  name,
247
225
  statusCode,
248
226
  duration: Date.now() - now
249
227
  }, {
250
- F: __dxlog_file2,
228
+ F: __dxlog_file,
251
229
  L: 177,
252
230
  S: this,
253
231
  C: (f, a) => f(...a)
@@ -263,9 +241,9 @@ import { TextObject } from "@dxos/client/echo";
263
241
  import { Context } from "@dxos/context";
264
242
  import { Filter, createSubscription, subscribe } from "@dxos/echo-schema";
265
243
  import { invariant as invariant2 } from "@dxos/invariant";
266
- import { log as log3 } from "@dxos/log";
244
+ import { log as log2 } from "@dxos/log";
267
245
  import { ComplexMap } from "@dxos/util";
268
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/scheduler.ts";
246
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/scheduler.ts";
269
247
  var Scheduler = class {
270
248
  constructor(_client, _manifest, _options = {}) {
271
249
  this._client = _client;
@@ -295,7 +273,7 @@ var Scheduler = class {
295
273
  };
296
274
  const def = this._manifest.functions.find((config) => config.id === trigger.function);
297
275
  invariant2(def, `Function not found: ${trigger.function}`, {
298
- F: __dxlog_file3,
276
+ F: __dxlog_file2,
299
277
  L: 63,
300
278
  S: this,
301
279
  A: [
@@ -309,11 +287,11 @@ var Scheduler = class {
309
287
  ctx,
310
288
  trigger
311
289
  });
312
- log3("mount", {
290
+ log2("mount", {
313
291
  space: space.key,
314
292
  trigger
315
293
  }, {
316
- F: __dxlog_file3,
294
+ F: __dxlog_file2,
317
295
  L: 69,
318
296
  S: this,
319
297
  C: (f, a) => f(...a)
@@ -347,7 +325,7 @@ var Scheduler = class {
347
325
  });
348
326
  });
349
327
  invariant2(trigger.schedule, void 0, {
350
- F: __dxlog_file3,
328
+ F: __dxlog_file2,
351
329
  L: 103,
352
330
  S: this,
353
331
  A: [
@@ -382,13 +360,13 @@ var Scheduler = class {
382
360
  const update = ({ objects }) => {
383
361
  subscription.update(objects);
384
362
  if (deep) {
385
- log3.info("update", {
363
+ log2.info("update", {
386
364
  type,
387
365
  deep,
388
366
  objects: objects.length
389
367
  }, {
390
- F: __dxlog_file3,
391
- L: 142,
368
+ F: __dxlog_file2,
369
+ L: 139,
392
370
  S: this,
393
371
  C: (f, a) => f(...a)
394
372
  });
@@ -410,11 +388,11 @@ var Scheduler = class {
410
388
  }
411
389
  async _execFunction(def, data) {
412
390
  try {
413
- log3("request", {
391
+ log2("request", {
414
392
  function: def.id
415
393
  }, {
416
- F: __dxlog_file3,
417
- L: 164,
394
+ F: __dxlog_file2,
395
+ L: 161,
418
396
  S: this,
419
397
  C: (f, a) => f(...a)
420
398
  });
@@ -432,22 +410,22 @@ var Scheduler = class {
432
410
  } else if (callback) {
433
411
  status = await callback(data);
434
412
  }
435
- log3("result", {
413
+ log2("result", {
436
414
  function: def.id,
437
415
  result: status
438
416
  }, {
439
- F: __dxlog_file3,
440
- L: 183,
417
+ F: __dxlog_file2,
418
+ L: 180,
441
419
  S: this,
442
420
  C: (f, a) => f(...a)
443
421
  });
444
422
  } catch (err) {
445
- log3.error("error", {
423
+ log2.error("error", {
446
424
  function: def.id,
447
425
  error: err.message
448
426
  }, {
449
- F: __dxlog_file3,
450
- L: 185,
427
+ F: __dxlog_file2,
428
+ L: 182,
451
429
  S: this,
452
430
  C: (f, a) => f(...a)
453
431
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/handler.ts", "../../../src/runtime/dev-server.ts", "../../../src/runtime/scheduler.ts"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Client, PublicKey } from '@dxos/client';\nimport { type Space } from '@dxos/client/echo';\nimport { isTypedObject, type TypedObject } from '@dxos/echo-schema';\nimport { log } from '@dxos/log';\nimport { nonNullable } from '@dxos/util';\n\n// TODO(burdon): No response?\nexport interface Response {\n status(code: number): Response;\n}\n\n// TODO(burdon): Limit access to individual space?\nexport interface FunctionContext {\n client: Client;\n dataDir?: string;\n}\n\n// TODO(burdon): Model after http request. Ref Lambda/OpenFaaS.\n// https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html\nexport type FunctionHandler<T extends {}> = (params: {\n event: T;\n context: FunctionContext;\n response: Response;\n}) => Promise<Response | void>;\n\nexport type FunctionSubscriptionEvent = {\n space?: string; // TODO(burdon): Convert to PublicKey.\n objects?: string[];\n};\n\nexport type FunctionSubscriptionEvent2 = {\n space?: Space;\n objects?: TypedObject[];\n};\n\n/**\n * Handler wrapper for subscription events; extracts space and objects.\n *\n * To test:\n * ```\n * curl -s -X POST -H \"Content-Type: application/json\" --data '{\"space\": \"0446...1cbb\"}' http://localhost:7100/dev/email-extractor\n * ```\n *\n * NOTE: Get space key from devtools or `dx space list --json`\n */\nexport const subscriptionHandler = (\n handler: FunctionHandler<FunctionSubscriptionEvent2>,\n): FunctionHandler<FunctionSubscriptionEvent> => {\n return ({ event, context, ...rest }) => {\n const { client } = context;\n const space = event.space ? client.spaces.get(PublicKey.from(event.space)) : undefined;\n const objects =\n space &&\n event.objects\n ?.map<TypedObject | undefined>((id) => space!.db.getObjectById(id))\n .filter(nonNullable)\n .filter(isTypedObject);\n\n if (!!event.space && !space) {\n log.warn('invalid space', { event });\n } else {\n log.info('handler', { space: space?.key.truncate(), objects: objects?.length });\n }\n\n return handler({ event: { space, objects }, context, ...rest });\n };\n};\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport express from 'express';\nimport { getPort } from 'get-port-please';\nimport type http from 'http';\nimport { join } from 'node:path';\n\nimport { Trigger } from '@dxos/async';\nimport { type Client } from '@dxos/client';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\n\nimport { type FunctionContext, type FunctionHandler, type Response } from '../handler';\nimport { type FunctionDef, type FunctionManifest } from '../manifest';\n\nexport type DevServerOptions = {\n port?: number;\n directory: string;\n manifest: FunctionManifest;\n reload?: boolean;\n dataDir?: string;\n};\n\n/**\n * Functions dev server provides a local HTTP server for testing functions.\n */\nexport class DevServer {\n // Function handlers indexed by name (URL path).\n private readonly _handlers: Record<string, { def: FunctionDef; handler: FunctionHandler<any> }> = {};\n\n private _server?: http.Server;\n private _port?: number;\n private _registrationId?: string;\n private _proxy?: string;\n private _seq = 0;\n\n // prettier-ignore\n constructor(\n private readonly _client: Client,\n private readonly _options: DevServerOptions,\n ) {}\n\n get endpoint() {\n invariant(this._port);\n return `http://localhost:${this._port}`;\n }\n\n get proxy() {\n return this._proxy;\n }\n\n get functions() {\n return Object.values(this._handlers);\n }\n\n async initialize() {\n for (const def of this._options.manifest.functions) {\n try {\n await this._load(def);\n } catch (err) {\n log.error('parsing function (check manifest)', err);\n }\n }\n }\n\n async start() {\n const app = express();\n app.use(express.json());\n\n app.post('/:name', async (req, res) => {\n const { name } = req.params;\n try {\n if (this._options.reload) {\n const { def } = this._handlers[name];\n await this._load(def, true);\n }\n\n res.statusCode = await this._invoke(name, req.body);\n res.end();\n } catch (err: any) {\n log.error(`Function failed: ${name}`, err);\n res.statusCode = 500;\n res.end();\n }\n });\n\n this._port = await getPort({ host: 'localhost', port: 7200, portRange: [7200, 7299] });\n this._server = app.listen(this._port);\n\n try {\n // Register functions.\n const { registrationId, endpoint } = await this._client.services.services.FunctionRegistryService!.register({\n endpoint: this.endpoint,\n functions: this.functions.map(({ def: { name } }) => ({ name })),\n });\n\n log.info('registered', { registrationId, endpoint });\n this._registrationId = registrationId;\n this._proxy = endpoint;\n } catch (err: any) {\n await this.stop();\n throw new Error('FunctionRegistryService not available (check plugin is configured).');\n }\n }\n\n async stop() {\n const trigger = new Trigger();\n this._server?.close(async () => {\n if (this._registrationId) {\n await this._client.services.services.FunctionRegistryService!.unregister({\n registrationId: this._registrationId,\n });\n\n log.info('unregistered', { registrationId: this._registrationId });\n this._registrationId = undefined;\n this._proxy = undefined;\n }\n\n trigger.wake();\n });\n\n await trigger.wait();\n this._port = undefined;\n this._server = undefined;\n }\n\n /**\n * Load function.\n */\n private async _load(def: FunctionDef, flush = false) {\n const { id, name, handler } = def;\n const path = join(this._options.directory, handler);\n log.info('loading', { id });\n\n // Remove from cache.\n if (flush) {\n Object.keys(require.cache)\n .filter((key) => key.startsWith(path))\n .forEach((key) => delete require.cache[key]);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const module = require(path);\n if (typeof module.default !== 'function') {\n throw new Error(`Handler must export default function: ${id}`);\n }\n\n this._handlers[name] = { def, handler: module.default };\n }\n\n /**\n * Invoke function handler.\n */\n private async _invoke(name: string, event: any) {\n const seq = ++this._seq;\n const now = Date.now();\n\n log.info('req', { seq, name });\n const { handler } = this._handlers[name];\n\n const context: FunctionContext = {\n client: this._client,\n dataDir: this._options.dataDir,\n };\n\n let statusCode = 200;\n const response: Response = {\n status: (code: number) => {\n statusCode = code;\n return response;\n },\n };\n\n await handler({ context, event, response });\n log.info('res', { seq, name, statusCode, duration: Date.now() - now });\n\n return statusCode;\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { CronJob } from 'cron';\n\nimport { debounce, DeferredTask } from '@dxos/async';\nimport { type Client, type PublicKey } from '@dxos/client';\nimport { type Space, TextObject } from '@dxos/client/echo';\nimport { Context } from '@dxos/context';\nimport { Filter, createSubscription, type Query, subscribe } from '@dxos/echo-schema';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\nimport { ComplexMap } from '@dxos/util';\n\nimport { type FunctionSubscriptionEvent } from '../handler';\nimport { type FunctionDef, type FunctionManifest, type FunctionTrigger, type TriggerSubscription } from '../manifest';\n\ntype Callback = (data: FunctionSubscriptionEvent) => Promise<number>;\n\ntype SchedulerOptions = {\n endpoint?: string;\n callback?: Callback;\n};\n\n/**\n * Functions scheduler.\n */\n// TODO(burdon): Create tests.\nexport class Scheduler {\n // Map of mounted functions.\n private readonly _mounts = new ComplexMap<\n { id: string; spaceKey: PublicKey },\n { ctx: Context; trigger: FunctionTrigger }\n >(({ id, spaceKey }) => `${spaceKey.toHex()}:${id}`);\n\n constructor(\n private readonly _client: Client,\n private readonly _manifest: FunctionManifest,\n private readonly _options: SchedulerOptions = {},\n ) {}\n\n async start() {\n this._client.spaces.subscribe(async (spaces) => {\n for (const space of spaces) {\n await space.waitUntilReady();\n for (const trigger of this._manifest.triggers ?? []) {\n await this.mount(new Context(), space, trigger);\n }\n }\n });\n }\n\n async stop() {\n for (const { id, spaceKey } of this._mounts.keys()) {\n await this.unmount(id, spaceKey);\n }\n }\n\n private async mount(ctx: Context, space: Space, trigger: FunctionTrigger) {\n const key = { id: trigger.function, spaceKey: space.key };\n const def = this._manifest.functions.find((config) => config.id === trigger.function);\n invariant(def, `Function not found: ${trigger.function}`);\n\n // Currently supports only one trigger declaration per function.\n const exists = this._mounts.get(key);\n if (!exists) {\n this._mounts.set(key, { ctx, trigger });\n log('mount', { space: space.key, trigger });\n if (ctx.disposed) {\n return;\n }\n\n // Timer.\n if (trigger.schedule) {\n this._createTimer(ctx, space, def, trigger);\n }\n\n // Subscription.\n for (const triggerSubscription of trigger.subscriptions ?? []) {\n this._createSubscription(ctx, space, def, triggerSubscription);\n }\n }\n }\n\n private async unmount(id: string, spaceKey: PublicKey) {\n const key = { id, spaceKey };\n const { ctx } = this._mounts.get(key) ?? {};\n if (ctx) {\n this._mounts.delete(key);\n await ctx.dispose();\n }\n }\n\n private _createTimer(ctx: Context, space: Space, def: FunctionDef, trigger: FunctionTrigger) {\n const task = new DeferredTask(ctx, async () => {\n await this._execFunction(def, {\n space: space.key,\n });\n });\n\n // TODO(burdon): Check greater than 30s min (use cron-parser).\n invariant(trigger.schedule);\n const job = new CronJob(trigger.schedule, () => task.schedule());\n\n job.start();\n ctx.onDispose(() => job.stop());\n }\n\n private _createSubscription(ctx: Context, space: Space, def: FunctionDef, triggerSubscription: TriggerSubscription) {\n const objectIds = new Set<string>();\n const task = new DeferredTask(ctx, async () => {\n await this._execFunction(def, {\n space: space.key,\n objects: Array.from(objectIds),\n });\n });\n\n // TODO(burdon): Don't fire initially.\n // TODO(burdon): Standardize subscription handles.\n const subscriptions: (() => void)[] = [];\n const subscription = createSubscription(({ added, updated }) => {\n for (const object of added) {\n objectIds.add(object.id);\n }\n for (const object of updated) {\n objectIds.add(object.id);\n }\n\n task.schedule();\n });\n subscriptions.push(() => subscription.unsubscribe());\n\n // TODO(burdon): Create queue. Only allow one invocation per trigger at a time?\n // TODO(burdon): Disable trigger if keeps failing.\n const { type, props, deep, delay } = triggerSubscription;\n const update = ({ objects }: Query) => {\n subscription.update(objects);\n\n // TODO(burdon): Hack to monitor changes to Document's text object.\n if (deep) {\n log.info('update', { type, deep, objects: objects.length });\n for (const object of objects) {\n const content = object.content;\n if (content instanceof TextObject) {\n subscriptions.push(content[subscribe](debounce(() => subscription.update([object]), 1_000)));\n }\n }\n }\n };\n\n // TODO(burdon): [Bug]: all callbacks are fired on the first mutation.\n // TODO(burdon): [Bug]: not updated when document is deleted (either top or hierarchically).\n const query = space.db.query(Filter.typename(type, props));\n subscriptions.push(query.subscribe(delay ? debounce(update, delay * 1_000) : update));\n\n ctx.onDispose(() => {\n subscriptions.forEach((unsubscribe) => unsubscribe());\n });\n }\n\n private async _execFunction(def: FunctionDef, data: any) {\n try {\n log('request', { function: def.id });\n const { endpoint, callback } = this._options;\n let status = 0;\n if (endpoint) {\n // TODO(burdon): Move out of scheduler (generalize as callback).\n const response = await fetch(`${this._options.endpoint}/${def.name}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(data),\n });\n\n status = response.status;\n } else if (callback) {\n status = await callback(data);\n }\n\n // const result = await response.json();\n log('result', { function: def.id, result: status });\n } catch (err: any) {\n log.error('error', { function: def.id, error: err.message });\n }\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["PublicKey", "isTypedObject", "log", "nonNullable", "subscriptionHandler", "handler", "event", "context", "rest", "client", "space", "spaces", "get", "from", "undefined", "objects", "map", "id", "db", "getObjectById", "filter", "warn", "info", "key", "truncate", "length", "express", "getPort", "join", "Trigger", "invariant", "log", "DevServer", "constructor", "_client", "_options", "_handlers", "_seq", "endpoint", "invariant", "_port", "proxy", "_proxy", "functions", "Object", "values", "initialize", "def", "manifest", "_load", "err", "log", "error", "start", "app", "express", "use", "json", "post", "req", "res", "name", "params", "reload", "statusCode", "_invoke", "body", "end", "getPort", "host", "port", "portRange", "_server", "listen", "registrationId", "services", "FunctionRegistryService", "register", "map", "info", "_registrationId", "stop", "Error", "trigger", "Trigger", "close", "unregister", "undefined", "wake", "wait", "flush", "id", "handler", "path", "join", "directory", "keys", "require", "cache", "filter", "key", "startsWith", "forEach", "module", "default", "event", "seq", "now", "Date", "context", "client", "dataDir", "response", "status", "code", "duration", "CronJob", "debounce", "DeferredTask", "TextObject", "Context", "Filter", "createSubscription", "subscribe", "invariant", "log", "ComplexMap", "Scheduler", "constructor", "_client", "_manifest", "_options", "_mounts", "id", "spaceKey", "toHex", "start", "spaces", "space", "waitUntilReady", "trigger", "triggers", "mount", "stop", "keys", "unmount", "ctx", "key", "function", "def", "functions", "find", "config", "exists", "get", "set", "disposed", "schedule", "_createTimer", "triggerSubscription", "subscriptions", "_createSubscription", "delete", "dispose", "task", "_execFunction", "job", "onDispose", "objectIds", "Set", "objects", "Array", "from", "subscription", "added", "updated", "object", "add", "push", "unsubscribe", "type", "props", "deep", "delay", "update", "info", "length", "content", "query", "db", "typename", "forEach", "data", "endpoint", "callback", "status", "response", "fetch", "name", "method", "headers", "body", "JSON", "stringify", "result", "err", "error", "message"]
4
+ "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Client, PublicKey } from '@dxos/client';\nimport { type Space } from '@dxos/client/echo';\nimport { isTypedObject, type TypedObject } from '@dxos/echo-schema';\nimport { nonNullable } from '@dxos/util';\n\n// TODO(burdon): No response?\nexport interface Response {\n status(code: number): Response;\n}\n\n// TODO(burdon): Limit access to individual space?\nexport interface FunctionContext {\n client: Client;\n dataDir?: string;\n}\n\n// TODO(burdon): Model after http request. Ref Lambda/OpenFaaS.\n// https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html\nexport type FunctionHandler<T extends {}> = (params: {\n event: T;\n context: FunctionContext;\n response: Response;\n}) => Promise<Response | void>;\n\nexport type FunctionSubscriptionEvent = {\n space?: string; // TODO(burdon): Convert to PublicKey.\n objects?: string[];\n};\n\nexport type FunctionSubscriptionEvent2 = {\n space?: Space;\n objects?: TypedObject[];\n};\n\nexport const subscriptionHandler = (\n handler: FunctionHandler<FunctionSubscriptionEvent2>,\n): FunctionHandler<FunctionSubscriptionEvent> => {\n return ({ event, context, ...rest }) => {\n const { client } = context;\n const space = event.space ? client.spaces.get(PublicKey.from(event.space)) : undefined;\n const objects =\n space &&\n event.objects\n ?.map<TypedObject | undefined>((id) => space!.db.getObjectById(id))\n .filter(nonNullable)\n .filter(isTypedObject);\n\n return handler({ event: { space, objects }, context, ...rest });\n };\n};\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport express from 'express';\nimport { getPort } from 'get-port-please';\nimport type http from 'http';\nimport { join } from 'node:path';\n\nimport { Trigger } from '@dxos/async';\nimport { type Client } from '@dxos/client';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\n\nimport { type FunctionContext, type FunctionHandler, type Response } from '../handler';\nimport { type FunctionDef, type FunctionManifest } from '../manifest';\n\nexport type DevServerOptions = {\n port?: number;\n directory: string;\n manifest: FunctionManifest;\n reload?: boolean;\n dataDir?: string;\n};\n\n/**\n * Functions dev server provides a local HTTP server for testing functions.\n */\nexport class DevServer {\n // Function handlers indexed by name (URL path).\n private readonly _handlers: Record<string, { def: FunctionDef; handler: FunctionHandler<any> }> = {};\n\n private _server?: http.Server;\n private _port?: number;\n private _registrationId?: string;\n private _proxy?: string;\n private _seq = 0;\n\n // prettier-ignore\n constructor(\n private readonly _client: Client,\n private readonly _options: DevServerOptions,\n ) {}\n\n get endpoint() {\n invariant(this._port);\n return `http://localhost:${this._port}`;\n }\n\n get proxy() {\n return this._proxy;\n }\n\n get functions() {\n return Object.values(this._handlers);\n }\n\n async initialize() {\n for (const def of this._options.manifest.functions) {\n try {\n await this._load(def);\n } catch (err) {\n log.error('parsing function (check manifest)', err);\n }\n }\n }\n\n async start() {\n const app = express();\n app.use(express.json());\n\n app.post('/:name', async (req, res) => {\n const { name } = req.params;\n try {\n if (this._options.reload) {\n const { def } = this._handlers[name];\n await this._load(def, true);\n }\n\n res.statusCode = await this._invoke(name, req.body);\n res.end();\n } catch (err: any) {\n log.catch(err);\n res.statusCode = 500;\n res.end();\n }\n });\n\n this._port = await getPort({ host: 'localhost', port: 7200, portRange: [7200, 7299] });\n this._server = app.listen(this._port);\n\n try {\n // Register functions.\n const { registrationId, endpoint } = await this._client.services.services.FunctionRegistryService!.register({\n endpoint: this.endpoint,\n functions: this.functions.map(({ def: { name } }) => ({ name })),\n });\n\n log.info('registered', { registrationId, endpoint });\n this._registrationId = registrationId;\n this._proxy = endpoint;\n } catch (err: any) {\n await this.stop();\n throw new Error('FunctionRegistryService not available (check plugin is configured).');\n }\n }\n\n async stop() {\n const trigger = new Trigger();\n this._server?.close(async () => {\n if (this._registrationId) {\n await this._client.services.services.FunctionRegistryService!.unregister({\n registrationId: this._registrationId,\n });\n\n log.info('unregistered', { registrationId: this._registrationId });\n this._registrationId = undefined;\n this._proxy = undefined;\n }\n\n trigger.wake();\n });\n\n await trigger.wait();\n this._port = undefined;\n this._server = undefined;\n }\n\n /**\n * Load function.\n */\n private async _load(def: FunctionDef, flush = false) {\n const { id, name, handler } = def;\n const path = join(this._options.directory, handler);\n log.info('loading', { id });\n\n // Remove from cache.\n if (flush) {\n Object.keys(require.cache)\n .filter((key) => key.startsWith(path))\n .forEach((key) => delete require.cache[key]);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const module = require(path);\n if (typeof module.default !== 'function') {\n throw new Error(`Handler must export default function: ${id}`);\n }\n\n this._handlers[name] = { def, handler: module.default };\n }\n\n /**\n * Invoke function handler.\n */\n private async _invoke(name: string, event: any) {\n const seq = ++this._seq;\n const now = Date.now();\n\n log.info('req', { seq, name });\n const { handler } = this._handlers[name];\n\n const context: FunctionContext = {\n client: this._client,\n dataDir: this._options.dataDir,\n };\n\n let statusCode = 200;\n const response: Response = {\n status: (code: number) => {\n statusCode = code;\n return response;\n },\n };\n\n await handler({ context, event, response });\n log.info('res', { seq, name, statusCode, duration: Date.now() - now });\n\n return statusCode;\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { CronJob } from 'cron';\n\nimport { debounce, DeferredTask } from '@dxos/async';\nimport { type Client, type PublicKey } from '@dxos/client';\nimport { type Space, TextObject } from '@dxos/client/echo';\nimport { Context } from '@dxos/context';\nimport { Filter, createSubscription, type Query, subscribe } from '@dxos/echo-schema';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\nimport { ComplexMap } from '@dxos/util';\n\nimport { type FunctionSubscriptionEvent } from '../handler';\nimport { type FunctionDef, type FunctionManifest, type FunctionTrigger, type TriggerSubscription } from '../manifest';\n\ntype Callback = (data: FunctionSubscriptionEvent) => Promise<number>;\n\ntype SchedulerOptions = {\n endpoint?: string;\n callback?: Callback;\n};\n\n/**\n * Functions scheduler.\n */\n// TODO(burdon): Create tests.\nexport class Scheduler {\n // Map of mounted functions.\n private readonly _mounts = new ComplexMap<\n { id: string; spaceKey: PublicKey },\n { ctx: Context; trigger: FunctionTrigger }\n >(({ id, spaceKey }) => `${spaceKey.toHex()}:${id}`);\n\n constructor(\n private readonly _client: Client,\n private readonly _manifest: FunctionManifest,\n private readonly _options: SchedulerOptions = {},\n ) {}\n\n async start() {\n this._client.spaces.subscribe(async (spaces) => {\n for (const space of spaces) {\n await space.waitUntilReady();\n for (const trigger of this._manifest.triggers ?? []) {\n await this.mount(new Context(), space, trigger);\n }\n }\n });\n }\n\n async stop() {\n for (const { id, spaceKey } of this._mounts.keys()) {\n await this.unmount(id, spaceKey);\n }\n }\n\n private async mount(ctx: Context, space: Space, trigger: FunctionTrigger) {\n const key = { id: trigger.function, spaceKey: space.key };\n const def = this._manifest.functions.find((config) => config.id === trigger.function);\n invariant(def, `Function not found: ${trigger.function}`);\n\n // Currently supports only one trigger declaration per function.\n const exists = this._mounts.get(key);\n if (!exists) {\n this._mounts.set(key, { ctx, trigger });\n log('mount', { space: space.key, trigger });\n if (ctx.disposed) {\n return;\n }\n\n // Timer.\n if (trigger.schedule) {\n this._createTimer(ctx, space, def, trigger);\n }\n\n // Subscription.\n for (const triggerSubscription of trigger.subscriptions ?? []) {\n this._createSubscription(ctx, space, def, triggerSubscription);\n }\n }\n }\n\n private async unmount(id: string, spaceKey: PublicKey) {\n const key = { id, spaceKey };\n const { ctx } = this._mounts.get(key) ?? {};\n if (ctx) {\n this._mounts.delete(key);\n await ctx.dispose();\n }\n }\n\n private _createTimer(ctx: Context, space: Space, def: FunctionDef, trigger: FunctionTrigger) {\n const task = new DeferredTask(ctx, async () => {\n await this._execFunction(def, {\n space: space.key,\n });\n });\n\n // TODO(burdon): Check greater than 30s min (use cron-parser).\n invariant(trigger.schedule);\n const job = new CronJob(trigger.schedule, () => task.schedule());\n\n job.start();\n ctx.onDispose(() => job.stop());\n }\n\n private _createSubscription(ctx: Context, space: Space, def: FunctionDef, triggerSubscription: TriggerSubscription) {\n const objectIds = new Set<string>();\n const task = new DeferredTask(ctx, async () => {\n await this._execFunction(def, {\n space: space.key,\n objects: Array.from(objectIds),\n });\n });\n\n // TODO(burdon): Standardize subscription handles.\n const subscriptions: (() => void)[] = [];\n const subscription = createSubscription(({ added, updated }) => {\n for (const object of added) {\n objectIds.add(object.id);\n }\n for (const object of updated) {\n objectIds.add(object.id);\n }\n\n task.schedule();\n });\n subscriptions.push(() => subscription.unsubscribe());\n\n const { type, props, deep, delay } = triggerSubscription;\n const update = ({ objects }: Query) => {\n subscription.update(objects);\n\n // TODO(burdon): Hack to monitor changes to Document's text object.\n if (deep) {\n log.info('update', { type, deep, objects: objects.length });\n for (const object of objects) {\n const content = object.content;\n if (content instanceof TextObject) {\n subscriptions.push(content[subscribe](debounce(() => subscription.update([object]), 1_000)));\n }\n }\n }\n };\n\n // TODO(burdon): [Bug]: all callbacks are fired on the first mutation.\n // TODO(burdon): [Bug]: not updated when document is deleted (either top or hierarchically).\n const query = space.db.query(Filter.typename(type, props));\n subscriptions.push(query.subscribe(delay ? debounce(update, delay * 1_000) : update));\n\n ctx.onDispose(() => {\n subscriptions.forEach((unsubscribe) => unsubscribe());\n });\n }\n\n private async _execFunction(def: FunctionDef, data: any) {\n try {\n log('request', { function: def.id });\n const { endpoint, callback } = this._options;\n let status = 0;\n if (endpoint) {\n // TODO(burdon): Move out of scheduler (generalize as callback).\n const response = await fetch(`${this._options.endpoint}/${def.name}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(data),\n });\n\n status = response.status;\n } else if (callback) {\n status = await callback(data);\n }\n\n // const result = await response.json();\n log('result', { function: def.id, result: status });\n } catch (err: any) {\n log.error('error', { function: def.id, error: err.message });\n }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["PublicKey", "isTypedObject", "nonNullable", "subscriptionHandler", "handler", "event", "context", "rest", "client", "space", "spaces", "get", "PublicKey", "from", "undefined", "objects", "map", "id", "db", "getObjectById", "filter", "nonNullable", "isTypedObject", "express", "getPort", "join", "Trigger", "invariant", "log", "DevServer", "constructor", "_client", "_options", "_handlers", "_seq", "endpoint", "invariant", "_port", "proxy", "_proxy", "functions", "Object", "values", "initialize", "def", "manifest", "_load", "err", "log", "error", "start", "app", "express", "use", "json", "post", "req", "res", "name", "params", "reload", "statusCode", "_invoke", "body", "end", "catch", "getPort", "host", "port", "portRange", "_server", "listen", "registrationId", "services", "FunctionRegistryService", "register", "map", "info", "_registrationId", "stop", "Error", "trigger", "Trigger", "close", "unregister", "undefined", "wake", "wait", "flush", "id", "handler", "path", "join", "directory", "keys", "require", "cache", "filter", "key", "startsWith", "forEach", "module", "default", "event", "seq", "now", "Date", "context", "client", "dataDir", "response", "status", "code", "duration", "CronJob", "debounce", "DeferredTask", "TextObject", "Context", "Filter", "createSubscription", "subscribe", "invariant", "log", "ComplexMap", "Scheduler", "constructor", "_client", "_manifest", "_options", "_mounts", "id", "spaceKey", "toHex", "start", "spaces", "space", "waitUntilReady", "trigger", "triggers", "mount", "stop", "keys", "unmount", "ctx", "key", "function", "def", "functions", "find", "config", "exists", "get", "set", "disposed", "schedule", "_createTimer", "triggerSubscription", "subscriptions", "_createSubscription", "delete", "dispose", "task", "_execFunction", "job", "onDispose", "objectIds", "Set", "objects", "Array", "from", "subscription", "added", "updated", "object", "add", "push", "unsubscribe", "type", "props", "deep", "delay", "update", "info", "length", "content", "query", "db", "typename", "forEach", "data", "endpoint", "callback", "status", "response", "fetch", "name", "method", "headers", "body", "JSON", "stringify", "result", "err", "error", "message"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"inject-globals:@inject-globals":{"bytes":384,"imports":[{"path":"@dxos/node-std/inject-globals","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/handler.ts":{"bytes":6074,"imports":[{"path":"@dxos/client","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@inject-globals","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/manifest.ts":{"bytes":1863,"imports":[{"path":"@inject-globals","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/runtime/dev-server.ts":{"bytes":18932,"imports":[{"path":"express","kind":"import-statement","external":true},{"path":"get-port-please","kind":"import-statement","external":true},{"path":"@dxos/node-std/path","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@inject-globals","kind":"import-statement","external":true},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/runtime/scheduler.ts":{"bytes":22961,"imports":[{"path":"cron","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/client/echo","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@inject-globals","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/runtime/index.ts":{"bytes":566,"imports":[{"path":"packages/core/functions/src/runtime/dev-server.ts","kind":"import-statement","original":"./dev-server"},{"path":"packages/core/functions/src/runtime/scheduler.ts","kind":"import-statement","original":"./scheduler"},{"path":"@inject-globals","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/index.ts":{"bytes":637,"imports":[{"path":"packages/core/functions/src/handler.ts","kind":"import-statement","original":"./handler"},{"path":"packages/core/functions/src/manifest.ts","kind":"import-statement","original":"./manifest"},{"path":"packages/core/functions/src/runtime/index.ts","kind":"import-statement","original":"./runtime"},{"path":"@inject-globals","kind":"import-statement","external":true}],"format":"esm"}},"outputs":{"packages/core/functions/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":22950},"packages/core/functions/dist/lib/browser/index.mjs":{"imports":[{"path":"@dxos/node-std/inject-globals","kind":"import-statement","external":true},{"path":"@dxos/client","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"express","kind":"import-statement","external":true},{"path":"get-port-please","kind":"import-statement","external":true},{"path":"@dxos/node-std/path","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"cron","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/client/echo","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["DevServer","Scheduler","subscriptionHandler"],"entryPoint":"packages/core/functions/src/index.ts","inputs":{"inject-globals:@inject-globals":{"bytesInOutput":90},"packages/core/functions/src/handler.ts":{"bytesInOutput":1130},"packages/core/functions/src/index.ts":{"bytesInOutput":0},"packages/core/functions/src/runtime/dev-server.ts":{"bytesInOutput":4846},"packages/core/functions/src/runtime/index.ts":{"bytesInOutput":0},"packages/core/functions/src/runtime/scheduler.ts":{"bytesInOutput":5475}},"bytes":12223}}}
1
+ {"inputs":{"inject-globals:@inject-globals":{"bytes":384,"imports":[{"path":"@dxos/node-std/inject-globals","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/handler.ts":{"bytes":4072,"imports":[{"path":"@dxos/client","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@inject-globals","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/manifest.ts":{"bytes":1863,"imports":[{"path":"@inject-globals","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/runtime/dev-server.ts":{"bytes":18840,"imports":[{"path":"express","kind":"import-statement","external":true},{"path":"get-port-please","kind":"import-statement","external":true},{"path":"@dxos/node-std/path","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@inject-globals","kind":"import-statement","external":true},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/runtime/scheduler.ts":{"bytes":22471,"imports":[{"path":"cron","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/client/echo","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@inject-globals","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/runtime/index.ts":{"bytes":566,"imports":[{"path":"packages/core/functions/src/runtime/dev-server.ts","kind":"import-statement","original":"./dev-server"},{"path":"packages/core/functions/src/runtime/scheduler.ts","kind":"import-statement","original":"./scheduler"},{"path":"@inject-globals","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/index.ts":{"bytes":637,"imports":[{"path":"packages/core/functions/src/handler.ts","kind":"import-statement","original":"./handler"},{"path":"packages/core/functions/src/manifest.ts","kind":"import-statement","original":"./manifest"},{"path":"packages/core/functions/src/runtime/index.ts","kind":"import-statement","original":"./runtime"},{"path":"@inject-globals","kind":"import-statement","external":true}],"format":"esm"}},"outputs":{"packages/core/functions/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":21917},"packages/core/functions/dist/lib/browser/index.mjs":{"imports":[{"path":"@dxos/node-std/inject-globals","kind":"import-statement","external":true},{"path":"@dxos/client","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"express","kind":"import-statement","external":true},{"path":"get-port-please","kind":"import-statement","external":true},{"path":"@dxos/node-std/path","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"cron","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/client/echo","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["DevServer","Scheduler","subscriptionHandler"],"entryPoint":"packages/core/functions/src/index.ts","inputs":{"inject-globals:@inject-globals":{"bytesInOutput":90},"packages/core/functions/src/handler.ts":{"bytesInOutput":589},"packages/core/functions/src/index.ts":{"bytesInOutput":0},"packages/core/functions/src/runtime/dev-server.ts":{"bytesInOutput":4802},"packages/core/functions/src/runtime/index.ts":{"bytesInOutput":0},"packages/core/functions/src/runtime/scheduler.ts":{"bytesInOutput":5475}},"bytes":11638}}}
@@ -35,21 +35,20 @@ __export(node_exports, {
35
35
  module.exports = __toCommonJS(node_exports);
36
36
  var import_client = require("@dxos/client");
37
37
  var import_echo_schema = require("@dxos/echo-schema");
38
- var import_log = require("@dxos/log");
39
38
  var import_util = require("@dxos/util");
40
39
  var import_express = __toESM(require("express"));
41
40
  var import_get_port_please = require("get-port-please");
42
41
  var import_node_path = require("node:path");
43
42
  var import_async = require("@dxos/async");
44
43
  var import_invariant = require("@dxos/invariant");
45
- var import_log2 = require("@dxos/log");
44
+ var import_log = require("@dxos/log");
46
45
  var import_cron = require("cron");
47
46
  var import_async2 = require("@dxos/async");
48
47
  var import_echo = require("@dxos/client/echo");
49
48
  var import_context = require("@dxos/context");
50
49
  var import_echo_schema2 = require("@dxos/echo-schema");
51
50
  var import_invariant2 = require("@dxos/invariant");
52
- var import_log3 = require("@dxos/log");
51
+ var import_log2 = require("@dxos/log");
53
52
  var import_util2 = require("@dxos/util");
54
53
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
55
54
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -58,32 +57,11 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
58
57
  return require.apply(this, arguments);
59
58
  throw Error('Dynamic require of "' + x + '" is not supported');
60
59
  });
61
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/functions/src/handler.ts";
62
60
  var subscriptionHandler = (handler) => {
63
61
  return ({ event, context, ...rest }) => {
64
62
  const { client } = context;
65
63
  const space = event.space ? client.spaces.get(import_client.PublicKey.from(event.space)) : void 0;
66
64
  const objects = space && event.objects?.map((id) => space.db.getObjectById(id)).filter(import_util.nonNullable).filter(import_echo_schema.isTypedObject);
67
- if (!!event.space && !space) {
68
- import_log.log.warn("invalid space", {
69
- event
70
- }, {
71
- F: __dxlog_file,
72
- L: 64,
73
- S: void 0,
74
- C: (f, a) => f(...a)
75
- });
76
- } else {
77
- import_log.log.info("handler", {
78
- space: space?.key.truncate(),
79
- objects: objects?.length
80
- }, {
81
- F: __dxlog_file,
82
- L: 66,
83
- S: void 0,
84
- C: (f, a) => f(...a)
85
- });
86
- }
87
65
  return handler({
88
66
  event: {
89
67
  space,
@@ -94,7 +72,7 @@ var subscriptionHandler = (handler) => {
94
72
  });
95
73
  };
96
74
  };
97
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/dev-server.ts";
75
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/dev-server.ts";
98
76
  var DevServer = class {
99
77
  // prettier-ignore
100
78
  constructor(_client, _options) {
@@ -105,7 +83,7 @@ var DevServer = class {
105
83
  }
106
84
  get endpoint() {
107
85
  (0, import_invariant.invariant)(this._port, void 0, {
108
- F: __dxlog_file2,
86
+ F: __dxlog_file,
109
87
  L: 46,
110
88
  S: this,
111
89
  A: [
@@ -126,8 +104,8 @@ var DevServer = class {
126
104
  try {
127
105
  await this._load(def);
128
106
  } catch (err) {
129
- import_log2.log.error("parsing function (check manifest)", err, {
130
- F: __dxlog_file2,
107
+ import_log.log.error("parsing function (check manifest)", err, {
108
+ F: __dxlog_file,
131
109
  L: 63,
132
110
  S: this,
133
111
  C: (f, a) => f(...a)
@@ -148,8 +126,8 @@ var DevServer = class {
148
126
  res.statusCode = await this._invoke(name, req.body);
149
127
  res.end();
150
128
  } catch (err) {
151
- import_log2.log.error(`Function failed: ${name}`, err, {
152
- F: __dxlog_file2,
129
+ import_log.log.catch(err, void 0, {
130
+ F: __dxlog_file,
153
131
  L: 83,
154
132
  S: this,
155
133
  C: (f, a) => f(...a)
@@ -174,11 +152,11 @@ var DevServer = class {
174
152
  name
175
153
  }))
176
154
  });
177
- import_log2.log.info("registered", {
155
+ import_log.log.info("registered", {
178
156
  registrationId,
179
157
  endpoint
180
158
  }, {
181
- F: __dxlog_file2,
159
+ F: __dxlog_file,
182
160
  L: 99,
183
161
  S: this,
184
162
  C: (f, a) => f(...a)
@@ -197,10 +175,10 @@ var DevServer = class {
197
175
  await this._client.services.services.FunctionRegistryService.unregister({
198
176
  registrationId: this._registrationId
199
177
  });
200
- import_log2.log.info("unregistered", {
178
+ import_log.log.info("unregistered", {
201
179
  registrationId: this._registrationId
202
180
  }, {
203
- F: __dxlog_file2,
181
+ F: __dxlog_file,
204
182
  L: 116,
205
183
  S: this,
206
184
  C: (f, a) => f(...a)
@@ -220,10 +198,10 @@ var DevServer = class {
220
198
  async _load(def, flush = false) {
221
199
  const { id, name, handler } = def;
222
200
  const path = (0, import_node_path.join)(this._options.directory, handler);
223
- import_log2.log.info("loading", {
201
+ import_log.log.info("loading", {
224
202
  id
225
203
  }, {
226
- F: __dxlog_file2,
204
+ F: __dxlog_file,
227
205
  L: 135,
228
206
  S: this,
229
207
  C: (f, a) => f(...a)
@@ -246,11 +224,11 @@ var DevServer = class {
246
224
  async _invoke(name, event) {
247
225
  const seq = ++this._seq;
248
226
  const now = Date.now();
249
- import_log2.log.info("req", {
227
+ import_log.log.info("req", {
250
228
  seq,
251
229
  name
252
230
  }, {
253
- F: __dxlog_file2,
231
+ F: __dxlog_file,
254
232
  L: 160,
255
233
  S: this,
256
234
  C: (f, a) => f(...a)
@@ -272,13 +250,13 @@ var DevServer = class {
272
250
  event,
273
251
  response
274
252
  });
275
- import_log2.log.info("res", {
253
+ import_log.log.info("res", {
276
254
  seq,
277
255
  name,
278
256
  statusCode,
279
257
  duration: Date.now() - now
280
258
  }, {
281
- F: __dxlog_file2,
259
+ F: __dxlog_file,
282
260
  L: 177,
283
261
  S: this,
284
262
  C: (f, a) => f(...a)
@@ -286,7 +264,7 @@ var DevServer = class {
286
264
  return statusCode;
287
265
  }
288
266
  };
289
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/scheduler.ts";
267
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/scheduler.ts";
290
268
  var Scheduler = class {
291
269
  constructor(_client, _manifest, _options = {}) {
292
270
  this._client = _client;
@@ -316,7 +294,7 @@ var Scheduler = class {
316
294
  };
317
295
  const def = this._manifest.functions.find((config) => config.id === trigger.function);
318
296
  (0, import_invariant2.invariant)(def, `Function not found: ${trigger.function}`, {
319
- F: __dxlog_file3,
297
+ F: __dxlog_file2,
320
298
  L: 63,
321
299
  S: this,
322
300
  A: [
@@ -330,11 +308,11 @@ var Scheduler = class {
330
308
  ctx,
331
309
  trigger
332
310
  });
333
- (0, import_log3.log)("mount", {
311
+ (0, import_log2.log)("mount", {
334
312
  space: space.key,
335
313
  trigger
336
314
  }, {
337
- F: __dxlog_file3,
315
+ F: __dxlog_file2,
338
316
  L: 69,
339
317
  S: this,
340
318
  C: (f, a) => f(...a)
@@ -368,7 +346,7 @@ var Scheduler = class {
368
346
  });
369
347
  });
370
348
  (0, import_invariant2.invariant)(trigger.schedule, void 0, {
371
- F: __dxlog_file3,
349
+ F: __dxlog_file2,
372
350
  L: 103,
373
351
  S: this,
374
352
  A: [
@@ -403,13 +381,13 @@ var Scheduler = class {
403
381
  const update = ({ objects }) => {
404
382
  subscription.update(objects);
405
383
  if (deep) {
406
- import_log3.log.info("update", {
384
+ import_log2.log.info("update", {
407
385
  type,
408
386
  deep,
409
387
  objects: objects.length
410
388
  }, {
411
- F: __dxlog_file3,
412
- L: 142,
389
+ F: __dxlog_file2,
390
+ L: 139,
413
391
  S: this,
414
392
  C: (f, a) => f(...a)
415
393
  });
@@ -431,11 +409,11 @@ var Scheduler = class {
431
409
  }
432
410
  async _execFunction(def, data) {
433
411
  try {
434
- (0, import_log3.log)("request", {
412
+ (0, import_log2.log)("request", {
435
413
  function: def.id
436
414
  }, {
437
- F: __dxlog_file3,
438
- L: 164,
415
+ F: __dxlog_file2,
416
+ L: 161,
439
417
  S: this,
440
418
  C: (f, a) => f(...a)
441
419
  });
@@ -453,22 +431,22 @@ var Scheduler = class {
453
431
  } else if (callback) {
454
432
  status = await callback(data);
455
433
  }
456
- (0, import_log3.log)("result", {
434
+ (0, import_log2.log)("result", {
457
435
  function: def.id,
458
436
  result: status
459
437
  }, {
460
- F: __dxlog_file3,
461
- L: 183,
438
+ F: __dxlog_file2,
439
+ L: 180,
462
440
  S: this,
463
441
  C: (f, a) => f(...a)
464
442
  });
465
443
  } catch (err) {
466
- import_log3.log.error("error", {
444
+ import_log2.log.error("error", {
467
445
  function: def.id,
468
446
  error: err.message
469
447
  }, {
470
- F: __dxlog_file3,
471
- L: 185,
448
+ F: __dxlog_file2,
449
+ L: 182,
472
450
  S: this,
473
451
  C: (f, a) => f(...a)
474
452
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/handler.ts", "../../../src/runtime/dev-server.ts", "../../../src/runtime/scheduler.ts"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Client, PublicKey } from '@dxos/client';\nimport { type Space } from '@dxos/client/echo';\nimport { isTypedObject, type TypedObject } from '@dxos/echo-schema';\nimport { log } from '@dxos/log';\nimport { nonNullable } from '@dxos/util';\n\n// TODO(burdon): No response?\nexport interface Response {\n status(code: number): Response;\n}\n\n// TODO(burdon): Limit access to individual space?\nexport interface FunctionContext {\n client: Client;\n dataDir?: string;\n}\n\n// TODO(burdon): Model after http request. Ref Lambda/OpenFaaS.\n// https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html\nexport type FunctionHandler<T extends {}> = (params: {\n event: T;\n context: FunctionContext;\n response: Response;\n}) => Promise<Response | void>;\n\nexport type FunctionSubscriptionEvent = {\n space?: string; // TODO(burdon): Convert to PublicKey.\n objects?: string[];\n};\n\nexport type FunctionSubscriptionEvent2 = {\n space?: Space;\n objects?: TypedObject[];\n};\n\n/**\n * Handler wrapper for subscription events; extracts space and objects.\n *\n * To test:\n * ```\n * curl -s -X POST -H \"Content-Type: application/json\" --data '{\"space\": \"0446...1cbb\"}' http://localhost:7100/dev/email-extractor\n * ```\n *\n * NOTE: Get space key from devtools or `dx space list --json`\n */\nexport const subscriptionHandler = (\n handler: FunctionHandler<FunctionSubscriptionEvent2>,\n): FunctionHandler<FunctionSubscriptionEvent> => {\n return ({ event, context, ...rest }) => {\n const { client } = context;\n const space = event.space ? client.spaces.get(PublicKey.from(event.space)) : undefined;\n const objects =\n space &&\n event.objects\n ?.map<TypedObject | undefined>((id) => space!.db.getObjectById(id))\n .filter(nonNullable)\n .filter(isTypedObject);\n\n if (!!event.space && !space) {\n log.warn('invalid space', { event });\n } else {\n log.info('handler', { space: space?.key.truncate(), objects: objects?.length });\n }\n\n return handler({ event: { space, objects }, context, ...rest });\n };\n};\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport express from 'express';\nimport { getPort } from 'get-port-please';\nimport type http from 'http';\nimport { join } from 'node:path';\n\nimport { Trigger } from '@dxos/async';\nimport { type Client } from '@dxos/client';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\n\nimport { type FunctionContext, type FunctionHandler, type Response } from '../handler';\nimport { type FunctionDef, type FunctionManifest } from '../manifest';\n\nexport type DevServerOptions = {\n port?: number;\n directory: string;\n manifest: FunctionManifest;\n reload?: boolean;\n dataDir?: string;\n};\n\n/**\n * Functions dev server provides a local HTTP server for testing functions.\n */\nexport class DevServer {\n // Function handlers indexed by name (URL path).\n private readonly _handlers: Record<string, { def: FunctionDef; handler: FunctionHandler<any> }> = {};\n\n private _server?: http.Server;\n private _port?: number;\n private _registrationId?: string;\n private _proxy?: string;\n private _seq = 0;\n\n // prettier-ignore\n constructor(\n private readonly _client: Client,\n private readonly _options: DevServerOptions,\n ) {}\n\n get endpoint() {\n invariant(this._port);\n return `http://localhost:${this._port}`;\n }\n\n get proxy() {\n return this._proxy;\n }\n\n get functions() {\n return Object.values(this._handlers);\n }\n\n async initialize() {\n for (const def of this._options.manifest.functions) {\n try {\n await this._load(def);\n } catch (err) {\n log.error('parsing function (check manifest)', err);\n }\n }\n }\n\n async start() {\n const app = express();\n app.use(express.json());\n\n app.post('/:name', async (req, res) => {\n const { name } = req.params;\n try {\n if (this._options.reload) {\n const { def } = this._handlers[name];\n await this._load(def, true);\n }\n\n res.statusCode = await this._invoke(name, req.body);\n res.end();\n } catch (err: any) {\n log.error(`Function failed: ${name}`, err);\n res.statusCode = 500;\n res.end();\n }\n });\n\n this._port = await getPort({ host: 'localhost', port: 7200, portRange: [7200, 7299] });\n this._server = app.listen(this._port);\n\n try {\n // Register functions.\n const { registrationId, endpoint } = await this._client.services.services.FunctionRegistryService!.register({\n endpoint: this.endpoint,\n functions: this.functions.map(({ def: { name } }) => ({ name })),\n });\n\n log.info('registered', { registrationId, endpoint });\n this._registrationId = registrationId;\n this._proxy = endpoint;\n } catch (err: any) {\n await this.stop();\n throw new Error('FunctionRegistryService not available (check plugin is configured).');\n }\n }\n\n async stop() {\n const trigger = new Trigger();\n this._server?.close(async () => {\n if (this._registrationId) {\n await this._client.services.services.FunctionRegistryService!.unregister({\n registrationId: this._registrationId,\n });\n\n log.info('unregistered', { registrationId: this._registrationId });\n this._registrationId = undefined;\n this._proxy = undefined;\n }\n\n trigger.wake();\n });\n\n await trigger.wait();\n this._port = undefined;\n this._server = undefined;\n }\n\n /**\n * Load function.\n */\n private async _load(def: FunctionDef, flush = false) {\n const { id, name, handler } = def;\n const path = join(this._options.directory, handler);\n log.info('loading', { id });\n\n // Remove from cache.\n if (flush) {\n Object.keys(require.cache)\n .filter((key) => key.startsWith(path))\n .forEach((key) => delete require.cache[key]);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const module = require(path);\n if (typeof module.default !== 'function') {\n throw new Error(`Handler must export default function: ${id}`);\n }\n\n this._handlers[name] = { def, handler: module.default };\n }\n\n /**\n * Invoke function handler.\n */\n private async _invoke(name: string, event: any) {\n const seq = ++this._seq;\n const now = Date.now();\n\n log.info('req', { seq, name });\n const { handler } = this._handlers[name];\n\n const context: FunctionContext = {\n client: this._client,\n dataDir: this._options.dataDir,\n };\n\n let statusCode = 200;\n const response: Response = {\n status: (code: number) => {\n statusCode = code;\n return response;\n },\n };\n\n await handler({ context, event, response });\n log.info('res', { seq, name, statusCode, duration: Date.now() - now });\n\n return statusCode;\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { CronJob } from 'cron';\n\nimport { debounce, DeferredTask } from '@dxos/async';\nimport { type Client, type PublicKey } from '@dxos/client';\nimport { type Space, TextObject } from '@dxos/client/echo';\nimport { Context } from '@dxos/context';\nimport { Filter, createSubscription, type Query, subscribe } from '@dxos/echo-schema';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\nimport { ComplexMap } from '@dxos/util';\n\nimport { type FunctionSubscriptionEvent } from '../handler';\nimport { type FunctionDef, type FunctionManifest, type FunctionTrigger, type TriggerSubscription } from '../manifest';\n\ntype Callback = (data: FunctionSubscriptionEvent) => Promise<number>;\n\ntype SchedulerOptions = {\n endpoint?: string;\n callback?: Callback;\n};\n\n/**\n * Functions scheduler.\n */\n// TODO(burdon): Create tests.\nexport class Scheduler {\n // Map of mounted functions.\n private readonly _mounts = new ComplexMap<\n { id: string; spaceKey: PublicKey },\n { ctx: Context; trigger: FunctionTrigger }\n >(({ id, spaceKey }) => `${spaceKey.toHex()}:${id}`);\n\n constructor(\n private readonly _client: Client,\n private readonly _manifest: FunctionManifest,\n private readonly _options: SchedulerOptions = {},\n ) {}\n\n async start() {\n this._client.spaces.subscribe(async (spaces) => {\n for (const space of spaces) {\n await space.waitUntilReady();\n for (const trigger of this._manifest.triggers ?? []) {\n await this.mount(new Context(), space, trigger);\n }\n }\n });\n }\n\n async stop() {\n for (const { id, spaceKey } of this._mounts.keys()) {\n await this.unmount(id, spaceKey);\n }\n }\n\n private async mount(ctx: Context, space: Space, trigger: FunctionTrigger) {\n const key = { id: trigger.function, spaceKey: space.key };\n const def = this._manifest.functions.find((config) => config.id === trigger.function);\n invariant(def, `Function not found: ${trigger.function}`);\n\n // Currently supports only one trigger declaration per function.\n const exists = this._mounts.get(key);\n if (!exists) {\n this._mounts.set(key, { ctx, trigger });\n log('mount', { space: space.key, trigger });\n if (ctx.disposed) {\n return;\n }\n\n // Timer.\n if (trigger.schedule) {\n this._createTimer(ctx, space, def, trigger);\n }\n\n // Subscription.\n for (const triggerSubscription of trigger.subscriptions ?? []) {\n this._createSubscription(ctx, space, def, triggerSubscription);\n }\n }\n }\n\n private async unmount(id: string, spaceKey: PublicKey) {\n const key = { id, spaceKey };\n const { ctx } = this._mounts.get(key) ?? {};\n if (ctx) {\n this._mounts.delete(key);\n await ctx.dispose();\n }\n }\n\n private _createTimer(ctx: Context, space: Space, def: FunctionDef, trigger: FunctionTrigger) {\n const task = new DeferredTask(ctx, async () => {\n await this._execFunction(def, {\n space: space.key,\n });\n });\n\n // TODO(burdon): Check greater than 30s min (use cron-parser).\n invariant(trigger.schedule);\n const job = new CronJob(trigger.schedule, () => task.schedule());\n\n job.start();\n ctx.onDispose(() => job.stop());\n }\n\n private _createSubscription(ctx: Context, space: Space, def: FunctionDef, triggerSubscription: TriggerSubscription) {\n const objectIds = new Set<string>();\n const task = new DeferredTask(ctx, async () => {\n await this._execFunction(def, {\n space: space.key,\n objects: Array.from(objectIds),\n });\n });\n\n // TODO(burdon): Don't fire initially.\n // TODO(burdon): Standardize subscription handles.\n const subscriptions: (() => void)[] = [];\n const subscription = createSubscription(({ added, updated }) => {\n for (const object of added) {\n objectIds.add(object.id);\n }\n for (const object of updated) {\n objectIds.add(object.id);\n }\n\n task.schedule();\n });\n subscriptions.push(() => subscription.unsubscribe());\n\n // TODO(burdon): Create queue. Only allow one invocation per trigger at a time?\n // TODO(burdon): Disable trigger if keeps failing.\n const { type, props, deep, delay } = triggerSubscription;\n const update = ({ objects }: Query) => {\n subscription.update(objects);\n\n // TODO(burdon): Hack to monitor changes to Document's text object.\n if (deep) {\n log.info('update', { type, deep, objects: objects.length });\n for (const object of objects) {\n const content = object.content;\n if (content instanceof TextObject) {\n subscriptions.push(content[subscribe](debounce(() => subscription.update([object]), 1_000)));\n }\n }\n }\n };\n\n // TODO(burdon): [Bug]: all callbacks are fired on the first mutation.\n // TODO(burdon): [Bug]: not updated when document is deleted (either top or hierarchically).\n const query = space.db.query(Filter.typename(type, props));\n subscriptions.push(query.subscribe(delay ? debounce(update, delay * 1_000) : update));\n\n ctx.onDispose(() => {\n subscriptions.forEach((unsubscribe) => unsubscribe());\n });\n }\n\n private async _execFunction(def: FunctionDef, data: any) {\n try {\n log('request', { function: def.id });\n const { endpoint, callback } = this._options;\n let status = 0;\n if (endpoint) {\n // TODO(burdon): Move out of scheduler (generalize as callback).\n const response = await fetch(`${this._options.endpoint}/${def.name}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(data),\n });\n\n status = response.status;\n } else if (callback) {\n status = await callback(data);\n }\n\n // const result = await response.json();\n log('result', { function: def.id, result: status });\n } catch (err: any) {\n log.error('error', { function: def.id, error: err.message });\n }\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,oBAAuC;AAEvC,yBAAgD;AAChD,iBAAoB;AACpB,kBAA4B;ACJ5B,qBAAoB;AACpB,6BAAwB;AAExB,uBAAqB;AAErB,mBAAwB;AAExB,uBAA0B;AAC1B,IAAAA,cAAoB;ACRpB,kBAAwB;AAExB,IAAAC,gBAAuC;AAEvC,kBAAuC;AACvC,qBAAwB;AACxB,IAAAC,sBAAkE;AAClE,IAAAC,oBAA0B;AAC1B,IAAAH,cAAoB;AACpB,IAAAI,eAA2B;;;;;;;;;AFoCpB,IAAMC,sBAAsB,CACjCC,YAAAA;AAEA,SAAO,CAAC,EAAEC,OAAOC,SAAS,GAAGC,KAAAA,MAAM;AACjC,UAAM,EAAEC,OAAM,IAAKF;AACnB,UAAMG,QAAQJ,MAAMI,QAAQD,OAAOE,OAAOC,IAAIC,wBAAUC,KAAKR,MAAMI,KAAK,CAAA,IAAKK;AAC7E,UAAMC,UACJN,SACAJ,MAAMU,SACFC,IAA6B,CAACC,OAAOR,MAAOS,GAAGC,cAAcF,EAAAA,CAAAA,EAC9DG,OAAOC,uBAAAA,EACPD,OAAOE,gCAAAA;AAEZ,QAAI,CAAC,CAACjB,MAAMI,SAAS,CAACA,OAAO;AAC3Bc,qBAAIC,KAAK,iBAAiB;QAAEnB;MAAM,GAAA;;;;;;IACpC,OAAO;AACLkB,qBAAIE,KAAK,WAAW;QAAEhB,OAAOA,OAAOiB,IAAIC,SAAAA;QAAYZ,SAASA,SAASa;MAAO,GAAA;;;;;;IAC/E;AAEA,WAAOxB,QAAQ;MAAEC,OAAO;QAAEI;QAAOM;MAAQ;MAAGT;MAAS,GAAGC;IAAK,CAAA;EAC/D;AACF;;AC1CO,IAAMsB,YAAN,MAAMA;;EAWXC,YACmBC,SACAC,UACjB;mBAFiBD;oBACAC;SAXFC,YAAiF,CAAC;SAM3FC,OAAO;EAMZ;EAEH,IAAIC,WAAW;AACbC,oCAAU,KAAKC,OAAK,QAAA;;;;;;;;;AACpB,WAAO,oBAAoB,KAAKA,KAAK;EACvC;EAEA,IAAIC,QAAQ;AACV,WAAO,KAAKC;EACd;EAEA,IAAIC,YAAY;AACd,WAAOC,OAAOC,OAAO,KAAKT,SAAS;EACrC;EAEA,MAAMU,aAAa;AACjB,eAAWC,OAAO,KAAKZ,SAASa,SAASL,WAAW;AAClD,UAAI;AACF,cAAM,KAAKM,MAAMF,GAAAA;MACnB,SAASG,KAAK;AACZxB,oBAAAA,IAAIyB,MAAM,qCAAqCD,KAAAA;;;;;;MACjD;IACF;EACF;EAEA,MAAME,QAAQ;AACZ,UAAMC,UAAMC,eAAAA,SAAAA;AACZD,QAAIE,IAAID,eAAAA,QAAQE,KAAI,CAAA;AAEpBH,QAAII,KAAK,UAAU,OAAOC,KAAKC,QAAAA;AAC7B,YAAM,EAAEC,KAAI,IAAKF,IAAIG;AACrB,UAAI;AACF,YAAI,KAAK1B,SAAS2B,QAAQ;AACxB,gBAAM,EAAEf,IAAG,IAAK,KAAKX,UAAUwB,IAAAA;AAC/B,gBAAM,KAAKX,MAAMF,KAAK,IAAA;QACxB;AAEAY,YAAII,aAAa,MAAM,KAAKC,QAAQJ,MAAMF,IAAIO,IAAI;AAClDN,YAAIO,IAAG;MACT,SAAShB,KAAU;AACjBxB,oBAAAA,IAAIyB,MAAM,oBAAoBS,IAAAA,IAAQV,KAAAA;;;;;;AACtCS,YAAII,aAAa;AACjBJ,YAAIO,IAAG;MACT;IACF,CAAA;AAEA,SAAK1B,QAAQ,UAAM2B,gCAAQ;MAAEC,MAAM;MAAaC,MAAM;MAAMC,WAAW;QAAC;QAAM;;IAAM,CAAA;AACpF,SAAKC,UAAUlB,IAAImB,OAAO,KAAKhC,KAAK;AAEpC,QAAI;AAEF,YAAM,EAAEiC,gBAAgBnC,SAAQ,IAAK,MAAM,KAAKJ,QAAQwC,SAASA,SAASC,wBAAyBC,SAAS;QAC1GtC,UAAU,KAAKA;QACfK,WAAW,KAAKA,UAAUxB,IAAI,CAAC,EAAE4B,KAAK,EAAEa,KAAI,EAAE,OAAQ;UAAEA;QAAK,EAAA;MAC/D,CAAA;AAEAlC,kBAAAA,IAAIE,KAAK,cAAc;QAAE6C;QAAgBnC;MAAS,GAAA;;;;;;AAClD,WAAKuC,kBAAkBJ;AACvB,WAAK/B,SAASJ;IAChB,SAASY,KAAU;AACjB,YAAM,KAAK4B,KAAI;AACf,YAAM,IAAIC,MAAM,qEAAA;IAClB;EACF;EAEA,MAAMD,OAAO;AACX,UAAME,UAAU,IAAIC,qBAAAA;AACpB,SAAKV,SAASW,MAAM,YAAA;AAClB,UAAI,KAAKL,iBAAiB;AACxB,cAAM,KAAK3C,QAAQwC,SAASA,SAASC,wBAAyBQ,WAAW;UACvEV,gBAAgB,KAAKI;QACvB,CAAA;AAEAnD,oBAAAA,IAAIE,KAAK,gBAAgB;UAAE6C,gBAAgB,KAAKI;QAAgB,GAAA;;;;;;AAChE,aAAKA,kBAAkB5D;AACvB,aAAKyB,SAASzB;MAChB;AAEA+D,cAAQI,KAAI;IACd,CAAA;AAEA,UAAMJ,QAAQK,KAAI;AAClB,SAAK7C,QAAQvB;AACb,SAAKsD,UAAUtD;EACjB;;;;EAKA,MAAcgC,MAAMF,KAAkBuC,QAAQ,OAAO;AACnD,UAAM,EAAElE,IAAIwC,MAAMrD,QAAO,IAAKwC;AAC9B,UAAMwC,WAAOC,uBAAK,KAAKrD,SAASsD,WAAWlF,OAAAA;AAC3CmB,gBAAAA,IAAIE,KAAK,WAAW;MAAER;IAAG,GAAA;;;;;;AAGzB,QAAIkE,OAAO;AACT1C,aAAO8C,KAAKC,UAAQC,KAAK,EACtBrE,OAAO,CAACM,QAAQA,IAAIgE,WAAWN,IAAAA,CAAAA,EAC/BO,QAAQ,CAACjE,QAAQ,OAAO8D,UAAQC,MAAM/D,GAAAA,CAAI;IAC/C;AAGA,UAAMkE,UAASJ,UAAQJ,IAAAA;AACvB,QAAI,OAAOQ,QAAOC,YAAY,YAAY;AACxC,YAAM,IAAIjB,MAAM,yCAAyC3D,EAAAA,EAAI;IAC/D;AAEA,SAAKgB,UAAUwB,IAAAA,IAAQ;MAAEb;MAAKxC,SAASwF,QAAOC;IAAQ;EACxD;;;;EAKA,MAAchC,QAAQJ,MAAcpD,OAAY;AAC9C,UAAMyF,MAAM,EAAE,KAAK5D;AACnB,UAAM6D,MAAMC,KAAKD,IAAG;AAEpBxE,gBAAAA,IAAIE,KAAK,OAAO;MAAEqE;MAAKrC;IAAK,GAAA;;;;;;AAC5B,UAAM,EAAErD,QAAO,IAAK,KAAK6B,UAAUwB,IAAAA;AAEnC,UAAMnD,UAA2B;MAC/BE,QAAQ,KAAKuB;MACbkE,SAAS,KAAKjE,SAASiE;IACzB;AAEA,QAAIrC,aAAa;AACjB,UAAMsC,WAAqB;MACzBC,QAAQ,CAACC,SAAAA;AACPxC,qBAAawC;AACb,eAAOF;MACT;IACF;AAEA,UAAM9F,QAAQ;MAAEE;MAASD;MAAO6F;IAAS,CAAA;AACzC3E,gBAAAA,IAAIE,KAAK,OAAO;MAAEqE;MAAKrC;MAAMG;MAAYyC,UAAUL,KAAKD,IAAG,IAAKA;IAAI,GAAA;;;;;;AAEpE,WAAOnC;EACT;AACF;;ACvJO,IAAM0C,YAAN,MAAMA;EAOXxE,YACmBC,SACAwE,WACAvE,WAA6B,CAAC,GAC/C;mBAHiBD;qBACAwE;oBACAvE;SARFwE,UAAU,IAAIC,wBAG7B,CAAC,EAAExF,IAAIyF,SAAQ,MAAO,GAAGA,SAASC,MAAK,CAAA,IAAM1F,EAAAA,EAAI;EAMhD;EAEH,MAAMgC,QAAQ;AACZ,SAAKlB,QAAQrB,OAAOkG,UAAU,OAAOlG,WAAAA;AACnC,iBAAWD,SAASC,QAAQ;AAC1B,cAAMD,MAAMoG,eAAc;AAC1B,mBAAWhC,WAAW,KAAK0B,UAAUO,YAAY,CAAA,GAAI;AACnD,gBAAM,KAAKC,MAAM,IAAIC,uBAAAA,GAAWvG,OAAOoE,OAAAA;QACzC;MACF;IACF,CAAA;EACF;EAEA,MAAMF,OAAO;AACX,eAAW,EAAE1D,IAAIyF,SAAQ,KAAM,KAAKF,QAAQjB,KAAI,GAAI;AAClD,YAAM,KAAK0B,QAAQhG,IAAIyF,QAAAA;IACzB;EACF;EAEA,MAAcK,MAAMG,KAAczG,OAAcoE,SAA0B;AACxE,UAAMnD,MAAM;MAAET,IAAI4D,QAAQsC;MAAUT,UAAUjG,MAAMiB;IAAI;AACxD,UAAMkB,MAAM,KAAK2D,UAAU/D,UAAU4E,KAAK,CAACC,WAAWA,OAAOpG,OAAO4D,QAAQsC,QAAQ;AACpF/E,0BAAAA,WAAUQ,KAAK,uBAAuBiC,QAAQsC,QAAQ,IAAE;;;;;;;;;AAGxD,UAAMG,SAAS,KAAKd,QAAQ7F,IAAIe,GAAAA;AAChC,QAAI,CAAC4F,QAAQ;AACX,WAAKd,QAAQe,IAAI7F,KAAK;QAAEwF;QAAKrC;MAAQ,CAAA;AACrCtD,sBAAAA,KAAI,SAAS;QAAEd,OAAOA,MAAMiB;QAAKmD;MAAQ,GAAA;;;;;;AACzC,UAAIqC,IAAIM,UAAU;AAChB;MACF;AAGA,UAAI3C,QAAQ4C,UAAU;AACpB,aAAKC,aAAaR,KAAKzG,OAAOmC,KAAKiC,OAAAA;MACrC;AAGA,iBAAW8C,uBAAuB9C,QAAQ+C,iBAAiB,CAAA,GAAI;AAC7D,aAAKC,oBAAoBX,KAAKzG,OAAOmC,KAAK+E,mBAAAA;MAC5C;IACF;EACF;EAEA,MAAcV,QAAQhG,IAAYyF,UAAqB;AACrD,UAAMhF,MAAM;MAAET;MAAIyF;IAAS;AAC3B,UAAM,EAAEQ,IAAG,IAAK,KAAKV,QAAQ7F,IAAIe,GAAAA,KAAQ,CAAC;AAC1C,QAAIwF,KAAK;AACP,WAAKV,QAAQsB,OAAOpG,GAAAA;AACpB,YAAMwF,IAAIa,QAAO;IACnB;EACF;EAEQL,aAAaR,KAAczG,OAAcmC,KAAkBiC,SAA0B;AAC3F,UAAMmD,OAAO,IAAIC,2BAAaf,KAAK,YAAA;AACjC,YAAM,KAAKgB,cAActF,KAAK;QAC5BnC,OAAOA,MAAMiB;MACf,CAAA;IACF,CAAA;AAGAU,0BAAAA,WAAUyC,QAAQ4C,UAAQ,QAAA;;;;;;;;;AAC1B,UAAMU,MAAM,IAAIC,oBAAQvD,QAAQ4C,UAAU,MAAMO,KAAKP,SAAQ,CAAA;AAE7DU,QAAIlF,MAAK;AACTiE,QAAImB,UAAU,MAAMF,IAAIxD,KAAI,CAAA;EAC9B;EAEQkD,oBAAoBX,KAAczG,OAAcmC,KAAkB+E,qBAA0C;AAClH,UAAMW,YAAY,oBAAIC,IAAAA;AACtB,UAAMP,OAAO,IAAIC,2BAAaf,KAAK,YAAA;AACjC,YAAM,KAAKgB,cAActF,KAAK;QAC5BnC,OAAOA,MAAMiB;QACbX,SAASyH,MAAM3H,KAAKyH,SAAAA;MACtB,CAAA;IACF,CAAA;AAIA,UAAMV,gBAAgC,CAAA;AACtC,UAAMa,mBAAeC,wCAAmB,CAAC,EAAEC,OAAOC,QAAO,MAAE;AACzD,iBAAWC,UAAUF,OAAO;AAC1BL,kBAAUQ,IAAID,OAAO5H,EAAE;MACzB;AACA,iBAAW4H,UAAUD,SAAS;AAC5BN,kBAAUQ,IAAID,OAAO5H,EAAE;MACzB;AAEA+G,WAAKP,SAAQ;IACf,CAAA;AACAG,kBAAcmB,KAAK,MAAMN,aAAaO,YAAW,CAAA;AAIjD,UAAM,EAAEC,MAAMC,OAAOC,MAAMC,MAAK,IAAKzB;AACrC,UAAM0B,SAAS,CAAC,EAAEtI,QAAO,MAAS;AAChC0H,mBAAaY,OAAOtI,OAAAA;AAGpB,UAAIoI,MAAM;AACR5H,oBAAAA,IAAIE,KAAK,UAAU;UAAEwH;UAAME;UAAMpI,SAASA,QAAQa;QAAO,GAAA;;;;;;AACzD,mBAAWiH,UAAU9H,SAAS;AAC5B,gBAAMuI,UAAUT,OAAOS;AACvB,cAAIA,mBAAmBC,wBAAY;AACjC3B,0BAAcmB,KAAKO,QAAQ1C,6BAAAA,MAAW4C,wBAAS,MAAMf,aAAaY,OAAO;cAACR;aAAO,GAAG,GAAA,CAAA,CAAA;UACtF;QACF;MACF;IACF;AAIA,UAAMY,QAAQhJ,MAAMS,GAAGuI,MAAMC,2BAAOC,SAASV,MAAMC,KAAAA,CAAAA;AACnDtB,kBAAcmB,KAAKU,MAAM7C,UAAUwC,YAAQI,wBAASH,QAAQD,QAAQ,GAAA,IAASC,MAAAA,CAAAA;AAE7EnC,QAAImB,UAAU,MAAA;AACZT,oBAAcjC,QAAQ,CAACqD,gBAAgBA,YAAAA,CAAAA;IACzC,CAAA;EACF;EAEA,MAAcd,cAActF,KAAkBgH,MAAW;AACvD,QAAI;AACFrI,sBAAAA,KAAI,WAAW;QAAE4F,UAAUvE,IAAI3B;MAAG,GAAA;;;;;;AAClC,YAAM,EAAEkB,UAAU0H,SAAQ,IAAK,KAAK7H;AACpC,UAAImE,SAAS;AACb,UAAIhE,UAAU;AAEZ,cAAM+D,WAAW,MAAM4D,MAAM,GAAG,KAAK9H,SAASG,QAAQ,IAAIS,IAAIa,IAAI,IAAI;UACpEsG,QAAQ;UACRC,SAAS;YACP,gBAAgB;UAClB;UACAlG,MAAMmG,KAAKC,UAAUN,IAAAA;QACvB,CAAA;AAEAzD,iBAASD,SAASC;MACpB,WAAW0D,UAAU;AACnB1D,iBAAS,MAAM0D,SAASD,IAAAA;MAC1B;AAGArI,sBAAAA,KAAI,UAAU;QAAE4F,UAAUvE,IAAI3B;QAAIkJ,QAAQhE;MAAO,GAAA;;;;;;IACnD,SAASpD,KAAU;AACjBxB,kBAAAA,IAAIyB,MAAM,SAAS;QAAEmE,UAAUvE,IAAI3B;QAAI+B,OAAOD,IAAIqH;MAAQ,GAAA;;;;;;IAC5D;EACF;AACF;",
6
- "names": ["import_log", "import_async", "import_echo_schema", "import_invariant", "import_util", "subscriptionHandler", "handler", "event", "context", "rest", "client", "space", "spaces", "get", "PublicKey", "from", "undefined", "objects", "map", "id", "db", "getObjectById", "filter", "nonNullable", "isTypedObject", "log", "warn", "info", "key", "truncate", "length", "DevServer", "constructor", "_client", "_options", "_handlers", "_seq", "endpoint", "invariant", "_port", "proxy", "_proxy", "functions", "Object", "values", "initialize", "def", "manifest", "_load", "err", "error", "start", "app", "express", "use", "json", "post", "req", "res", "name", "params", "reload", "statusCode", "_invoke", "body", "end", "getPort", "host", "port", "portRange", "_server", "listen", "registrationId", "services", "FunctionRegistryService", "register", "_registrationId", "stop", "Error", "trigger", "Trigger", "close", "unregister", "wake", "wait", "flush", "path", "join", "directory", "keys", "require", "cache", "startsWith", "forEach", "module", "default", "seq", "now", "Date", "dataDir", "response", "status", "code", "duration", "Scheduler", "_manifest", "_mounts", "ComplexMap", "spaceKey", "toHex", "subscribe", "waitUntilReady", "triggers", "mount", "Context", "unmount", "ctx", "function", "find", "config", "exists", "set", "disposed", "schedule", "_createTimer", "triggerSubscription", "subscriptions", "_createSubscription", "delete", "dispose", "task", "DeferredTask", "_execFunction", "job", "CronJob", "onDispose", "objectIds", "Set", "Array", "subscription", "createSubscription", "added", "updated", "object", "add", "push", "unsubscribe", "type", "props", "deep", "delay", "update", "content", "TextObject", "debounce", "query", "Filter", "typename", "data", "callback", "fetch", "method", "headers", "JSON", "stringify", "result", "message"]
4
+ "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Client, PublicKey } from '@dxos/client';\nimport { type Space } from '@dxos/client/echo';\nimport { isTypedObject, type TypedObject } from '@dxos/echo-schema';\nimport { nonNullable } from '@dxos/util';\n\n// TODO(burdon): No response?\nexport interface Response {\n status(code: number): Response;\n}\n\n// TODO(burdon): Limit access to individual space?\nexport interface FunctionContext {\n client: Client;\n dataDir?: string;\n}\n\n// TODO(burdon): Model after http request. Ref Lambda/OpenFaaS.\n// https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html\nexport type FunctionHandler<T extends {}> = (params: {\n event: T;\n context: FunctionContext;\n response: Response;\n}) => Promise<Response | void>;\n\nexport type FunctionSubscriptionEvent = {\n space?: string; // TODO(burdon): Convert to PublicKey.\n objects?: string[];\n};\n\nexport type FunctionSubscriptionEvent2 = {\n space?: Space;\n objects?: TypedObject[];\n};\n\nexport const subscriptionHandler = (\n handler: FunctionHandler<FunctionSubscriptionEvent2>,\n): FunctionHandler<FunctionSubscriptionEvent> => {\n return ({ event, context, ...rest }) => {\n const { client } = context;\n const space = event.space ? client.spaces.get(PublicKey.from(event.space)) : undefined;\n const objects =\n space &&\n event.objects\n ?.map<TypedObject | undefined>((id) => space!.db.getObjectById(id))\n .filter(nonNullable)\n .filter(isTypedObject);\n\n return handler({ event: { space, objects }, context, ...rest });\n };\n};\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport express from 'express';\nimport { getPort } from 'get-port-please';\nimport type http from 'http';\nimport { join } from 'node:path';\n\nimport { Trigger } from '@dxos/async';\nimport { type Client } from '@dxos/client';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\n\nimport { type FunctionContext, type FunctionHandler, type Response } from '../handler';\nimport { type FunctionDef, type FunctionManifest } from '../manifest';\n\nexport type DevServerOptions = {\n port?: number;\n directory: string;\n manifest: FunctionManifest;\n reload?: boolean;\n dataDir?: string;\n};\n\n/**\n * Functions dev server provides a local HTTP server for testing functions.\n */\nexport class DevServer {\n // Function handlers indexed by name (URL path).\n private readonly _handlers: Record<string, { def: FunctionDef; handler: FunctionHandler<any> }> = {};\n\n private _server?: http.Server;\n private _port?: number;\n private _registrationId?: string;\n private _proxy?: string;\n private _seq = 0;\n\n // prettier-ignore\n constructor(\n private readonly _client: Client,\n private readonly _options: DevServerOptions,\n ) {}\n\n get endpoint() {\n invariant(this._port);\n return `http://localhost:${this._port}`;\n }\n\n get proxy() {\n return this._proxy;\n }\n\n get functions() {\n return Object.values(this._handlers);\n }\n\n async initialize() {\n for (const def of this._options.manifest.functions) {\n try {\n await this._load(def);\n } catch (err) {\n log.error('parsing function (check manifest)', err);\n }\n }\n }\n\n async start() {\n const app = express();\n app.use(express.json());\n\n app.post('/:name', async (req, res) => {\n const { name } = req.params;\n try {\n if (this._options.reload) {\n const { def } = this._handlers[name];\n await this._load(def, true);\n }\n\n res.statusCode = await this._invoke(name, req.body);\n res.end();\n } catch (err: any) {\n log.catch(err);\n res.statusCode = 500;\n res.end();\n }\n });\n\n this._port = await getPort({ host: 'localhost', port: 7200, portRange: [7200, 7299] });\n this._server = app.listen(this._port);\n\n try {\n // Register functions.\n const { registrationId, endpoint } = await this._client.services.services.FunctionRegistryService!.register({\n endpoint: this.endpoint,\n functions: this.functions.map(({ def: { name } }) => ({ name })),\n });\n\n log.info('registered', { registrationId, endpoint });\n this._registrationId = registrationId;\n this._proxy = endpoint;\n } catch (err: any) {\n await this.stop();\n throw new Error('FunctionRegistryService not available (check plugin is configured).');\n }\n }\n\n async stop() {\n const trigger = new Trigger();\n this._server?.close(async () => {\n if (this._registrationId) {\n await this._client.services.services.FunctionRegistryService!.unregister({\n registrationId: this._registrationId,\n });\n\n log.info('unregistered', { registrationId: this._registrationId });\n this._registrationId = undefined;\n this._proxy = undefined;\n }\n\n trigger.wake();\n });\n\n await trigger.wait();\n this._port = undefined;\n this._server = undefined;\n }\n\n /**\n * Load function.\n */\n private async _load(def: FunctionDef, flush = false) {\n const { id, name, handler } = def;\n const path = join(this._options.directory, handler);\n log.info('loading', { id });\n\n // Remove from cache.\n if (flush) {\n Object.keys(require.cache)\n .filter((key) => key.startsWith(path))\n .forEach((key) => delete require.cache[key]);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const module = require(path);\n if (typeof module.default !== 'function') {\n throw new Error(`Handler must export default function: ${id}`);\n }\n\n this._handlers[name] = { def, handler: module.default };\n }\n\n /**\n * Invoke function handler.\n */\n private async _invoke(name: string, event: any) {\n const seq = ++this._seq;\n const now = Date.now();\n\n log.info('req', { seq, name });\n const { handler } = this._handlers[name];\n\n const context: FunctionContext = {\n client: this._client,\n dataDir: this._options.dataDir,\n };\n\n let statusCode = 200;\n const response: Response = {\n status: (code: number) => {\n statusCode = code;\n return response;\n },\n };\n\n await handler({ context, event, response });\n log.info('res', { seq, name, statusCode, duration: Date.now() - now });\n\n return statusCode;\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { CronJob } from 'cron';\n\nimport { debounce, DeferredTask } from '@dxos/async';\nimport { type Client, type PublicKey } from '@dxos/client';\nimport { type Space, TextObject } from '@dxos/client/echo';\nimport { Context } from '@dxos/context';\nimport { Filter, createSubscription, type Query, subscribe } from '@dxos/echo-schema';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\nimport { ComplexMap } from '@dxos/util';\n\nimport { type FunctionSubscriptionEvent } from '../handler';\nimport { type FunctionDef, type FunctionManifest, type FunctionTrigger, type TriggerSubscription } from '../manifest';\n\ntype Callback = (data: FunctionSubscriptionEvent) => Promise<number>;\n\ntype SchedulerOptions = {\n endpoint?: string;\n callback?: Callback;\n};\n\n/**\n * Functions scheduler.\n */\n// TODO(burdon): Create tests.\nexport class Scheduler {\n // Map of mounted functions.\n private readonly _mounts = new ComplexMap<\n { id: string; spaceKey: PublicKey },\n { ctx: Context; trigger: FunctionTrigger }\n >(({ id, spaceKey }) => `${spaceKey.toHex()}:${id}`);\n\n constructor(\n private readonly _client: Client,\n private readonly _manifest: FunctionManifest,\n private readonly _options: SchedulerOptions = {},\n ) {}\n\n async start() {\n this._client.spaces.subscribe(async (spaces) => {\n for (const space of spaces) {\n await space.waitUntilReady();\n for (const trigger of this._manifest.triggers ?? []) {\n await this.mount(new Context(), space, trigger);\n }\n }\n });\n }\n\n async stop() {\n for (const { id, spaceKey } of this._mounts.keys()) {\n await this.unmount(id, spaceKey);\n }\n }\n\n private async mount(ctx: Context, space: Space, trigger: FunctionTrigger) {\n const key = { id: trigger.function, spaceKey: space.key };\n const def = this._manifest.functions.find((config) => config.id === trigger.function);\n invariant(def, `Function not found: ${trigger.function}`);\n\n // Currently supports only one trigger declaration per function.\n const exists = this._mounts.get(key);\n if (!exists) {\n this._mounts.set(key, { ctx, trigger });\n log('mount', { space: space.key, trigger });\n if (ctx.disposed) {\n return;\n }\n\n // Timer.\n if (trigger.schedule) {\n this._createTimer(ctx, space, def, trigger);\n }\n\n // Subscription.\n for (const triggerSubscription of trigger.subscriptions ?? []) {\n this._createSubscription(ctx, space, def, triggerSubscription);\n }\n }\n }\n\n private async unmount(id: string, spaceKey: PublicKey) {\n const key = { id, spaceKey };\n const { ctx } = this._mounts.get(key) ?? {};\n if (ctx) {\n this._mounts.delete(key);\n await ctx.dispose();\n }\n }\n\n private _createTimer(ctx: Context, space: Space, def: FunctionDef, trigger: FunctionTrigger) {\n const task = new DeferredTask(ctx, async () => {\n await this._execFunction(def, {\n space: space.key,\n });\n });\n\n // TODO(burdon): Check greater than 30s min (use cron-parser).\n invariant(trigger.schedule);\n const job = new CronJob(trigger.schedule, () => task.schedule());\n\n job.start();\n ctx.onDispose(() => job.stop());\n }\n\n private _createSubscription(ctx: Context, space: Space, def: FunctionDef, triggerSubscription: TriggerSubscription) {\n const objectIds = new Set<string>();\n const task = new DeferredTask(ctx, async () => {\n await this._execFunction(def, {\n space: space.key,\n objects: Array.from(objectIds),\n });\n });\n\n // TODO(burdon): Standardize subscription handles.\n const subscriptions: (() => void)[] = [];\n const subscription = createSubscription(({ added, updated }) => {\n for (const object of added) {\n objectIds.add(object.id);\n }\n for (const object of updated) {\n objectIds.add(object.id);\n }\n\n task.schedule();\n });\n subscriptions.push(() => subscription.unsubscribe());\n\n const { type, props, deep, delay } = triggerSubscription;\n const update = ({ objects }: Query) => {\n subscription.update(objects);\n\n // TODO(burdon): Hack to monitor changes to Document's text object.\n if (deep) {\n log.info('update', { type, deep, objects: objects.length });\n for (const object of objects) {\n const content = object.content;\n if (content instanceof TextObject) {\n subscriptions.push(content[subscribe](debounce(() => subscription.update([object]), 1_000)));\n }\n }\n }\n };\n\n // TODO(burdon): [Bug]: all callbacks are fired on the first mutation.\n // TODO(burdon): [Bug]: not updated when document is deleted (either top or hierarchically).\n const query = space.db.query(Filter.typename(type, props));\n subscriptions.push(query.subscribe(delay ? debounce(update, delay * 1_000) : update));\n\n ctx.onDispose(() => {\n subscriptions.forEach((unsubscribe) => unsubscribe());\n });\n }\n\n private async _execFunction(def: FunctionDef, data: any) {\n try {\n log('request', { function: def.id });\n const { endpoint, callback } = this._options;\n let status = 0;\n if (endpoint) {\n // TODO(burdon): Move out of scheduler (generalize as callback).\n const response = await fetch(`${this._options.endpoint}/${def.name}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(data),\n });\n\n status = response.status;\n } else if (callback) {\n status = await callback(data);\n }\n\n // const result = await response.json();\n log('result', { function: def.id, result: status });\n } catch (err: any) {\n log.error('error', { function: def.id, error: err.message });\n }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["import_async", "import_echo_schema", "import_invariant", "import_log", "import_util", "subscriptionHandler", "handler", "event", "context", "rest", "client", "space", "spaces", "get", "PublicKey", "from", "undefined", "objects", "map", "id", "db", "getObjectById", "filter", "nonNullable", "isTypedObject", "DevServer", "constructor", "_client", "_options", "_handlers", "_seq", "endpoint", "invariant", "_port", "proxy", "_proxy", "functions", "Object", "values", "initialize", "def", "manifest", "_load", "err", "log", "error", "start", "app", "express", "use", "json", "post", "req", "res", "name", "params", "reload", "statusCode", "_invoke", "body", "end", "catch", "getPort", "host", "port", "portRange", "_server", "listen", "registrationId", "services", "FunctionRegistryService", "register", "info", "_registrationId", "stop", "Error", "trigger", "Trigger", "close", "unregister", "wake", "wait", "flush", "path", "join", "directory", "keys", "require", "cache", "key", "startsWith", "forEach", "module", "default", "seq", "now", "Date", "dataDir", "response", "status", "code", "duration", "Scheduler", "_manifest", "_mounts", "ComplexMap", "spaceKey", "toHex", "subscribe", "waitUntilReady", "triggers", "mount", "Context", "unmount", "ctx", "function", "find", "config", "exists", "set", "disposed", "schedule", "_createTimer", "triggerSubscription", "subscriptions", "_createSubscription", "delete", "dispose", "task", "DeferredTask", "_execFunction", "job", "CronJob", "onDispose", "objectIds", "Set", "Array", "subscription", "createSubscription", "added", "updated", "object", "add", "push", "unsubscribe", "type", "props", "deep", "delay", "update", "length", "content", "TextObject", "debounce", "query", "Filter", "typename", "data", "callback", "fetch", "method", "headers", "JSON", "stringify", "result", "message"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"packages/core/functions/src/handler.ts":{"bytes":6074,"imports":[{"path":"@dxos/client","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/manifest.ts":{"bytes":1863,"imports":[],"format":"esm"},"packages/core/functions/src/runtime/dev-server.ts":{"bytes":18932,"imports":[{"path":"express","kind":"import-statement","external":true},{"path":"get-port-please","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/runtime/scheduler.ts":{"bytes":22961,"imports":[{"path":"cron","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/client/echo","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/runtime/index.ts":{"bytes":566,"imports":[{"path":"packages/core/functions/src/runtime/dev-server.ts","kind":"import-statement","original":"./dev-server"},{"path":"packages/core/functions/src/runtime/scheduler.ts","kind":"import-statement","original":"./scheduler"}],"format":"esm"},"packages/core/functions/src/index.ts":{"bytes":637,"imports":[{"path":"packages/core/functions/src/handler.ts","kind":"import-statement","original":"./handler"},{"path":"packages/core/functions/src/manifest.ts","kind":"import-statement","original":"./manifest"},{"path":"packages/core/functions/src/runtime/index.ts","kind":"import-statement","original":"./runtime"}],"format":"esm"}},"outputs":{"packages/core/functions/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":22942},"packages/core/functions/dist/lib/node/index.cjs":{"imports":[{"path":"@dxos/client","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"express","kind":"import-statement","external":true},{"path":"get-port-please","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"cron","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/client/echo","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["DevServer","Scheduler","subscriptionHandler"],"entryPoint":"packages/core/functions/src/index.ts","inputs":{"packages/core/functions/src/handler.ts":{"bytesInOutput":1130},"packages/core/functions/src/index.ts":{"bytesInOutput":0},"packages/core/functions/src/runtime/dev-server.ts":{"bytesInOutput":4836},"packages/core/functions/src/runtime/index.ts":{"bytesInOutput":0},"packages/core/functions/src/runtime/scheduler.ts":{"bytesInOutput":5475}},"bytes":12055}}}
1
+ {"inputs":{"packages/core/functions/src/handler.ts":{"bytes":4072,"imports":[{"path":"@dxos/client","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/manifest.ts":{"bytes":1863,"imports":[],"format":"esm"},"packages/core/functions/src/runtime/dev-server.ts":{"bytes":18840,"imports":[{"path":"express","kind":"import-statement","external":true},{"path":"get-port-please","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/runtime/scheduler.ts":{"bytes":22471,"imports":[{"path":"cron","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/client/echo","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/runtime/index.ts":{"bytes":566,"imports":[{"path":"packages/core/functions/src/runtime/dev-server.ts","kind":"import-statement","original":"./dev-server"},{"path":"packages/core/functions/src/runtime/scheduler.ts","kind":"import-statement","original":"./scheduler"}],"format":"esm"},"packages/core/functions/src/index.ts":{"bytes":637,"imports":[{"path":"packages/core/functions/src/handler.ts","kind":"import-statement","original":"./handler"},{"path":"packages/core/functions/src/manifest.ts","kind":"import-statement","original":"./manifest"},{"path":"packages/core/functions/src/runtime/index.ts","kind":"import-statement","original":"./runtime"}],"format":"esm"}},"outputs":{"packages/core/functions/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":21909},"packages/core/functions/dist/lib/node/index.cjs":{"imports":[{"path":"@dxos/client","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"express","kind":"import-statement","external":true},{"path":"get-port-please","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"cron","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/client/echo","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["DevServer","Scheduler","subscriptionHandler"],"entryPoint":"packages/core/functions/src/index.ts","inputs":{"packages/core/functions/src/handler.ts":{"bytesInOutput":589},"packages/core/functions/src/index.ts":{"bytesInOutput":0},"packages/core/functions/src/runtime/dev-server.ts":{"bytesInOutput":4792},"packages/core/functions/src/runtime/index.ts":{"bytesInOutput":0},"packages/core/functions/src/runtime/scheduler.ts":{"bytesInOutput":5475}},"bytes":11470}}}
@@ -21,15 +21,5 @@ export type FunctionSubscriptionEvent2 = {
21
21
  space?: Space;
22
22
  objects?: TypedObject[];
23
23
  };
24
- /**
25
- * Handler wrapper for subscription events; extracts space and objects.
26
- *
27
- * To test:
28
- * ```
29
- * curl -s -X POST -H "Content-Type: application/json" --data '{"space": "0446...1cbb"}' http://localhost:7100/dev/email-extractor
30
- * ```
31
- *
32
- * NOTE: Get space key from devtools or `dx space list --json`
33
- */
34
24
  export declare const subscriptionHandler: (handler: FunctionHandler<FunctionSubscriptionEvent2>) => FunctionHandler<FunctionSubscriptionEvent>;
35
25
  //# sourceMappingURL=handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/handler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,MAAM,EAAa,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKpE,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;CAChC;AAGD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE;IACnD,KAAK,EAAE,CAAC,CAAC;IACT,OAAO,EAAE,eAAe,CAAC;IACzB,QAAQ,EAAE,QAAQ,CAAC;CACpB,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;AAE/B,MAAM,MAAM,yBAAyB,GAAG;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;CACzB,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,YACrB,gBAAgB,0BAA0B,CAAC,KACnD,gBAAgB,yBAAyB,CAmB3C,CAAC"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/handler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,MAAM,EAAa,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIpE,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;CAChC;AAGD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE;IACnD,KAAK,EAAE,CAAC,CAAC;IACT,OAAO,EAAE,eAAe,CAAC;IACzB,QAAQ,EAAE,QAAQ,CAAC;CACpB,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;AAE/B,MAAM,MAAM,yBAAyB,GAAG;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,mBAAmB,YACrB,gBAAgB,0BAA0B,CAAC,KACnD,gBAAgB,yBAAyB,CAa3C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../../../src/runtime/scheduler.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,MAAM,EAAkB,MAAM,cAAc,CAAC;AAQ3D,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAoB,KAAK,gBAAgB,EAAkD,MAAM,aAAa,CAAC;AAEtH,KAAK,QAAQ,GAAG,CAAC,IAAI,EAAE,yBAAyB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAErE,KAAK,gBAAgB,GAAG;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF;;GAEG;AAEH,qBAAa,SAAS;IAQlB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAR3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAG6B;gBAGlC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,GAAE,gBAAqB;IAG5C,KAAK;IAWL,IAAI;YAMI,KAAK;YA0BL,OAAO;IASrB,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,mBAAmB;YAoDb,aAAa;CA0B5B"}
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../../../src/runtime/scheduler.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,MAAM,EAAkB,MAAM,cAAc,CAAC;AAQ3D,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAoB,KAAK,gBAAgB,EAAkD,MAAM,aAAa,CAAC;AAEtH,KAAK,QAAQ,GAAG,CAAC,IAAI,EAAE,yBAAyB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAErE,KAAK,gBAAgB,GAAG;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF;;GAEG;AAEH,qBAAa,SAAS;IAQlB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAR3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAG6B;gBAGlC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,GAAE,gBAAqB;IAG5C,KAAK;IAWL,IAAI;YAMI,KAAK;YA0BL,OAAO;IASrB,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,mBAAmB;YAiDb,aAAa;CA0B5B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/functions",
3
- "version": "0.3.9-main.7b9e2ad",
3
+ "version": "0.3.9-main.8045d90",
4
4
  "description": "Functions SDK and runtime.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -24,14 +24,14 @@
24
24
  "deepsignal": "1.4.0-shallow.0",
25
25
  "express": "^4.17.1",
26
26
  "get-port-please": "^3.1.1",
27
- "@dxos/async": "0.3.9-main.7b9e2ad",
28
- "@dxos/client": "0.3.9-main.7b9e2ad",
29
- "@dxos/echo-schema": "0.3.9-main.7b9e2ad",
30
- "@dxos/context": "0.3.9-main.7b9e2ad",
31
- "@dxos/invariant": "0.3.9-main.7b9e2ad",
32
- "@dxos/log": "0.3.9-main.7b9e2ad",
33
- "@dxos/node-std": "0.3.9-main.7b9e2ad",
34
- "@dxos/util": "0.3.9-main.7b9e2ad"
27
+ "@dxos/async": "0.3.9-main.8045d90",
28
+ "@dxos/client": "0.3.9-main.8045d90",
29
+ "@dxos/context": "0.3.9-main.8045d90",
30
+ "@dxos/echo-schema": "0.3.9-main.8045d90",
31
+ "@dxos/invariant": "0.3.9-main.8045d90",
32
+ "@dxos/node-std": "0.3.9-main.8045d90",
33
+ "@dxos/log": "0.3.9-main.8045d90",
34
+ "@dxos/util": "0.3.9-main.8045d90"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/express": "^4.17.17"
package/src/handler.ts CHANGED
@@ -5,7 +5,6 @@
5
5
  import { type Client, PublicKey } from '@dxos/client';
6
6
  import { type Space } from '@dxos/client/echo';
7
7
  import { isTypedObject, type TypedObject } from '@dxos/echo-schema';
8
- import { log } from '@dxos/log';
9
8
  import { nonNullable } from '@dxos/util';
10
9
 
11
10
  // TODO(burdon): No response?
@@ -37,16 +36,6 @@ export type FunctionSubscriptionEvent2 = {
37
36
  objects?: TypedObject[];
38
37
  };
39
38
 
40
- /**
41
- * Handler wrapper for subscription events; extracts space and objects.
42
- *
43
- * To test:
44
- * ```
45
- * curl -s -X POST -H "Content-Type: application/json" --data '{"space": "0446...1cbb"}' http://localhost:7100/dev/email-extractor
46
- * ```
47
- *
48
- * NOTE: Get space key from devtools or `dx space list --json`
49
- */
50
39
  export const subscriptionHandler = (
51
40
  handler: FunctionHandler<FunctionSubscriptionEvent2>,
52
41
  ): FunctionHandler<FunctionSubscriptionEvent> => {
@@ -60,12 +49,6 @@ export const subscriptionHandler = (
60
49
  .filter(nonNullable)
61
50
  .filter(isTypedObject);
62
51
 
63
- if (!!event.space && !space) {
64
- log.warn('invalid space', { event });
65
- } else {
66
- log.info('handler', { space: space?.key.truncate(), objects: objects?.length });
67
- }
68
-
69
52
  return handler({ event: { space, objects }, context, ...rest });
70
53
  };
71
54
  };
@@ -80,7 +80,7 @@ export class DevServer {
80
80
  res.statusCode = await this._invoke(name, req.body);
81
81
  res.end();
82
82
  } catch (err: any) {
83
- log.error(`Function failed: ${name}`, err);
83
+ log.catch(err);
84
84
  res.statusCode = 500;
85
85
  res.end();
86
86
  }
@@ -116,7 +116,6 @@ export class Scheduler {
116
116
  });
117
117
  });
118
118
 
119
- // TODO(burdon): Don't fire initially.
120
119
  // TODO(burdon): Standardize subscription handles.
121
120
  const subscriptions: (() => void)[] = [];
122
121
  const subscription = createSubscription(({ added, updated }) => {
@@ -131,8 +130,6 @@ export class Scheduler {
131
130
  });
132
131
  subscriptions.push(() => subscription.unsubscribe());
133
132
 
134
- // TODO(burdon): Create queue. Only allow one invocation per trigger at a time?
135
- // TODO(burdon): Disable trigger if keeps failing.
136
133
  const { type, props, deep, delay } = triggerSubscription;
137
134
  const update = ({ objects }: Query) => {
138
135
  subscription.update(objects);