@dxos/functions 0.1.53-main.4544117 → 0.1.53-main.499755c

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -35,7 +35,7 @@ export default (event: any, context: FunctionContext) => {
35
35
  };
36
36
  ```
37
37
 
38
- ## Running functions with dev agent
38
+ ## Running functions with the dev server:
39
39
 
40
40
  Configure the agent to run functions on a given port:
41
41
 
@@ -50,26 +50,18 @@ runtime:
50
50
  Start functions in dev mode (from the related package):
51
51
 
52
52
  ```bash
53
- dx function dev -r ts-node/register
53
+ dx function dev-server -r ts-node/register
54
54
  ```
55
55
 
56
56
  > NOTE: `-r ts-node/register` configures native TypesScript support.
57
57
 
58
- TODO(burdon): Specify additional options to import dependencies:
59
-
60
- ```bash
61
- export NODE_PATH=$(git rev-parse --show-toplevel)/packages/experimental/kai-bots/node_modules
62
-
63
- dx function dev -r ts-node/register -r chess.js
64
- ```
65
-
66
58
  Install `nodemon` to support live reloading:
67
59
 
68
60
  ```bash
69
61
  npm i -g nodemon
70
62
  export DXOS_ROOT=$(git rev-parse --show-toplevel)
71
63
 
