@dxos/functions 0.1.53-main.b6f5d87 → 0.1.53-main.bb44a18

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 --verbose
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
- export DXOS_ROOT=$(git rev-parse --show-toplevel)
71
62
 
72
- nodemon -w ./src -e ts --exec $DXOS_ROOT/packages/devtools/cli/bin/dev function dev -r ts-node/register
63
+ nodemon -w ./src -e ts --exec $(git rev-parse --show-toplevel)/packages/devtools/cli/bin/dev \
64
+ function dev-server -r ts-node/register --verbose
73
65
  ```
74
66
 
75
67
  ## Invoking functions
@@ -77,8 +69,7 @@ nodemon -w ./src -e ts --exec $DXOS_ROOT/packages/devtools/cli/bin/dev function
77
69
  > NOTE: The port (7001) must match the one in config.
78
70
 
79
71
  ```bash
80
- curl -X POST -H 'Content-Type: application/json' -w '\n' \
81
- http://localhost:7001/dev/hello --data '{ "message": "Hello World!" }'
72
+ curl http://localhost:7001/dev/hello -X POST -H 'Content-Type: application/json' -w '\n' --data '{ "message": "Hello World!" }'
82
73
  ```
83
74
 
84
75
  ## DXOS Resources
@@ -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;
@@ -126,7 +137,7 @@ var TriggerManager = class {
126
137
  for (const space of spaces) {
127
138
  await space.waitUntilReady();
128
139
  for (const trigger of this._triggers) {
129
- await this.mount(new Context(), trigger, space);
140
+ await this.mount(new Context(), space, trigger);
130
141
  }
131
142
  }
132
143
  });
@@ -136,7 +147,7 @@ var TriggerManager = class {
136
147
  await this.unmount(name, spaceKey);
137
148
  }
138
149
  }
139
- async mount(ctx, trigger, space) {
150
+ async mount(ctx, space, trigger) {
140
151
  const key = {
141
152
  name: trigger.function,
142
153
  spaceKey: space.key
@@ -147,45 +158,56 @@ var TriggerManager = class {
147
158
  ctx,
148
159
  trigger
149
160
  });
161
+ log2("mount", {
162
+ space: space.key,
163
+ trigger
164
+ }, {
165
+ F: __dxlog_file2,
166
+ L: 59,
167
+ S: this,
168
+ C: (f, a) => f(...a)
169
+ });
150
170
  if (ctx.disposed) {
151
171
  return;
152
172
  }
153
- const updatedIds = /* @__PURE__ */ new Set();
173
+ const objectIds = /* @__PURE__ */ new Set();
154
174
  const task = new DeferredTask(ctx, async () => {
155
- const updatedObjects = Array.from(updatedIds);
156
- updatedIds.clear();
157
175
  await this.invokeFunction(this._invokeOptions, trigger.function, {
158
176
  space: space.key,
159
- objects: updatedObjects
177
+ objects: Array.from(objectIds)
160
178
  });
161
179
  });
162
- const selection = createSubscription(({ added, updated }) => {
180
+ let count = 0;
181
+ const subscription = createSubscription(({ added, updated }) => {
163
182
  for (const object of added) {
164
- updatedIds.add(object.id);
183
+ objectIds.add(object.id);
165
184
  }
166
- for (const object1 of updated) {
167
- updatedIds.add(object1.id);
185
+ for (const object of updated) {
186
+ objectIds.add(object.id);
168
187
  }
188
+ log2("updated", {
189
+ trigger,
190
+ space: space.key,
191
+ objects: objectIds.size,
192
+ count
193
+ }, {
194
+ F: __dxlog_file2,
195
+ L: 82,
196
+ S: this,
197
+ C: (f, a) => f(...a)
198
+ });
169
199
  task.schedule();
200
+ count++;
170
201
  });
171
- ctx.onDispose(() => selection.unsubscribe());
202
+ ctx.onDispose(() => subscription.unsubscribe());
172
203
  const query = space.db.query({
173
- ...trigger.subscription.props,
174
- "@type": trigger.subscription.type
204
+ "@type": trigger.subscription.type,
205
+ ...trigger.subscription.props
175
206
  });
176
207
  const unsubscribe = query.subscribe(({ objects }) => {
177
- selection.update(objects);
178
- });
179
- selection.update(query.objects);
180
- ctx.onDispose(unsubscribe);
181
- log2("mounted", {
182
- trigger
183
- }, {
184
- file: "trigger-manager.ts",
185
- line: 96,
186
- scope: this,
187
- callSite: (f, a) => f(...a)
208
+ subscription.update(objects);
188
209
  });
210
+ ctx.onDispose(() => unsubscribe());
189
211
  }
190
212
  }
191
213
  async unmount(name, spaceKey) {
@@ -208,10 +230,10 @@ var TriggerManager = class {
208
230
  log2("invoke", {
209
231
  function: functionName
210
232
  }, {
211
- file: "trigger-manager.ts",
212
- line: 115,
213
- scope: this,
214
- callSite: (f, a) => f(...a)
233
+ F: __dxlog_file2,
234
+ L: 123,
235
+ S: this,
236
+ C: (f, a) => f(...a)
215
237
  });
216
238
  const url = `${endpoint}/${runtime}/${functionName}`;
217
239
  const res = await fetch(url, {
@@ -225,20 +247,20 @@ var TriggerManager = class {
225
247
  function: functionName,
226
248
  result: await res.json()
227
249
  }, {
228
- file: "trigger-manager.ts",
229
- line: 125,
230
- scope: this,
231
- callSite: (f, a) => f(...a)
250
+ F: __dxlog_file2,
251
+ L: 133,
252
+ S: this,
253
+ C: (f, a) => f(...a)
232
254
  });
233
255
  } catch (err) {
234
- log2("error", {
256
+ log2.error("error", {
235
257
  function: functionName,
236
258
  error: err.message
237
259
  }, {
238
- file: "trigger-manager.ts",
239
- line: 127,
240
- scope: this,
241
- callSite: (f, a) => f(...a)
260
+ F: __dxlog_file2,
261
+ L: 135,
262
+ S: this,
263
+ C: (f, a) => f(...a)
242
264
  });
243
265
  }
244
266
  }
@@ -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(), space, trigger);\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, space: Space, trigger: FunctionTrigger) {\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 log('mount', { space: space.key, trigger });\n if (ctx.disposed) {\n return;\n }\n\n // TODO(burdon): Why DeferredTask? How to pass objectIds to function?\n const objectIds = new Set<string>();\n const task = new DeferredTask(ctx, async () => {\n await this.invokeFunction(this._invokeOptions, trigger.function, {\n space: space.key,\n objects: Array.from(objectIds),\n });\n });\n\n let count = 0;\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 log('updated', {\n trigger,\n space: space.key,\n objects: objectIds.size,\n count,\n });\n\n task.schedule();\n count++;\n });\n\n ctx.onDispose(() => subscription.unsubscribe());\n\n // TODO(burdon): DSL for query (replace props).\n const query = space.db.query({ '@type': trigger.subscription.type, ...trigger.subscription.props });\n const unsubscribe = query.subscribe(({ objects }) => {\n subscription.update(objects);\n });\n\n // TODO(burdon): Option to trigger on first subscription.\n // TODO(burdon): After restart not triggered.\n\n ctx.onDispose(() => unsubscribe());\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", "objectIds", "Set", "task", "invokeFunction", "objects", "Array", "from", "count", "subscription", "added", "updated", "object", "add", "id", "size", "schedule", "onDispose", "unsubscribe", "query", "db", "type", "props", "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":15730,"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":13972},"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":3977}},"bytes":7692}}}
@@ -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;
@@ -154,7 +165,7 @@ var TriggerManager = class {
154
165
  for (const space of spaces) {
155
166
  await space.waitUntilReady();
156
167
  for (const trigger of this._triggers) {
157
- await this.mount(new import_context.Context(), trigger, space);
168
+ await this.mount(new import_context.Context(), space, trigger);
158
169
  }
159
170
  }
160
171
  });
@@ -164,7 +175,7 @@ var TriggerManager = class {
164
175
  await this.unmount(name, spaceKey);
165
176
  }
166
177
  }
167
- async mount(ctx, trigger, space) {
178
+ async mount(ctx, space, trigger) {
168
179
  const key = {
169
180
  name: trigger.function,
170
181
  spaceKey: space.key
@@ -175,45 +186,56 @@ var TriggerManager = class {
175
186
  ctx,
176
187
  trigger
177
188
  });
189
+ (0, import_log2.log)("mount", {
190
+ space: space.key,
191
+ trigger
192
+ }, {
193
+ F: __dxlog_file2,
194
+ L: 59,
195
+ S: this,
196
+ C: (f, a) => f(...a)
197
+ });
178
198
  if (ctx.disposed) {
179
199
  return;
180
200
  }
181
- const updatedIds = /* @__PURE__ */ new Set();
201
+ const objectIds = /* @__PURE__ */ new Set();
182
202
  const task = new import_async2.DeferredTask(ctx, async () => {
183
- const updatedObjects = Array.from(updatedIds);
184
- updatedIds.clear();
185
203
  await this.invokeFunction(this._invokeOptions, trigger.function, {
186
204
  space: space.key,
187
- objects: updatedObjects
205
+ objects: Array.from(objectIds)
188
206
  });
189
207
  });
190
- const selection = (0, import_observable_object.createSubscription)(({ added, updated }) => {
208
+ let count = 0;
209
+ const subscription = (0, import_echo_schema.createSubscription)(({ added, updated }) => {
191
210
  for (const object of added) {
192
- updatedIds.add(object.id);
211
+ objectIds.add(object.id);
193
212
  }
194
- for (const object1 of updated) {
195
- updatedIds.add(object1.id);
213
+ for (const object of updated) {
214
+ objectIds.add(object.id);
196
215
  }
216
+ (0, import_log2.log)("updated", {
217
+ trigger,
218
+ space: space.key,
219
+ objects: objectIds.size,
220
+ count
221
+ }, {
222
+ F: __dxlog_file2,
223
+ L: 82,
224
+ S: this,
225
+ C: (f, a) => f(...a)
226
+ });
197
227
  task.schedule();
228
+ count++;
198
229
  });
199
- ctx.onDispose(() => selection.unsubscribe());
230
+ ctx.onDispose(() => subscription.unsubscribe());
200
231
  const query = space.db.query({
201
- ...trigger.subscription.props,
202
- "@type": trigger.subscription.type
232
+ "@type": trigger.subscription.type,
233
+ ...trigger.subscription.props
203
234
  });
204
235
  const unsubscribe = query.subscribe(({ objects }) => {
205
- selection.update(objects);
206
- });
207
- selection.update(query.objects);
208
- ctx.onDispose(unsubscribe);
209
- (0, import_log2.log)("mounted", {
210
- trigger
211
- }, {
212
- file: "trigger-manager.ts",
213
- line: 96,
214
- scope: this,
215
- callSite: (f, a) => f(...a)
236
+ subscription.update(objects);
216
237
  });
238
+ ctx.onDispose(() => unsubscribe());
217
239
  }
218
240
  }
219
241
  async unmount(name, spaceKey) {
@@ -236,10 +258,10 @@ var TriggerManager = class {
236
258
  (0, import_log2.log)("invoke", {
237
259
  function: functionName
238
260
  }, {
239
- file: "trigger-manager.ts",
240
- line: 115,
241
- scope: this,
242
- callSite: (f, a) => f(...a)
261
+ F: __dxlog_file2,
262
+ L: 123,
263
+ S: this,
264
+ C: (f, a) => f(...a)
243
265
  });
244
266
  const url = `${endpoint}/${runtime}/${functionName}`;
245
267
  const res = await fetch(url, {
@@ -253,20 +275,20 @@ var TriggerManager = class {
253
275
  function: functionName,
254
276
  result: await res.json()
255
277
  }, {
256
- file: "trigger-manager.ts",
257
- line: 125,
258
- scope: this,
259
- callSite: (f, a) => f(...a)
278
+ F: __dxlog_file2,
279
+ L: 133,
280
+ S: this,
281
+ C: (f, a) => f(...a)
260
282
  });
261
283
  } catch (err) {
262
- (0, import_log2.log)("error", {
284
+ import_log2.log.error("error", {
263
285
  function: functionName,
264
286
  error: err.message
265
287
  }, {
266
- file: "trigger-manager.ts",
267
- line: 127,
268
- scope: this,
269
- callSite: (f, a) => f(...a)
288
+ F: __dxlog_file2,
289
+ L: 135,
290
+ S: this,
291
+ C: (f, a) => f(...a)
270
292
  });
271
293
  }
272
294
  }
@@ -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(), space, trigger);\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, space: Space, trigger: FunctionTrigger) {\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 log('mount', { space: space.key, trigger });\n if (ctx.disposed) {\n return;\n }\n\n // TODO(burdon): Why DeferredTask? How to pass objectIds to function?\n const objectIds = new Set<string>();\n const task = new DeferredTask(ctx, async () => {\n await this.invokeFunction(this._invokeOptions, trigger.function, {\n space: space.key,\n objects: Array.from(objectIds),\n });\n });\n\n let count = 0;\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 log('updated', {\n trigger,\n space: space.key,\n objects: objectIds.size,\n count,\n });\n\n task.schedule();\n count++;\n });\n\n ctx.onDispose(() => subscription.unsubscribe());\n\n // TODO(burdon): DSL for query (replace props).\n const query = space.db.query({ '@type': trigger.subscription.type, ...trigger.subscription.props });\n const unsubscribe = query.subscribe(({ objects }) => {\n subscription.update(objects);\n });\n\n // TODO(burdon): Option to trigger on first subscription.\n // TODO(burdon): After restart not triggered.\n\n ctx.onDispose(() => unsubscribe());\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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;ACIA,qBAAoB;AAEpB,uBAAqB;AACrB,wBAA+B;AAE/B,mBAAwB;AAExB,iBAAoB;;AAIpB,IAAMA,eAAe;AAUd,IAAMC,YAAN,MAAMA;;EAQXC,YACmBC,SACAC,UACjB;mBAFiBD;oBACAC;SATFC,oBAAqD,CAAC;EAUpE;EAEH,IAAIC,OAAO;AACT,WAAO,KAAKC;EACd;EAEA,IAAIC,WAAW;AACb,WAAO,KAAKD,QAAQ,oBAAoB,KAAKA,UAAUE;EACzD;EAEA,IAAIC,YAAY;AACd,WAAOC,OAAOC,KAAK,KAAKP,iBAAiB;EAC3C;EAEA,MAAMQ,aAAa;AACjB,eAAW,CAACC,MAAMC,CAAAA,KAAMJ,OAAOK,QAAQ,KAAKZ,SAASa,SAASP,SAAS,GAAG;AACxE,UAAI;AAEF,cAAMQ,UAASC,YAAQC,uBAAK,KAAKhB,SAASiB,WAAWP,IAAAA,CAAAA;AACrD,cAAMQ,UAAUJ,QAAOK;AACvB,YAAI,OAAOD,YAAY,YAAY;AACjC,gBAAM,IAAIE,MAAM,yCAAyCV,MAAM;QACjE;AAEA,aAAKT,kBAAkBS,IAAAA,IAAQQ;MACjC,SAASG,KAAP;AACAC,uBAAIC,MAAM,mDAAmDF,KAAAA;;;;;;MAC/D;IACF;EACF;EAEA,MAAMG,QAAQ;AACZ,UAAMC,UAAMC,eAAAA,SAAAA;AACZD,QAAIE,IAAID,eAAAA,QAAQE,KAAI,CAAA;AAEpBH,QAAII,KAAK,kBAAkB,OAAOC,KAAKC,QAAAA;AACrC,YAAMC,eAAeF,IAAIG,OAAOD;AAChCV,0BAAI,UAAU;QAAEY,UAAUF;QAAcG,MAAML,IAAIM;MAAK,GAAA;;;;;;AAEvD,YAAMC,UAAoB;QACxBC,QAAQ,CAACC,SAAAA;AACPR,cAAIS,aAAaD;AACjB,iBAAOF;QACT;QACAI,SAAS,CAACC,SAAS,CAAC,MAAC;AACnBX,cAAIY,IAAIC,KAAKC,UAAUH,MAAAA,CAAAA;AACvB,iBAAOL;QACT;MACF;AAEA,YAAMS,UAA2B;QAC/BC,QAAQ,KAAKhD;QACbuC,QAAQD,QAAQC,OAAOU,KAAKX,OAAAA;MAC9B;AAEA,YAAM,YAAA;AACJ,YAAI;AACF,gBAAM,KAAKpC,kBAAkB+B,YAAAA,EAAcF,IAAIM,MAAMU,OAAAA;QACvD,SAASzB,KAAP;AACAU,cAAIS,aAAa;AACjBT,cAAIY,IAAItB,IAAI4B,OAAO;QACrB;MACF,GAAA;IACF,CAAA;AAEA,SAAK9C,QAAQ,UAAM+C,kCAAe;MAAEC,WAAWvD;IAAa,CAAA;AAC5D,SAAKwD,UAAU3B,IAAI4B,OAAO,KAAKlD,KAAK;AAIpC,UAAM,EAAEmD,eAAc,IAAK,MAAM,KAAKvD,QAAQwD,SAASA,SAASC,wBAAyBC,SAAS;MAChGrD,UAAU,KAAKA;MACfE,WAAW,KAAKA,UAAUoD,IAAI,CAAChD,UAAU;QAAEA;MAAK,EAAA;IAClD,CAAA;AACA,SAAKiD,kBAAkBL;EACzB;EAEA,MAAMM,OAAO;AAjHf;AAkHI,UAAMC,UAAU,IAAIC,qBAAAA;AACpB,eAAKV,YAAL,mBAAcW,MAAM,YAAA;AAClB,UAAI,KAAKJ,iBAAiB;AACxB,cAAM,KAAK5D,QAAQwD,SAASA,SAASC,wBAAyBQ,WAAW;UACvEV,gBAAgB,KAAKK;QACvB,CAAA;AACA,aAAKA,kBAAkBtD;MACzB;AAEAwD,cAAQI,KAAI;IACd;AAEA,UAAMJ,QAAQK,KAAI;AAClB,SAAKd,UAAU/C;AACf,SAAKF,QAAQE;EACf;AACF;;;AC9HA,yBAAmB;AAEnB,IAAA8D,gBAA6B;AAG7B,qBAAwB;AACxB,yBAAmC;AACnC,IAAAC,cAAoB;AACpB,kBAA2B;;AAUpB,IAAMC,iBAAN,MAAMA;EAMXC,YACmBC,SACAC,WACAC,gBACjB;mBAHiBF;qBACAC;0BACAC;SARFC,UAAU,IAAIC,uBAG7B,CAAC,EAAEC,MAAMC,SAAQ,MAAO,GAAGA,SAASC,MAAK,KAAMF,MAAM;EAMpD;EAEH,MAAMG,QAAQ;AAEZ,SAAKR,QAAQS,OAAOC,UAAU,OAAOD,WAAAA;AACnC,iBAAWE,SAASF,QAAQ;AAC1B,cAAME,MAAMC,eAAc;AAC1B,mBAAWC,WAAW,KAAKZ,WAAW;AAEpC,gBAAM,KAAKa,MAAM,IAAIC,uBAAAA,GAAWJ,OAAOE,OAAAA;QACzC;MACF;IACF,CAAA;EACF;EAEA,MAAMG,OAAO;AACX,eAAW,EAAEX,MAAMC,SAAQ,KAAM,KAAKH,QAAQc,KAAI,GAAI;AACpD,YAAM,KAAKC,QAAQb,MAAMC,QAAAA;IAC3B;EACF;EAEA,MAAcQ,MAAMK,KAAcR,OAAcE,SAA0B;AACxE,UAAMO,MAAM;MAAEf,MAAMQ,QAAQQ;MAAUf,UAAUK,MAAMS;IAAI;AAC1D,UAAME,SAAS,KAAKnB,QAAQoB,IAAIH,GAAAA;AAChC,QAAI,CAACE,QAAQ;AACX,WAAKnB,QAAQqB,IAAIJ,KAAK;QAAED;QAAKN;MAAQ,CAAA;AACrCY,2BAAI,SAAS;QAAEd,OAAOA,MAAMS;QAAKP;MAAQ,GAAA;;;;;;AACzC,UAAIM,IAAIO,UAAU;AAChB;MACF;AAGA,YAAMC,YAAY,oBAAIC,IAAAA;AACtB,YAAMC,OAAO,IAAIC,2BAAaX,KAAK,YAAA;AACjC,cAAM,KAAKY,eAAe,KAAK7B,gBAAgBW,QAAQQ,UAAU;UAC/DV,OAAOA,MAAMS;UACbY,SAASC,MAAMC,KAAKP,SAAAA;QACtB,CAAA;MACF,CAAA;AAEA,UAAIQ,QAAQ;AACZ,YAAMC,mBAAeC,uCAAmB,CAAC,EAAEC,OAAOC,QAAO,MAAE;AACzD,mBAAWC,UAAUF,OAAO;AAC1BX,oBAAUc,IAAID,OAAOE,EAAE;QACzB;AACA,mBAAWF,UAAUD,SAAS;AAC5BZ,oBAAUc,IAAID,OAAOE,EAAE;QACzB;AAEAjB,6BAAI,WAAW;UACbZ;UACAF,OAAOA,MAAMS;UACbY,SAASL,UAAUgB;UACnBR;QACF,GAAA;;;;;;AAEAN,aAAKe,SAAQ;AACbT;MACF,CAAA;AAEAhB,UAAI0B,UAAU,MAAMT,aAAaU,YAAW,CAAA;AAG5C,YAAMC,QAAQpC,MAAMqC,GAAGD,MAAM;QAAE,SAASlC,QAAQuB,aAAaa;QAAM,GAAGpC,QAAQuB,aAAac;MAAM,CAAA;AACjG,YAAMJ,cAAcC,MAAMrC,UAAU,CAAC,EAAEsB,QAAO,MAAE;AAC9CI,qBAAae,OAAOnB,OAAAA;MACtB,CAAA;AAKAb,UAAI0B,UAAU,MAAMC,YAAAA,CAAAA;IACtB;EACF;EAEA,MAAc5B,QAAQb,MAAcC,UAAqB;AA3G3D;AA4GI,UAAMc,MAAM;MAAEf;MAAMC;IAAS;AAC7B,UAAM,EAAEa,IAAG,KAAK,UAAKhB,QAAQoB,IAAIH,GAAAA,MAAjB,YAAyB,CAAC;AAC1C,QAAID,KAAK;AACP,WAAKhB,QAAQiD,OAAOhC,GAAAA;AACpB,YAAMD,IAAIkC,QAAO;IACnB;EACF;EAEA,MAActB,eAAeuB,SAAwBC,cAAsBC,MAAW;AACpF,UAAM,EAAEC,UAAUC,QAAO,IAAKJ;AAC9BK,2BAAAA,SAAOF,UAAU,kBAAA;AACjBE,2BAAAA,SAAOD,SAAS,iBAAA;AAEhB,QAAI;AACFjC,2BAAI,UAAU;QAAEJ,UAAUkC;MAAa,GAAA;;;;;;AACvC,YAAMK,MAAM,GAAGH,YAAYC,WAAWH;AACtC,YAAMM,MAAM,MAAMC,MAAMF,KAAK;QAC3BG,QAAQ;QACRC,MAAMC,KAAKC,UAAUV,IAAAA;QACrBW,SAAS;UACP,gBAAgB;QAClB;MACF,CAAA;AAEA1C,2BAAI,UAAU;QAAEJ,UAAUkC;QAAca,QAAQ,MAAMP,IAAIQ,KAAI;MAAG,GAAA;;;;;;IACnE,SAASC,KAAP;AACA7C,sBAAI8C,MAAM,SAAS;QAAElD,UAAUkC;QAAcgB,OAAOD,IAAIE;MAAQ,GAAA;;;;;;IAClE;EACF;AACF;",
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", "log", "disposed", "objectIds", "Set", "task", "DeferredTask", "invokeFunction", "objects", "Array", "from", "count", "subscription", "createSubscription", "added", "updated", "object", "add", "id", "size", "schedule", "onDispose", "unsubscribe", "query", "db", "type", "props", "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":15730,"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":14057},"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":4185}},"bytes":9325}}}
@@ -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;YAsDL,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.b6f5d87",
3
+ "version": "0.1.53-main.bb44a18",
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.b6f5d87",
25
- "@dxos/client": "0.1.53-main.b6f5d87",
26
- "@dxos/context": "0.1.53-main.b6f5d87",
27
- "@dxos/log": "0.1.53-main.b6f5d87",
28
- "@dxos/node-std": "0.1.53-main.b6f5d87",
29
- "@dxos/observable-object": "0.1.53-main.b6f5d87",
30
- "@dxos/util": "0.1.53-main.b6f5d87"
24
+ "@dxos/async": "0.1.53-main.bb44a18",
25
+ "@dxos/client": "0.1.53-main.bb44a18",
26
+ "@dxos/context": "0.1.53-main.bb44a18",
27
+ "@dxos/echo-schema": "0.1.53-main.bb44a18",
28
+ "@dxos/log": "0.1.53-main.bb44a18",
29
+ "@dxos/node-std": "0.1.53-main.bb44a18",
30
+ "@dxos/util": "0.1.53-main.bb44a18"
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';
@@ -38,7 +39,7 @@ export class TriggerManager {
38
39
  await space.waitUntilReady();
39
40
  for (const trigger of this._triggers) {
40
41
  // TODO(burdon): New context? Shared?
41
- await this.mount(new Context(), trigger, space);
42
+ await this.mount(new Context(), space, trigger);
42
43
  }
43
44
  }
44
45
  });
@@ -50,50 +51,57 @@ export class TriggerManager {
50
51
  }
51
52
  }
52
53
 
53
- private async mount(ctx: Context, trigger: FunctionTrigger, space: Space) {
54
+ private async mount(ctx: Context, space: Space, trigger: FunctionTrigger) {
54
55
  const key = { name: trigger.function, spaceKey: space.key };
55
56
  const exists = this._mounts.get(key);
56
57
  if (!exists) {
57
58
  this._mounts.set(key, { ctx, trigger });
59
+ log('mount', { space: space.key, trigger });
58
60
  if (ctx.disposed) {
59
61
  return;
60
62
  }
61
63
 
62
- const updatedIds = new Set<string>();
64
+ // TODO(burdon): Why DeferredTask? How to pass objectIds to function?
65
+ const objectIds = new Set<string>();
63
66
  const task = new DeferredTask(ctx, async () => {
64
- const updatedObjects = Array.from(updatedIds);
65
- updatedIds.clear();
66
-
67
67
  await this.invokeFunction(this._invokeOptions, trigger.function, {
68
68
  space: space.key,
69
- objects: updatedObjects,
69
+ objects: Array.from(objectIds),
70
70
  });
71
71
  });
72
72
 
73
- const selection = createSubscription(({ added, updated }) => {
73
+ let count = 0;
74
+ const subscription = createSubscription(({ added, updated }) => {
74
75
  for (const object of added) {
75
- updatedIds.add(object.id);
76
+ objectIds.add(object.id);
76
77
  }
77
78
  for (const object of updated) {
78
- updatedIds.add(object.id);
79
+ objectIds.add(object.id);
79
80
  }
80
81
 
82
+ log('updated', {
83
+ trigger,
84
+ space: space.key,
85
+ objects: objectIds.size,
86
+ count,
87
+ });
88
+
81
89
  task.schedule();
90
+ count++;
82
91
  });
83
92
 
84
- ctx.onDispose(() => selection.unsubscribe());
93
+ ctx.onDispose(() => subscription.unsubscribe());
85
94
 
86
- const query = space.db.query({ ...trigger.subscription.props, '@type': trigger.subscription.type });
95
+ // TODO(burdon): DSL for query (replace props).
96
+ const query = space.db.query({ '@type': trigger.subscription.type, ...trigger.subscription.props });
87
97
  const unsubscribe = query.subscribe(({ objects }) => {
88
- selection.update(objects);
98
+ subscription.update(objects);
89
99
  });
90
100
 
91
- // TODO(burdon): Subscribe method option to trigger automatically (throughout codebase).
92
- selection.update(query.objects);
101
+ // TODO(burdon): Option to trigger on first subscription.
102
+ // TODO(burdon): After restart not triggered.
93
103
 
94
- ctx.onDispose(unsubscribe);
95
-
96
- log('mounted', { trigger });
104
+ ctx.onDispose(() => unsubscribe());
97
105
  }
98
106
  }
99
107
 
@@ -124,14 +132,7 @@ export class TriggerManager {
124
132
 
125
133
  log('result', { function: functionName, result: await res.json() });
126
134
  } catch (err: any) {
127
- log('error', { function: functionName, error: err.message });
135
+ log.error('error', { function: functionName, error: err.message });
128
136
  }
129
137
  }
130
138
  }
131
-
132
- export type MountTriggerParams = {
133
- ctx: Context;
134
- client: Client;
135
- trigger: FunctionTrigger;
136
- invokeOptions: InvokeOptions;
137
- };