72
- nodemon -w ./src -e ts --exec $DXOS_ROOT/packages/devtools/cli/bin/dev function dev -r ts-node/register
64
+ nodemon -w ./src -e ts --exec $DXOS_ROOT/packages/devtools/cli/bin/dev function dev-server -r ts-node/register
73
65
  ```
74
66
 
75
67
  ## Invoking functions
@@ -1,4 +1,4 @@
1
- import "@dxos/node-std/globals"
1
+ import "@dxos/node-std/globals";
2
2
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
3
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
4
  }) : x)(function(x) {
@@ -13,6 +13,7 @@ import { join } from "@dxos/node-std/path";
13
13
  import { getPortPromise } from "portfinder";
14
14
  import { Trigger } from "@dxos/async";
15
15
  import { log } from "@dxos/log";
16
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/dev-server.ts";
16
17
  var DEFAULT_PORT = 7e3;
17
18
  var DevServer = class {
18
19
  // prettier-ignore
@@ -41,10 +42,10 @@ var DevServer = class {
41
42
  this._functionHandlers[name] = handler;
42
43
  } catch (err) {
43
44
  log.error("parsing function (check functions.yml manifest)", err, {
44
- file: "dev-server.ts",
45
- line: 63,
46
- scope: this,
47
- callSite: (f, a) => f(...a)
45
+ F: __dxlog_file,
46
+ L: 63,
47
+ S: this,
48
+ C: (f, a) => f(...a)
48
49
  });
49
50
  }
50
51
  }
@@ -54,6 +55,15 @@ var DevServer = class {
54
55
  app.use(express.json());
55
56
  app.post("/:functionName", async (req, res) => {
56
57
  const functionName = req.params.functionName;
58
+ log("invoke", {
59
+ function: functionName,
60
+ data: req.body
61
+ }, {
62
+ F: __dxlog_file,
63
+ L: 74,
64
+ S: this,
65
+ C: (f, a) => f(...a)
66
+ });
57
67
  const builder = {
58
68
  status: (code) => {
59
69
  res.statusCode = code;
@@ -111,9 +121,10 @@ var DevServer = class {
111
121
  import assert from "@dxos/node-std/assert";
112
122
  import { DeferredTask } from "@dxos/async";
113
123
  import { Context } from "@dxos/context";
124
+ import { createSubscription } from "@dxos/echo-schema";
114
125
  import { log as log2 } from "@dxos/log";
115
- import { createSubscription } from "@dxos/observable-object";
116
126
  import { ComplexMap } from "@dxos/util";
127
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/trigger-manager.ts";
117
128
  var TriggerManager = class {
118
129
  constructor(_client, _triggers, _invokeOptions) {
119
130
  this._client = _client;
@@ -150,10 +161,11 @@ var TriggerManager = class {
150
161
  if (ctx.disposed) {
151
162
  return;
152
163
  }
153
- const updatedIds = /* @__PURE__ */ new Set();
164
+ let count = 0;
165
+ const objectIds = /* @__PURE__ */ new Set();
154
166
  const task = new DeferredTask(ctx, async () => {
155
- const updatedObjects = Array.from(updatedIds);
156
- updatedIds.clear();
167
+ const updatedObjects = Array.from(objectIds);
168
+ objectIds.clear();
157
169
  await this.invokeFunction(this._invokeOptions, trigger.function, {
158
170
  space: space.key,
159
171
  objects: updatedObjects
@@ -161,12 +173,26 @@ var TriggerManager = class {
161
173
  });
162
174
  const selection = createSubscription(({ added, updated }) => {
163
175
  for (const object of added) {
164
- updatedIds.add(object.id);
176
+ objectIds.add(object.id);
165
177
  }
166
- for (const object1 of updated) {
167
- updatedIds.add(object1.id);
178
+ for (const object of updated) {
179
+ objectIds.add(object.id);
180
+ }
181
+ log2.info("updated", {
182
+ space: space.key,
183
+ objects: objectIds.size,
184
+ added: added.length,
185
+ updated: updated.length,
186
+ count
187
+ }, {
188
+ F: __dxlog_file2,
189
+ L: 86,
190
+ S: this,
191
+ C: (f, a) => f(...a)
192
+ });
193
+ if (count++) {
194
+ task.schedule();
168
195
  }
169
- task.schedule();
170
196
  });
171
197
  ctx.onDispose(() => selection.unsubscribe());
172
198
  const query = space.db.query({
@@ -176,15 +202,15 @@ var TriggerManager = class {
176
202
  const unsubscribe = query.subscribe(({ objects }) => {
177
203
  selection.update(objects);
178
204
  });
179
- selection.update(query.objects);
180
205
  ctx.onDispose(unsubscribe);
181
- log2("mounted", {
206
+ log2.info("mounted", {
207
+ space: space.key,
182
208
  trigger
183
209
  }, {
184
- file: "trigger-manager.ts",
185
- line: 96,
186
- scope: this,
187
- callSite: (f, a) => f(...a)
210
+ F: __dxlog_file2,
211
+ L: 110,
212
+ S: this,
213
+ C: (f, a) => f(...a)
188
214
  });
189
215
  }
190
216
  }
@@ -208,10 +234,10 @@ var TriggerManager = class {
208
234
  log2("invoke", {
209
235
  function: functionName
210
236
  }, {
211
- file: "trigger-manager.ts",
212
- line: 115,
213
- scope: this,
214
- callSite: (f, a) => f(...a)
237
+ F: __dxlog_file2,
238
+ L: 129,
239
+ S: this,
240
+ C: (f, a) => f(...a)
215
241
  });
216
242
  const url = `${endpoint}/${runtime}/${functionName}`;
217
243
  const res = await fetch(url, {
@@ -225,20 +251,20 @@ var TriggerManager = class {
225
251
  function: functionName,
226
252
  result: await res.json()
227
253
  }, {
228
- file: "trigger-manager.ts",
229
- line: 125,
230
- scope: this,
231
- callSite: (f, a) => f(...a)
254
+ F: __dxlog_file2,
255
+ L: 139,
256
+ S: this,
257
+ C: (f, a) => f(...a)
232
258
  });
233
259
  } catch (err) {
234
- log2("error", {
260
+ log2.error("error", {
235
261
  function: functionName,
236
262
  error: err.message
237
263
  }, {
238
- file: "trigger-manager.ts",
239
- line: 127,
240
- scope: this,
241
- callSite: (f, a) => f(...a)
264
+ F: __dxlog_file2,
265
+ L: 141,
266
+ S: this,
267
+ C: (f, a) => f(...a)
242
268
  });
243
269
  }
244
270
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/runtime/dev-server.ts", "../../../src/runtime/trigger-manager.ts"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport express from 'express';\nimport http from 'http';\nimport { join } from 'node:path';\nimport { getPortPromise } from 'portfinder';\n\nimport { Trigger } from '@dxos/async';\nimport { Client } from '@dxos/client';\nimport { log } from '@dxos/log';\n\nimport { FunctionContext, FunctionHandler, FunctionsManifest, Response } from '../function';\n\nconst DEFAULT_PORT = 7000;\n\nexport type DevServerOptions = {\n directory: string;\n manifest: FunctionsManifest;\n};\n\n/**\n * Functions dev server provides a local HTTP server for testing functions.\n */\nexport class DevServer {\n private readonly _functionHandlers: Record<string, FunctionHandler> = {};\n\n private _server?: http.Server;\n private _port?: number;\n private _registrationId?: string;\n\n // prettier-ignore\n constructor(\n private readonly _client: Client,\n private readonly _options: DevServerOptions\n ) {}\n\n get port() {\n return this._port;\n }\n\n get endpoint() {\n return this._port ? `http://localhost:${this._port}` : undefined;\n }\n\n get functions() {\n return Object.keys(this._functionHandlers);\n }\n\n async initialize() {\n for (const [name, _] of Object.entries(this._options.manifest.functions)) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const module = require(join(this._options.directory, name));\n const handler = module.default;\n if (typeof handler !== 'function') {\n throw new Error(`Handler must export default function: ${name}`);\n }\n\n this._functionHandlers[name] = handler;\n } catch (err) {\n log.error('parsing function (check functions.yml manifest)', err);\n }\n }\n }\n\n async start() {\n const app = express();\n app.use(express.json());\n\n app.post('/:functionName', async (req, res) => {\n const functionName = req.params.functionName;\n\n const builder: Response = {\n status: (code: number) => {\n res.statusCode = code;\n return builder;\n },\n succeed: (result = {}) => {\n res.end(JSON.stringify(result));\n return builder;\n },\n };\n\n const context: FunctionContext = {\n client: this._client,\n status: builder.status.bind(builder),\n };\n\n void (async () => {\n try {\n await this._functionHandlers[functionName](req.body, context);\n } catch (err: any) {\n res.statusCode = 500;\n res.end(err.message);\n }\n })();\n });\n\n this._port = await getPortPromise({ startPort: DEFAULT_PORT });\n this._server = app.listen(this._port);\n\n const { registrationId } = await this._client.services.services.FunctionRegistryService!.register({\n endpoint: this.endpoint!,\n functions: this.functions.map((name) => ({ name })),\n });\n this._registrationId = registrationId;\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 this._registrationId = undefined;\n }\n\n trigger.wake();\n });\n\n await trigger.wait();\n this._server = undefined;\n this._port = undefined;\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport assert from 'node:assert';\n\nimport { DeferredTask } from '@dxos/async';\nimport { Client, PublicKey, Space } from '@dxos/client';\nimport { Context } from '@dxos/context';\nimport { log } from '@dxos/log';\nimport { createSubscription } from '@dxos/observable-object';\nimport { ComplexMap } from '@dxos/util';\n\nimport { FunctionTrigger } from '../function';\n\n// TODO(burdon): Rename.\nexport type InvokeOptions = {\n endpoint: string;\n runtime: string;\n};\n\nexport class TriggerManager {\n private readonly _mounts = new ComplexMap<\n { name: string; spaceKey: PublicKey },\n { ctx: Context; trigger: FunctionTrigger }\n >(({ name, spaceKey }) => `${spaceKey.toHex()}:${name}`);\n\n constructor(\n private readonly _client: Client,\n private readonly _triggers: FunctionTrigger[],\n private readonly _invokeOptions: InvokeOptions,\n ) {}\n\n async start() {\n // TODO(burdon): Make runtime configurable (via CLI)?\n this._client.spaces.subscribe(async (spaces) => {\n for (const space of spaces) {\n await space.waitUntilReady();\n for (const trigger of this._triggers) {\n // TODO(burdon): New context? Shared?\n await this.mount(new Context(), trigger, space);\n }\n }\n });\n }\n\n async stop() {\n for (const { name, spaceKey } of this._mounts.keys()) {\n await this.unmount(name, spaceKey);\n }\n }\n\n private async mount(ctx: Context, trigger: FunctionTrigger, space: Space) {\n const key = { name: trigger.function, spaceKey: space.key };\n const exists = this._mounts.get(key);\n if (!exists) {\n this._mounts.set(key, { ctx, trigger });\n if (ctx.disposed) {\n return;\n }\n\n const updatedIds = new Set<string>();\n const task = new DeferredTask(ctx, async () => {\n const updatedObjects = Array.from(updatedIds);\n updatedIds.clear();\n\n await this.invokeFunction(this._invokeOptions, trigger.function, {\n space: space.key,\n objects: updatedObjects,\n });\n });\n\n const selection = createSubscription(({ added, updated }) => {\n for (const object of added) {\n updatedIds.add(object.id);\n }\n for (const object of updated) {\n updatedIds.add(object.id);\n }\n\n task.schedule();\n });\n\n ctx.onDispose(() => selection.unsubscribe());\n\n const query = space.db.query({ ...trigger.subscription.props, '@type': trigger.subscription.type });\n const unsubscribe = query.subscribe(({ objects }) => {\n selection.update(objects);\n });\n\n // TODO(burdon): Subscribe method option to trigger automatically (throughout codebase).\n selection.update(query.objects);\n\n ctx.onDispose(unsubscribe);\n\n log('mounted', { trigger });\n }\n }\n\n private async unmount(name: string, spaceKey: PublicKey) {\n const key = { name, 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 async invokeFunction(options: InvokeOptions, functionName: string, data: any) {\n const { endpoint, runtime } = options;\n assert(endpoint, 'Missing endpoint');\n assert(runtime, 'Missing runtime');\n\n try {\n log('invoke', { function: functionName });\n const url = `${endpoint}/${runtime}/${functionName}`;\n const res = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(data),\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n log('result', { function: functionName, result: await res.json() });\n } catch (err: any) {\n log('error', { function: functionName, error: err.message });\n }\n }\n}\n\nexport type MountTriggerParams = {\n ctx: Context;\n client: Client;\n trigger: FunctionTrigger;\n invokeOptions: InvokeOptions;\n};\n"],
5
- "mappings": "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",
6
- "names": ["express", "join", "getPortPromise", "Trigger", "log", "DEFAULT_PORT", "DevServer", "constructor", "_client", "_options", "_functionHandlers", "port", "_port", "endpoint", "undefined", "functions", "Object", "keys", "initialize", "name", "_", "entries", "manifest", "module", "require", "join", "directory", "handler", "default", "Error", "err", "log", "error", "start", "app", "express", "use", "json", "post", "req", "res", "functionName", "params", "builder", "status", "code", "statusCode", "succeed", "result", "end", "JSON", "stringify", "context", "client", "bind", "body", "message", "getPortPromise", "startPort", "_server", "listen", "registrationId", "services", "FunctionRegistryService", "register", "map", "_registrationId", "stop", "trigger", "Trigger", "close", "unregister", "wake", "wait", "assert", "DeferredTask", "Context", "log", "createSubscription", "ComplexMap", "TriggerManager", "constructor", "_client", "_triggers", "_invokeOptions", "_mounts", "name", "spaceKey", "toHex", "start", "spaces", "subscribe", "space", "waitUntilReady", "trigger", "mount", "stop", "keys", "unmount", "ctx", "key", "function", "exists", "get", "set", "disposed", "updatedIds", "Set", "task", "updatedObjects", "Array", "from", "clear", "invokeFunction", "objects", "selection", "added", "updated", "object", "add", "id", "schedule", "onDispose", "unsubscribe", "query", "db", "subscription", "props", "type", "update", "delete", "dispose", "options", "functionName", "data", "endpoint", "runtime", "url", "res", "fetch", "method", "body", "JSON", "stringify", "headers", "result", "json", "err", "error", "message"]
4
+ "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport express from 'express';\nimport http from 'http';\nimport { join } from 'node:path';\nimport { getPortPromise } from 'portfinder';\n\nimport { Trigger } from '@dxos/async';\nimport { Client } from '@dxos/client';\nimport { log } from '@dxos/log';\n\nimport { FunctionContext, FunctionHandler, FunctionsManifest, Response } from '../function';\n\nconst DEFAULT_PORT = 7000;\n\nexport type DevServerOptions = {\n directory: string;\n manifest: FunctionsManifest;\n};\n\n/**\n * Functions dev server provides a local HTTP server for testing functions.\n */\nexport class DevServer {\n private readonly _functionHandlers: Record<string, FunctionHandler> = {};\n\n private _server?: http.Server;\n private _port?: number;\n private _registrationId?: string;\n\n // prettier-ignore\n constructor(\n private readonly _client: Client,\n private readonly _options: DevServerOptions\n ) {}\n\n get port() {\n return this._port;\n }\n\n get endpoint() {\n return this._port ? `http://localhost:${this._port}` : undefined;\n }\n\n get functions() {\n return Object.keys(this._functionHandlers);\n }\n\n async initialize() {\n for (const [name, _] of Object.entries(this._options.manifest.functions)) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const module = require(join(this._options.directory, name));\n const handler = module.default;\n if (typeof handler !== 'function') {\n throw new Error(`Handler must export default function: ${name}`);\n }\n\n this._functionHandlers[name] = handler;\n } catch (err) {\n log.error('parsing function (check functions.yml manifest)', err);\n }\n }\n }\n\n async start() {\n const app = express();\n app.use(express.json());\n\n app.post('/:functionName', async (req, res) => {\n const functionName = req.params.functionName;\n log('invoke', { function: functionName, data: req.body });\n\n const builder: Response = {\n status: (code: number) => {\n res.statusCode = code;\n return builder;\n },\n succeed: (result = {}) => {\n res.end(JSON.stringify(result));\n return builder;\n },\n };\n\n const context: FunctionContext = {\n client: this._client,\n status: builder.status.bind(builder),\n };\n\n void (async () => {\n try {\n await this._functionHandlers[functionName](req.body, context);\n } catch (err: any) {\n res.statusCode = 500;\n res.end(err.message);\n }\n })();\n });\n\n this._port = await getPortPromise({ startPort: DEFAULT_PORT });\n this._server = app.listen(this._port);\n\n // TODO(burdon): Check plugin is registered.\n // TypeError: Cannot read properties of undefined (reading 'register')\n const { registrationId } = await this._client.services.services.FunctionRegistryService!.register({\n endpoint: this.endpoint!,\n functions: this.functions.map((name) => ({ name })),\n });\n this._registrationId = registrationId;\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 this._registrationId = undefined;\n }\n\n trigger.wake();\n });\n\n await trigger.wait();\n this._server = undefined;\n this._port = undefined;\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport assert from 'node:assert';\n\nimport { DeferredTask } from '@dxos/async';\nimport { Client, PublicKey } from '@dxos/client';\nimport type { Space } from '@dxos/client/echo';\nimport { Context } from '@dxos/context';\nimport { createSubscription } from '@dxos/echo-schema';\nimport { log } from '@dxos/log';\nimport { ComplexMap } from '@dxos/util';\n\nimport { FunctionTrigger } from '../function';\n\n// TODO(burdon): Rename.\nexport type InvokeOptions = {\n endpoint: string;\n runtime: string;\n};\n\nexport class TriggerManager {\n private readonly _mounts = new ComplexMap<\n { name: string; spaceKey: PublicKey },\n { ctx: Context; trigger: FunctionTrigger }\n >(({ name, spaceKey }) => `${spaceKey.toHex()}:${name}`);\n\n constructor(\n private readonly _client: Client,\n private readonly _triggers: FunctionTrigger[],\n private readonly _invokeOptions: InvokeOptions,\n ) {}\n\n async start() {\n // TODO(burdon): Make runtime configurable (via CLI)?\n this._client.spaces.subscribe(async (spaces) => {\n for (const space of spaces) {\n await space.waitUntilReady();\n for (const trigger of this._triggers) {\n // TODO(burdon): New context? Shared?\n await this.mount(new Context(), trigger, space);\n }\n }\n });\n }\n\n async stop() {\n for (const { name, spaceKey } of this._mounts.keys()) {\n await this.unmount(name, spaceKey);\n }\n }\n\n private async mount(ctx: Context, trigger: FunctionTrigger, space: Space) {\n const key = { name: trigger.function, spaceKey: space.key };\n const exists = this._mounts.get(key);\n if (!exists) {\n this._mounts.set(key, { ctx, trigger });\n if (ctx.disposed) {\n return;\n }\n\n // TODO(burdon): Factor out subscription/result delta.\n\n let count = 0;\n const objectIds = new Set<string>();\n const task = new DeferredTask(ctx, async () => {\n const updatedObjects = Array.from(objectIds);\n objectIds.clear();\n\n await this.invokeFunction(this._invokeOptions, trigger.function, {\n space: space.key,\n objects: updatedObjects,\n });\n });\n\n // TODO(burdon): Removed?\n const selection = 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 log.info('updated', {\n space: space.key,\n objects: objectIds.size,\n added: added.length,\n updated: updated.length,\n count,\n });\n if (count++) {\n task.schedule();\n }\n });\n\n ctx.onDispose(() => selection.unsubscribe());\n\n const query = space.db.query({ ...trigger.subscription.props, '@type': trigger.subscription.type });\n const unsubscribe = query.subscribe(({ objects }) => {\n selection.update(objects);\n });\n\n // Trigger first update, but don't schedule task.\n // selection.update(query.objects);\n\n ctx.onDispose(unsubscribe);\n\n log.info('mounted', { space: space.key, trigger });\n }\n }\n\n private async unmount(name: string, spaceKey: PublicKey) {\n const key = { name, 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 async invokeFunction(options: InvokeOptions, functionName: string, data: any) {\n const { endpoint, runtime } = options;\n assert(endpoint, 'Missing endpoint');\n assert(runtime, 'Missing runtime');\n\n try {\n log('invoke', { function: functionName });\n const url = `${endpoint}/${runtime}/${functionName}`;\n const res = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(data),\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n log('result', { function: functionName, result: await res.json() });\n } catch (err: any) {\n log.error('error', { function: functionName, error: err.message });\n }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["express", "join", "getPortPromise", "Trigger", "log", "DEFAULT_PORT", "DevServer", "constructor", "_client", "_options", "_functionHandlers", "port", "_port", "endpoint", "undefined", "functions", "Object", "keys", "initialize", "name", "_", "entries", "manifest", "module", "require", "join", "directory", "handler", "default", "Error", "err", "log", "error", "start", "app", "express", "use", "json", "post", "req", "res", "functionName", "params", "function", "data", "body", "builder", "status", "code", "statusCode", "succeed", "result", "end", "JSON", "stringify", "context", "client", "bind", "message", "getPortPromise", "startPort", "_server", "listen", "registrationId", "services", "FunctionRegistryService", "register", "map", "_registrationId", "stop", "trigger", "Trigger", "close", "unregister", "wake", "wait", "assert", "DeferredTask", "Context", "createSubscription", "log", "ComplexMap", "TriggerManager", "constructor", "_client", "_triggers", "_invokeOptions", "_mounts", "name", "spaceKey", "toHex", "start", "spaces", "subscribe", "space", "waitUntilReady", "trigger", "mount", "stop", "keys", "unmount", "ctx", "key", "function", "exists", "get", "set", "disposed", "count", "objectIds", "Set", "task", "updatedObjects", "Array", "from", "clear", "invokeFunction", "objects", "selection", "added", "updated", "object", "add", "id", "info", "size", "length", "schedule", "onDispose", "unsubscribe", "query", "db", "subscription", "props", "type", "update", "delete", "dispose", "options", "functionName", "data", "endpoint", "runtime", "url", "res", "fetch", "method", "body", "JSON", "stringify", "headers", "result", "json", "err", "error", "message"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"packages/core/functions/src/function.ts":{"bytes":1332,"imports":[]},"packages/core/functions/src/runtime/dev-server.ts":{"bytes":12360,"imports":[{"path":"express","kind":"import-statement","external":true},{"path":"@dxos/node-std/path","kind":"import-statement","external":true},{"path":"portfinder","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"<runtime>","kind":"import-statement","external":true}]},"packages/core/functions/src/runtime/trigger-manager.ts":{"bytes":14884,"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/observable-object","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}]},"packages/core/functions/src/runtime/index.ts":{"bytes":489,"imports":[{"path":"packages/core/functions/src/runtime/dev-server.ts","kind":"import-statement","original":"./dev-server"},{"path":"packages/core/functions/src/runtime/trigger-manager.ts","kind":"import-statement","original":"./trigger-manager"}]},"packages/core/functions/src/index.ts":{"bytes":463,"imports":[{"path":"packages/core/functions/src/function.ts","kind":"import-statement","original":"./function"},{"path":"packages/core/functions/src/runtime/index.ts","kind":"import-statement","original":"./runtime"}]}},"outputs":{"packages/core/functions/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":13494},"packages/core/functions/dist/lib/browser/index.mjs":{"imports":[{"path":"express","kind":"import-statement","external":true},{"path":"@dxos/node-std/path","kind":"import-statement","external":true},{"path":"portfinder","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/observable-object","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["DevServer","TriggerManager"],"entryPoint":"packages/core/functions/src/index.ts","inputs":{"packages/core/functions/src/index.ts":{"bytesInOutput":0},"packages/core/functions/src/runtime/dev-server.ts":{"bytesInOutput":2855},"packages/core/functions/src/runtime/index.ts":{"bytesInOutput":0},"packages/core/functions/src/runtime/trigger-manager.ts":{"bytesInOutput":3764}},"bytes":7214}}}
1
+ {"inputs":{"packages/core/functions/src/function.ts":{"bytes":1422,"imports":[]},"packages/core/functions/src/runtime/dev-server.ts":{"bytes":13335,"imports":[{"path":"express","kind":"import-statement","external":true},{"path":"@dxos/node-std/path","kind":"import-statement","external":true},{"path":"portfinder","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"<runtime>","kind":"import-statement","external":true}]},"packages/core/functions/src/runtime/trigger-manager.ts":{"bytes":16196,"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","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}]},"packages/core/functions/src/runtime/index.ts":{"bytes":584,"imports":[{"path":"packages/core/functions/src/runtime/dev-server.ts","kind":"import-statement","original":"./dev-server"},{"path":"packages/core/functions/src/runtime/trigger-manager.ts","kind":"import-statement","original":"./trigger-manager"}]},"packages/core/functions/src/index.ts":{"bytes":550,"imports":[{"path":"packages/core/functions/src/function.ts","kind":"import-statement","original":"./function"},{"path":"packages/core/functions/src/runtime/index.ts","kind":"import-statement","original":"./runtime"}]}},"outputs":{"packages/core/functions/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":14209},"packages/core/functions/dist/lib/browser/index.mjs":{"imports":[{"path":"express","kind":"import-statement","external":true},{"path":"@dxos/node-std/path","kind":"import-statement","external":true},{"path":"portfinder","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","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}],"exports":["DevServer","TriggerManager"],"entryPoint":"packages/core/functions/src/index.ts","inputs":{"packages/core/functions/src/index.ts":{"bytesInOutput":0},"packages/core/functions/src/runtime/dev-server.ts":{"bytesInOutput":3119},"packages/core/functions/src/runtime/index.ts":{"bytesInOutput":0},"packages/core/functions/src/runtime/trigger-manager.ts":{"bytesInOutput":4112}},"bytes":7827}}}
@@ -41,6 +41,7 @@ var import_node_path = require("node:path");
41
41
  var import_portfinder = require("portfinder");
42
42
  var import_async = require("@dxos/async");
43
43
  var import_log = require("@dxos/log");
44
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/dev-server.ts";
44
45
  var DEFAULT_PORT = 7e3;
45
46
  var DevServer = class {
46
47
  // prettier-ignore
@@ -69,10 +70,10 @@ var DevServer = class {
69
70
  this._functionHandlers[name] = handler;
70
71
  } catch (err) {
71
72
  import_log.log.error("parsing function (check functions.yml manifest)", err, {
72
- file: "dev-server.ts",
73
- line: 63,
74
- scope: this,
75
- callSite: (f, a) => f(...a)
73
+ F: __dxlog_file,
74
+ L: 63,
75
+ S: this,
76
+ C: (f, a) => f(...a)
76
77
  });
77
78
  }
78
79
  }
@@ -82,6 +83,15 @@ var DevServer = class {
82
83
  app.use(import_express.default.json());
83
84
  app.post("/:functionName", async (req, res) => {
84
85
  const functionName = req.params.functionName;
86
+ (0, import_log.log)("invoke", {
87
+ function: functionName,
88
+ data: req.body
89
+ }, {
90
+ F: __dxlog_file,
91
+ L: 74,
92
+ S: this,
93
+ C: (f, a) => f(...a)
94
+ });
85
95
  const builder = {
86
96
  status: (code) => {
87
97
  res.statusCode = code;
@@ -139,9 +149,10 @@ var DevServer = class {
139
149
  var import_node_assert = __toESM(require("node:assert"));
140
150
  var import_async2 = require("@dxos/async");
141
151
  var import_context = require("@dxos/context");
152
+ var import_echo_schema = require("@dxos/echo-schema");
142
153
  var import_log2 = require("@dxos/log");
143
- var import_observable_object = require("@dxos/observable-object");
144
154
  var import_util = require("@dxos/util");
155
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/functions/src/runtime/trigger-manager.ts";
145
156
  var TriggerManager = class {
146
157
  constructor(_client, _triggers, _invokeOptions) {
147
158
  this._client = _client;
@@ -178,23 +189,38 @@ var TriggerManager = class {
178
189
  if (ctx.disposed) {
179
190
  return;
180
191
  }
181
- const updatedIds = /* @__PURE__ */ new Set();
192
+ let count = 0;
193
+ const objectIds = /* @__PURE__ */ new Set();
182
194
  const task = new import_async2.DeferredTask(ctx, async () => {
183
- const updatedObjects = Array.from(updatedIds);
184
- updatedIds.clear();
195
+ const updatedObjects = Array.from(objectIds);
196
+ objectIds.clear();
185
197
  await this.invokeFunction(this._invokeOptions, trigger.function, {
186
198
  space: space.key,
187
199
  objects: updatedObjects
188
200
  });
189
201
  });
190
- const selection = (0, import_observable_object.createSubscription)(({ added, updated }) => {
202
+ const selection = (0, import_echo_schema.createSubscription)(({ added, updated }) => {
191
203
  for (const object of added) {
192
- updatedIds.add(object.id);
204
+ objectIds.add(object.id);
193
205
  }
194
- for (const object1 of updated) {
195
- updatedIds.add(object1.id);
206
+ for (const object of updated) {
207
+ objectIds.add(object.id);
208
+ }
209
+ import_log2.log.info("updated", {
210
+ space: space.key,
211
+ objects: objectIds.size,
212
+ added: added.length,
213
+ updated: updated.length,
214
+ count
215
+ }, {
216
+ F: __dxlog_file2,
217
+ L: 86,
218
+ S: this,
219
+ C: (f, a) => f(...a)
220
+ });
221
+ if (count++) {
222
+ task.schedule();
196
223
  }
197
- task.schedule();
198
224
  });
199
225
  ctx.onDispose(() => selection.unsubscribe());
200
226
  const query = space.db.query({
@@ -204,15 +230,15 @@ var TriggerManager = class {
204
230
  const unsubscribe = query.subscribe(({ objects }) => {
205
231
  selection.update(objects);
206
232
  });
207
- selection.update(query.objects);
208
233
  ctx.onDispose(unsubscribe);
209
- (0, import_log2.log)("mounted", {
234
+ import_log2.log.info("mounted", {
235
+ space: space.key,
210
236
  trigger
211
237
  }, {
212
- file: "trigger-manager.ts",
213
- line: 96,
214
- scope: this,
215
- callSite: (f, a) => f(...a)
238
+ F: __dxlog_file2,
239
+ L: 110,
240
+ S: this,
241
+ C: (f, a) => f(...a)
216
242
  });
217
243
  }
218
244
  }
@@ -236,10 +262,10 @@ var TriggerManager = class {
236
262
  (0, import_log2.log)("invoke", {
237
263
  function: functionName
238
264
  }, {
239
- file: "trigger-manager.ts",
240
- line: 115,
241
- scope: this,
242
- callSite: (f, a) => f(...a)
265
+ F: __dxlog_file2,
266
+ L: 129,
267
+ S: this,
268
+ C: (f, a) => f(...a)
243
269
  });
244
270
  const url = `${endpoint}/${runtime}/${functionName}`;
245
271
  const res = await fetch(url, {
@@ -253,20 +279,20 @@ var TriggerManager = class {
253
279
  function: functionName,
254
280
  result: await res.json()
255
281
  }, {
256
- file: "trigger-manager.ts",
257
- line: 125,
258
- scope: this,
259
- callSite: (f, a) => f(...a)
282
+ F: __dxlog_file2,
283
+ L: 139,
284
+ S: this,
285
+ C: (f, a) => f(...a)
260
286
  });
261
287
  } catch (err) {
262
- (0, import_log2.log)("error", {
288
+ import_log2.log.error("error", {
263
289
  function: functionName,
264
290
  error: err.message
265
291
  }, {
266
- file: "trigger-manager.ts",
267
- line: 127,
268
- scope: this,
269
- callSite: (f, a) => f(...a)
292
+ F: __dxlog_file2,
293
+ L: 141,
294
+ S: this,
295
+ C: (f, a) => f(...a)
270
296
  });
271
297
  }
272
298
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/index.ts", "../../../src/runtime/dev-server.ts", "../../../src/runtime/trigger-manager.ts"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nexport * from './function';\nexport * from './runtime';\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport express from 'express';\nimport http from 'http';\nimport { join } from 'node:path';\nimport { getPortPromise } from 'portfinder';\n\nimport { Trigger } from '@dxos/async';\nimport { Client } from '@dxos/client';\nimport { log } from '@dxos/log';\n\nimport { FunctionContext, FunctionHandler, FunctionsManifest, Response } from '../function';\n\nconst DEFAULT_PORT = 7000;\n\nexport type DevServerOptions = {\n directory: string;\n manifest: FunctionsManifest;\n};\n\n/**\n * Functions dev server provides a local HTTP server for testing functions.\n */\nexport class DevServer {\n private readonly _functionHandlers: Record<string, FunctionHandler> = {};\n\n private _server?: http.Server;\n private _port?: number;\n private _registrationId?: string;\n\n // prettier-ignore\n constructor(\n private readonly _client: Client,\n private readonly _options: DevServerOptions\n ) {}\n\n get port() {\n return this._port;\n }\n\n get endpoint() {\n return this._port ? `http://localhost:${this._port}` : undefined;\n }\n\n get functions() {\n return Object.keys(this._functionHandlers);\n }\n\n async initialize() {\n for (const [name, _] of Object.entries(this._options.manifest.functions)) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const module = require(join(this._options.directory, name));\n const handler = module.default;\n if (typeof handler !== 'function') {\n throw new Error(`Handler must export default function: ${name}`);\n }\n\n this._functionHandlers[name] = handler;\n } catch (err) {\n log.error('parsing function (check functions.yml manifest)', err);\n }\n }\n }\n\n async start() {\n const app = express();\n app.use(express.json());\n\n app.post('/:functionName', async (req, res) => {\n const functionName = req.params.functionName;\n\n const builder: Response = {\n status: (code: number) => {\n res.statusCode = code;\n return builder;\n },\n succeed: (result = {}) => {\n res.end(JSON.stringify(result));\n return builder;\n },\n };\n\n const context: FunctionContext = {\n client: this._client,\n status: builder.status.bind(builder),\n };\n\n void (async () => {\n try {\n await this._functionHandlers[functionName](req.body, context);\n } catch (err: any) {\n res.statusCode = 500;\n res.end(err.message);\n }\n })();\n });\n\n this._port = await getPortPromise({ startPort: DEFAULT_PORT });\n this._server = app.listen(this._port);\n\n const { registrationId } = await this._client.services.services.FunctionRegistryService!.register({\n endpoint: this.endpoint!,\n functions: this.functions.map((name) => ({ name })),\n });\n this._registrationId = registrationId;\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 this._registrationId = undefined;\n }\n\n trigger.wake();\n });\n\n await trigger.wait();\n this._server = undefined;\n this._port = undefined;\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport assert from 'node:assert';\n\nimport { DeferredTask } from '@dxos/async';\nimport { Client, PublicKey, Space } from '@dxos/client';\nimport { Context } from '@dxos/context';\nimport { log } from '@dxos/log';\nimport { createSubscription } from '@dxos/observable-object';\nimport { ComplexMap } from '@dxos/util';\n\nimport { FunctionTrigger } from '../function';\n\n// TODO(burdon): Rename.\nexport type InvokeOptions = {\n endpoint: string;\n runtime: string;\n};\n\nexport class TriggerManager {\n private readonly _mounts = new ComplexMap<\n { name: string; spaceKey: PublicKey },\n { ctx: Context; trigger: FunctionTrigger }\n >(({ name, spaceKey }) => `${spaceKey.toHex()}:${name}`);\n\n constructor(\n private readonly _client: Client,\n private readonly _triggers: FunctionTrigger[],\n private readonly _invokeOptions: InvokeOptions,\n ) {}\n\n async start() {\n // TODO(burdon): Make runtime configurable (via CLI)?\n this._client.spaces.subscribe(async (spaces) => {\n for (const space of spaces) {\n await space.waitUntilReady();\n for (const trigger of this._triggers) {\n // TODO(burdon): New context? Shared?\n await this.mount(new Context(), trigger, space);\n }\n }\n });\n }\n\n async stop() {\n for (const { name, spaceKey } of this._mounts.keys()) {\n await this.unmount(name, spaceKey);\n }\n }\n\n private async mount(ctx: Context, trigger: FunctionTrigger, space: Space) {\n const key = { name: trigger.function, spaceKey: space.key };\n const exists = this._mounts.get(key);\n if (!exists) {\n this._mounts.set(key, { ctx, trigger });\n if (ctx.disposed) {\n return;\n }\n\n const updatedIds = new Set<string>();\n const task = new DeferredTask(ctx, async () => {\n const updatedObjects = Array.from(updatedIds);\n updatedIds.clear();\n\n await this.invokeFunction(this._invokeOptions, trigger.function, {\n space: space.key,\n objects: updatedObjects,\n });\n });\n\n const selection = createSubscription(({ added, updated }) => {\n for (const object of added) {\n updatedIds.add(object.id);\n }\n for (const object of updated) {\n updatedIds.add(object.id);\n }\n\n task.schedule();\n });\n\n ctx.onDispose(() => selection.unsubscribe());\n\n const query = space.db.query({ ...trigger.subscription.props, '@type': trigger.subscription.type });\n const unsubscribe = query.subscribe(({ objects }) => {\n selection.update(objects);\n });\n\n // TODO(burdon): Subscribe method option to trigger automatically (throughout codebase).\n selection.update(query.objects);\n\n ctx.onDispose(unsubscribe);\n\n log('mounted', { trigger });\n }\n }\n\n private async unmount(name: string, spaceKey: PublicKey) {\n const key = { name, 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 async invokeFunction(options: InvokeOptions, functionName: string, data: any) {\n const { endpoint, runtime } = options;\n assert(endpoint, 'Missing endpoint');\n assert(runtime, 'Missing runtime');\n\n try {\n log('invoke', { function: functionName });\n const url = `${endpoint}/${runtime}/${functionName}`;\n const res = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(data),\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n log('result', { function: functionName, result: await res.json() });\n } catch (err: any) {\n log('error', { function: functionName, error: err.message });\n }\n }\n}\n\nexport type MountTriggerParams = {\n ctx: Context;\n client: Client;\n trigger: FunctionTrigger;\n invokeOptions: InvokeOptions;\n};\n"],
5
- "mappings": "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",
6
- "names": ["DEFAULT_PORT", "DevServer", "constructor", "_client", "_options", "_functionHandlers", "port", "_port", "endpoint", "undefined", "functions", "Object", "keys", "initialize", "name", "_", "entries", "manifest", "module", "require", "join", "directory", "handler", "default", "Error", "err", "log", "error", "start", "app", "express", "use", "json", "post", "req", "res", "functionName", "params", "builder", "status", "code", "statusCode", "succeed", "result", "end", "JSON", "stringify", "context", "client", "bind", "body", "message", "getPortPromise", "startPort", "_server", "listen", "registrationId", "services", "FunctionRegistryService", "register", "map", "_registrationId", "stop", "trigger", "Trigger", "close", "unregister", "wake", "wait", "import_async", "import_log", "TriggerManager", "constructor", "_client", "_triggers", "_invokeOptions", "_mounts", "ComplexMap", "name", "spaceKey", "toHex", "start", "spaces", "subscribe", "space", "waitUntilReady", "trigger", "mount", "Context", "stop", "keys", "unmount", "ctx", "key", "function", "exists", "get", "set", "disposed", "updatedIds", "Set", "task", "DeferredTask", "updatedObjects", "Array", "from", "clear", "invokeFunction", "objects", "selection", "createSubscription", "added", "updated", "object", "add", "id", "schedule", "onDispose", "unsubscribe", "query", "db", "subscription", "props", "type", "update", "log", "delete", "dispose", "options", "functionName", "data", "endpoint", "runtime", "assert", "url", "res", "fetch", "method", "body", "JSON", "stringify", "headers", "result", "json", "err", "error", "message"]
4
+ "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nexport * from './function';\nexport * from './runtime';\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport express from 'express';\nimport http from 'http';\nimport { join } from 'node:path';\nimport { getPortPromise } from 'portfinder';\n\nimport { Trigger } from '@dxos/async';\nimport { Client } from '@dxos/client';\nimport { log } from '@dxos/log';\n\nimport { FunctionContext, FunctionHandler, FunctionsManifest, Response } from '../function';\n\nconst DEFAULT_PORT = 7000;\n\nexport type DevServerOptions = {\n directory: string;\n manifest: FunctionsManifest;\n};\n\n/**\n * Functions dev server provides a local HTTP server for testing functions.\n */\nexport class DevServer {\n private readonly _functionHandlers: Record<string, FunctionHandler> = {};\n\n private _server?: http.Server;\n private _port?: number;\n private _registrationId?: string;\n\n // prettier-ignore\n constructor(\n private readonly _client: Client,\n private readonly _options: DevServerOptions\n ) {}\n\n get port() {\n return this._port;\n }\n\n get endpoint() {\n return this._port ? `http://localhost:${this._port}` : undefined;\n }\n\n get functions() {\n return Object.keys(this._functionHandlers);\n }\n\n async initialize() {\n for (const [name, _] of Object.entries(this._options.manifest.functions)) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const module = require(join(this._options.directory, name));\n const handler = module.default;\n if (typeof handler !== 'function') {\n throw new Error(`Handler must export default function: ${name}`);\n }\n\n this._functionHandlers[name] = handler;\n } catch (err) {\n log.error('parsing function (check functions.yml manifest)', err);\n }\n }\n }\n\n async start() {\n const app = express();\n app.use(express.json());\n\n app.post('/:functionName', async (req, res) => {\n const functionName = req.params.functionName;\n log('invoke', { function: functionName, data: req.body });\n\n const builder: Response = {\n status: (code: number) => {\n res.statusCode = code;\n return builder;\n },\n succeed: (result = {}) => {\n res.end(JSON.stringify(result));\n return builder;\n },\n };\n\n const context: FunctionContext = {\n client: this._client,\n status: builder.status.bind(builder),\n };\n\n void (async () => {\n try {\n await this._functionHandlers[functionName](req.body, context);\n } catch (err: any) {\n res.statusCode = 500;\n res.end(err.message);\n }\n })();\n });\n\n this._port = await getPortPromise({ startPort: DEFAULT_PORT });\n this._server = app.listen(this._port);\n\n // TODO(burdon): Check plugin is registered.\n // TypeError: Cannot read properties of undefined (reading 'register')\n const { registrationId } = await this._client.services.services.FunctionRegistryService!.register({\n endpoint: this.endpoint!,\n functions: this.functions.map((name) => ({ name })),\n });\n this._registrationId = registrationId;\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 this._registrationId = undefined;\n }\n\n trigger.wake();\n });\n\n await trigger.wait();\n this._server = undefined;\n this._port = undefined;\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport assert from 'node:assert';\n\nimport { DeferredTask } from '@dxos/async';\nimport { Client, PublicKey } from '@dxos/client';\nimport type { Space } from '@dxos/client/echo';\nimport { Context } from '@dxos/context';\nimport { createSubscription } from '@dxos/echo-schema';\nimport { log } from '@dxos/log';\nimport { ComplexMap } from '@dxos/util';\n\nimport { FunctionTrigger } from '../function';\n\n// TODO(burdon): Rename.\nexport type InvokeOptions = {\n endpoint: string;\n runtime: string;\n};\n\nexport class TriggerManager {\n private readonly _mounts = new ComplexMap<\n { name: string; spaceKey: PublicKey },\n { ctx: Context; trigger: FunctionTrigger }\n >(({ name, spaceKey }) => `${spaceKey.toHex()}:${name}`);\n\n constructor(\n private readonly _client: Client,\n private readonly _triggers: FunctionTrigger[],\n private readonly _invokeOptions: InvokeOptions,\n ) {}\n\n async start() {\n // TODO(burdon): Make runtime configurable (via CLI)?\n this._client.spaces.subscribe(async (spaces) => {\n for (const space of spaces) {\n await space.waitUntilReady();\n for (const trigger of this._triggers) {\n // TODO(burdon): New context? Shared?\n await this.mount(new Context(), trigger, space);\n }\n }\n });\n }\n\n async stop() {\n for (const { name, spaceKey } of this._mounts.keys()) {\n await this.unmount(name, spaceKey);\n }\n }\n\n private async mount(ctx: Context, trigger: FunctionTrigger, space: Space) {\n const key = { name: trigger.function, spaceKey: space.key };\n const exists = this._mounts.get(key);\n if (!exists) {\n this._mounts.set(key, { ctx, trigger });\n if (ctx.disposed) {\n return;\n }\n\n // TODO(burdon): Factor out subscription/result delta.\n\n let count = 0;\n const objectIds = new Set<string>();\n const task = new DeferredTask(ctx, async () => {\n const updatedObjects = Array.from(objectIds);\n objectIds.clear();\n\n await this.invokeFunction(this._invokeOptions, trigger.function, {\n space: space.key,\n objects: updatedObjects,\n });\n });\n\n // TODO(burdon): Removed?\n const selection = 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 log.info('updated', {\n space: space.key,\n objects: objectIds.size,\n added: added.length,\n updated: updated.length,\n count,\n });\n if (count++) {\n task.schedule();\n }\n });\n\n ctx.onDispose(() => selection.unsubscribe());\n\n const query = space.db.query({ ...trigger.subscription.props, '@type': trigger.subscription.type });\n const unsubscribe = query.subscribe(({ objects }) => {\n selection.update(objects);\n });\n\n // Trigger first update, but don't schedule task.\n // selection.update(query.objects);\n\n ctx.onDispose(unsubscribe);\n\n log.info('mounted', { space: space.key, trigger });\n }\n }\n\n private async unmount(name: string, spaceKey: PublicKey) {\n const key = { name, 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 async invokeFunction(options: InvokeOptions, functionName: string, data: any) {\n const { endpoint, runtime } = options;\n assert(endpoint, 'Missing endpoint');\n assert(runtime, 'Missing runtime');\n\n try {\n log('invoke', { function: functionName });\n const url = `${endpoint}/${runtime}/${functionName}`;\n const res = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(data),\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n log('result', { function: functionName, result: await res.json() });\n } catch (err: any) {\n log.error('error', { function: functionName, error: err.message });\n }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["DEFAULT_PORT", "DevServer", "constructor", "_client", "_options", "_functionHandlers", "port", "_port", "endpoint", "undefined", "functions", "Object", "keys", "initialize", "name", "_", "entries", "manifest", "module", "require", "join", "directory", "handler", "default", "Error", "err", "log", "error", "start", "app", "express", "use", "json", "post", "req", "res", "functionName", "params", "function", "data", "body", "builder", "status", "code", "statusCode", "succeed", "result", "end", "JSON", "stringify", "context", "client", "bind", "message", "getPortPromise", "startPort", "_server", "listen", "registrationId", "services", "FunctionRegistryService", "register", "map", "_registrationId", "stop", "trigger", "Trigger", "close", "unregister", "wake", "wait", "import_async", "import_log", "TriggerManager", "constructor", "_client", "_triggers", "_invokeOptions", "_mounts", "ComplexMap", "name", "spaceKey", "toHex", "start", "spaces", "subscribe", "space", "waitUntilReady", "trigger", "mount", "Context", "stop", "keys", "unmount", "ctx", "key", "function", "exists", "get", "set", "disposed", "count", "objectIds", "Set", "task", "DeferredTask", "updatedObjects", "Array", "from", "clear", "invokeFunction", "objects", "selection", "createSubscription", "added", "updated", "object", "add", "id", "log", "info", "size", "length", "schedule", "onDispose", "unsubscribe", "query", "db", "subscription", "props", "type", "update", "delete", "dispose", "options", "functionName", "data", "endpoint", "runtime", "assert", "url", "res", "fetch", "method", "body", "JSON", "stringify", "headers", "result", "json", "err", "error", "message"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"packages/core/functions/src/function.ts":{"bytes":1332,"imports":[]},"packages/core/functions/src/runtime/dev-server.ts":{"bytes":12360,"imports":[{"path":"express","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"portfinder","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true}]},"packages/core/functions/src/runtime/trigger-manager.ts":{"bytes":14884,"imports":[{"path":"node:assert","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/observable-object","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}]},"packages/core/functions/src/runtime/index.ts":{"bytes":489,"imports":[{"path":"packages/core/functions/src/runtime/dev-server.ts","kind":"import-statement","original":"./dev-server"},{"path":"packages/core/functions/src/runtime/trigger-manager.ts","kind":"import-statement","original":"./trigger-manager"}]},"packages/core/functions/src/index.ts":{"bytes":463,"imports":[{"path":"packages/core/functions/src/function.ts","kind":"import-statement","original":"./function"},{"path":"packages/core/functions/src/runtime/index.ts","kind":"import-statement","original":"./runtime"}]}},"outputs":{"packages/core/functions/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":13585},"packages/core/functions/dist/lib/node/index.cjs":{"imports":[{"path":"express","kind":"require-call","external":true},{"path":"node:path","kind":"require-call","external":true},{"path":"portfinder","kind":"require-call","external":true},{"path":"@dxos/async","kind":"require-call","external":true},{"path":"@dxos/log","kind":"require-call","external":true},{"path":"node:assert","kind":"require-call","external":true},{"path":"@dxos/async","kind":"require-call","external":true},{"path":"@dxos/context","kind":"require-call","external":true},{"path":"@dxos/log","kind":"require-call","external":true},{"path":"@dxos/observable-object","kind":"require-call","external":true},{"path":"@dxos/util","kind":"require-call","external":true}],"exports":[],"entryPoint":"packages/core/functions/src/index.ts","inputs":{"packages/core/functions/src/index.ts":{"bytesInOutput":163},"packages/core/functions/src/runtime/dev-server.ts":{"bytesInOutput":2991},"packages/core/functions/src/runtime/index.ts":{"bytesInOutput":0},"packages/core/functions/src/runtime/trigger-manager.ts":{"bytesInOutput":3973}},"bytes":8833}}}
1
+ {"inputs":{"packages/core/functions/src/function.ts":{"bytes":1422,"imports":[]},"packages/core/functions/src/runtime/dev-server.ts":{"bytes":13335,"imports":[{"path":"express","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"portfinder","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true}]},"packages/core/functions/src/runtime/trigger-manager.ts":{"bytes":16196,"imports":[{"path":"node:assert","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","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}]},"packages/core/functions/src/runtime/index.ts":{"bytes":584,"imports":[{"path":"packages/core/functions/src/runtime/dev-server.ts","kind":"import-statement","original":"./dev-server"},{"path":"packages/core/functions/src/runtime/trigger-manager.ts","kind":"import-statement","original":"./trigger-manager"}]},"packages/core/functions/src/index.ts":{"bytes":550,"imports":[{"path":"packages/core/functions/src/function.ts","kind":"import-statement","original":"./function"},{"path":"packages/core/functions/src/runtime/index.ts","kind":"import-statement","original":"./runtime"}]}},"outputs":{"packages/core/functions/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":14294},"packages/core/functions/dist/lib/node/index.cjs":{"imports":[{"path":"express","kind":"require-call","external":true},{"path":"node:path","kind":"require-call","external":true},{"path":"portfinder","kind":"require-call","external":true},{"path":"@dxos/async","kind":"require-call","external":true},{"path":"@dxos/log","kind":"require-call","external":true},{"path":"node:assert","kind":"require-call","external":true},{"path":"@dxos/async","kind":"require-call","external":true},{"path":"@dxos/context","kind":"require-call","external":true},{"path":"@dxos/echo-schema","kind":"require-call","external":true},{"path":"@dxos/log","kind":"require-call","external":true},{"path":"@dxos/util","kind":"require-call","external":true}],"exports":[],"entryPoint":"packages/core/functions/src/index.ts","inputs":{"packages/core/functions/src/index.ts":{"bytesInOutput":163},"packages/core/functions/src/runtime/dev-server.ts":{"bytesInOutput":3271},"packages/core/functions/src/runtime/index.ts":{"bytesInOutput":0},"packages/core/functions/src/runtime/trigger-manager.ts":{"bytesInOutput":4310}},"bytes":9450}}}
@@ -1 +1 @@
1
- {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../../../src/runtime/dev-server.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAGtC,OAAO,EAAoC,iBAAiB,EAAY,MAAM,aAAa,CAAC;AAI5F,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,iBAAiB,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,qBAAa,SAAS;IASlB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAT3B,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAuC;IAEzE,OAAO,CAAC,OAAO,CAAC,CAAc;IAC9B,OAAO,CAAC,KAAK,CAAC,CAAS;IACvB,OAAO,CAAC,eAAe,CAAC,CAAS;gBAId,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,gBAAgB;IAG7C,IAAI,IAAI,uBAEP;IAED,IAAI,QAAQ,uBAEX;IAED,IAAI,SAAS,aAEZ;IAEK,UAAU;IAiBV,KAAK;IA2CL,IAAI;CAiBX"}
1
+ {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../../../src/runtime/dev-server.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAGtC,OAAO,EAAoC,iBAAiB,EAAY,MAAM,aAAa,CAAC;AAI5F,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,iBAAiB,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,qBAAa,SAAS;IASlB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAT3B,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAuC;IAEzE,OAAO,CAAC,OAAO,CAAC,CAAc;IAC9B,OAAO,CAAC,KAAK,CAAC,CAAS;IACvB,OAAO,CAAC,eAAe,CAAC,CAAS;gBAId,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,gBAAgB;IAG7C,IAAI,IAAI,uBAEP;IAED,IAAI,QAAQ,uBAEX;IAED,IAAI,SAAS,aAEZ;IAEK,UAAU;IAiBV,KAAK;IA8CL,IAAI;CAiBX"}
@@ -1,5 +1,4 @@
1
1
  import { Client } from '@dxos/client';
2
- import { Context } from '@dxos/context';
3
2
  import { FunctionTrigger } from '../function';
4
3
  export type InvokeOptions = {
5
4
  endpoint: string;
@@ -17,10 +16,4 @@ export declare class TriggerManager {
17
16
  private unmount;
18
17
  private invokeFunction;
19
18
  }
20
- export type MountTriggerParams = {
21
- ctx: Context;
22
- client: Client;
23
- trigger: FunctionTrigger;
24
- invokeOptions: InvokeOptions;
25
- };
26
19
  //# sourceMappingURL=trigger-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"trigger-manager.d.ts","sourceRoot":"","sources":["../../../../src/runtime/trigger-manager.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,MAAM,EAAoB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAKxC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG9C,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,qBAAa,cAAc;IAOvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,cAAc;IARjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAGiC;gBAGtC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,eAAe,EAAE,EAC5B,cAAc,EAAE,aAAa;IAG1C,KAAK;IAaL,IAAI;YAMI,KAAK;YA+CL,OAAO;YASP,cAAc;CAqB7B;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,eAAe,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;CAC9B,CAAC"}
1
+ {"version":3,"file":"trigger-manager.d.ts","sourceRoot":"","sources":["../../../../src/runtime/trigger-manager.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,MAAM,EAAa,MAAM,cAAc,CAAC;AAOjD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG9C,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,qBAAa,cAAc;IAOvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,cAAc;IARjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAGiC;gBAGtC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,eAAe,EAAE,EAC5B,cAAc,EAAE,aAAa;IAG1C,KAAK;IAaL,IAAI;YAMI,KAAK;YA4DL,OAAO;YASP,cAAc;CAqB7B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/functions",
3
- "version": "0.1.53-main.4544117",
3
+ "version": "0.1.53-main.499755c",
4
4
  "description": "Functions SDK and runtime.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -21,13 +21,13 @@
21
21
  "dependencies": {
22
22
  "express": "4.17.1",
23
23
  "portfinder": "^1.0.32",
24
- "@dxos/async": "0.1.53-main.4544117",
25
- "@dxos/client": "0.1.53-main.4544117",
26
- "@dxos/context": "0.1.53-main.4544117",
27
- "@dxos/log": "0.1.53-main.4544117",
28
- "@dxos/node-std": "0.1.53-main.4544117",
29
- "@dxos/observable-object": "0.1.53-main.4544117",
30
- "@dxos/util": "0.1.53-main.4544117"
24
+ "@dxos/async": "0.1.53-main.499755c",
25
+ "@dxos/client": "0.1.53-main.499755c",
26
+ "@dxos/context": "0.1.53-main.499755c",
27
+ "@dxos/echo-schema": "0.1.53-main.499755c",
28
+ "@dxos/log": "0.1.53-main.499755c",
29
+ "@dxos/node-std": "0.1.53-main.499755c",
30
+ "@dxos/util": "0.1.53-main.499755c"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/express": "^4.17.17"
@@ -71,6 +71,7 @@ export class DevServer {
71
71
 
72
72
  app.post('/:functionName', async (req, res) => {
73
73
  const functionName = req.params.functionName;
74
+ log('invoke', { function: functionName, data: req.body });
74
75
 
75
76
  const builder: Response = {
76
77
  status: (code: number) => {
@@ -101,6 +102,8 @@ export class DevServer {
101
102
  this._port = await getPortPromise({ startPort: DEFAULT_PORT });
102
103
  this._server = app.listen(this._port);
103
104
 
105
+ // TODO(burdon): Check plugin is registered.
106
+ // TypeError: Cannot read properties of undefined (reading 'register')
104
107
  const { registrationId } = await this._client.services.services.FunctionRegistryService!.register({
105
108
  endpoint: this.endpoint!,
106
109
  functions: this.functions.map((name) => ({ name })),
@@ -5,10 +5,11 @@
5
5
  import assert from 'node:assert';
6
6
 
7
7
  import { DeferredTask } from '@dxos/async';
8
- import { Client, PublicKey, Space } from '@dxos/client';
8
+ import { Client, PublicKey } from '@dxos/client';
9
+ import type { Space } from '@dxos/client/echo';
9
10
  import { Context } from '@dxos/context';
11
+ import { createSubscription } from '@dxos/echo-schema';
10
12
  import { log } from '@dxos/log';
11
- import { createSubscription } from '@dxos/observable-object';
12
13
  import { ComplexMap } from '@dxos/util';
13
14
 
14
15
  import { FunctionTrigger } from '../function';
@@ -59,10 +60,13 @@ export class TriggerManager {
59
60
  return;
60
61
  }
61
62
 
62
- const updatedIds = new Set<string>();
63
+ // TODO(burdon): Factor out subscription/result delta.
64
+
65
+ let count = 0;
66
+ const objectIds = new Set<string>();
63
67
  const task = new DeferredTask(ctx, async () => {
64
- const updatedObjects = Array.from(updatedIds);
65
- updatedIds.clear();
68
+ const updatedObjects = Array.from(objectIds);
69
+ objectIds.clear();
66
70
 
67
71
  await this.invokeFunction(this._invokeOptions, trigger.function, {
68
72
  space: space.key,
@@ -70,15 +74,25 @@ export class TriggerManager {
70
74
  });
71
75
  });
72
76
 
77
+ // TODO(burdon): Removed?
73
78
  const selection = createSubscription(({ added, updated }) => {
74
79
  for (const object of added) {
75
- updatedIds.add(object.id);
80
+ objectIds.add(object.id);
76
81
  }
77
82
  for (const object of updated) {
78
- updatedIds.add(object.id);
83
+ objectIds.add(object.id);
79
84
  }
80
85
 
81
- task.schedule();
86
+ log.info('updated', {
87
+ space: space.key,
88
+ objects: objectIds.size,
89
+ added: added.length,
90
+ updated: updated.length,
91
+ count,
92
+ });
93
+ if (count++) {
94
+ task.schedule();
95
+ }
82
96
  });
83
97
 
84
98
  ctx.onDispose(() => selection.unsubscribe());
@@ -88,12 +102,12 @@ export class TriggerManager {
88
102
  selection.update(objects);
89
103
  });
90
104
 
91
- // TODO(burdon): Subscribe method option to trigger automatically (throughout codebase).
92
- selection.update(query.objects);
105
+ // Trigger first update, but don't schedule task.
106
+ // selection.update(query.objects);
93
107
 
94
108
  ctx.onDispose(unsubscribe);
95
109
 
96
- log('mounted', { trigger });
110
+ log.info('mounted', { space: space.key, trigger });
97
111
  }
98
112
  }
99
113
 
@@ -124,14 +138,7 @@ export class TriggerManager {
124
138
 
125
139
  log('result', { function: functionName, result: await res.json() });
126
140
  } catch (err: any) {
127
- log('error', { function: functionName, error: err.message });
141
+ log.error('error', { function: functionName, error: err.message });
128
142
  }
129
143
  }
130
144
  }
131
-
132
- export type MountTriggerParams = {
133
- ctx: Context;
134
- client: Client;
135
- trigger: FunctionTrigger;
136
- invokeOptions: InvokeOptions;
137
- };