@dxos/functions 0.1.53-main.499755c → 0.1.53-main.528b72b

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
@@ -50,7 +50,7 @@ runtime:
50
50
  Start functions in dev mode (from the related package):
51
51
 
52
52
  ```bash
53
- dx function dev-server -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.
@@ -59,9 +59,9 @@ Install `nodemon` to support live reloading:
59
59
 
60
60
  ```bash
61
61
  npm i -g nodemon
62
- export DXOS_ROOT=$(git rev-parse --show-toplevel)
63
62
 
64
- nodemon -w ./src -e ts --exec $DXOS_ROOT/packages/devtools/cli/bin/dev function dev-server -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
65
65
  ```
66
66
 
67
67
  ## Invoking functions
@@ -137,7 +137,7 @@ var TriggerManager = class {
137
137
  for (const space of spaces) {
138
138
  await space.waitUntilReady();
139
139
  for (const trigger of this._triggers) {
140
- await this.mount(new Context(), trigger, space);
140
+ await this.mount(new Context(), space, trigger);
141
141
  }
142
142
  }
143
143
  });
@@ -147,7 +147,7 @@ var TriggerManager = class {
147
147
  await this.unmount(name, spaceKey);
148
148
  }
149
149
  }
150
- async mount(ctx, trigger, space) {
150
+ async mount(ctx, space, trigger) {
151
151
  const key = {
152
152
  name: trigger.function,
153
153
  spaceKey: space.key
@@ -158,60 +158,56 @@ var TriggerManager = class {
158
158
  ctx,
159
159
  trigger
160
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
+ });
161
170
  if (ctx.disposed) {
162
171
  return;
163
172
  }
164
- let count = 0;
165
173
  const objectIds = /* @__PURE__ */ new Set();
166
174
  const task = new DeferredTask(ctx, async () => {
167
- const updatedObjects = Array.from(objectIds);
168
- objectIds.clear();
169
175
  await this.invokeFunction(this._invokeOptions, trigger.function, {
170
176
  space: space.key,
171
- objects: updatedObjects
177
+ objects: Array.from(objectIds)
172
178
  });
173
179
  });
174
- const selection = createSubscription(({ added, updated }) => {
180
+ let count = 0;
181
+ const subscription = createSubscription(({ added, updated }) => {
175
182
  for (const object of added) {
176
183
  objectIds.add(object.id);
177
184
  }
178
185
  for (const object of updated) {
179
186
  objectIds.add(object.id);
180
187
  }
181
- log2.info("updated", {
188
+ log2("updated", {
189
+ trigger,
182
190
  space: space.key,
183
191
  objects: objectIds.size,
184
- added: added.length,
185
- updated: updated.length,
186
192
  count
187
193
  }, {
188
194
  F: __dxlog_file2,
189
- L: 86,
195
+ L: 82,
190
196
  S: this,
191
197
  C: (f, a) => f(...a)
192
198
  });
193
- if (count++) {
194
- task.schedule();
195
- }
199
+ task.schedule();
200
+ count++;
196
201
  });
197
- ctx.onDispose(() => selection.unsubscribe());
202
+ ctx.onDispose(() => subscription.unsubscribe());
198
203
  const query = space.db.query({
199
- ...trigger.subscription.props,
200
- "@type": trigger.subscription.type
204
+ "@type": trigger.subscription.type,
205
+ ...trigger.subscription.props
201
206
  });
202
207
  const unsubscribe = query.subscribe(({ objects }) => {
203
- selection.update(objects);
204
- });
205
- ctx.onDispose(unsubscribe);
206
- log2.info("mounted", {
207
- space: space.key,
208
- trigger
209
- }, {
210
- F: __dxlog_file2,
211
- L: 110,
212
- S: this,
213
- C: (f, a) => f(...a)
208
+ subscription.update(objects);
214
209
  });
210
+ ctx.onDispose(() => unsubscribe());
215
211
  }
216
212
  }
217
213
  async unmount(name, spaceKey) {
@@ -235,7 +231,7 @@ var TriggerManager = class {
235
231
  function: functionName
236
232
  }, {
237
233
  F: __dxlog_file2,
238
- L: 129,
234
+ L: 123,
239
235
  S: this,
240
236
  C: (f, a) => f(...a)
241
237
  });
@@ -252,7 +248,7 @@ var TriggerManager = class {
252
248
  result: await res.json()
253
249
  }, {
254
250
  F: __dxlog_file2,
255
- L: 139,
251
+ L: 133,
256
252
  S: this,
257
253
  C: (f, a) => f(...a)
258
254
  });
@@ -262,7 +258,7 @@ var TriggerManager = class {
262
258
  error: err.message
263
259
  }, {
264
260
  F: __dxlog_file2,
265
- L: 141,
261
+ L: 135,
266
262
  S: this,
267
263
  C: (f, a) => f(...a)
268
264
  });
@@ -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 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"]
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":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}}}
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}}}
@@ -165,7 +165,7 @@ var TriggerManager = class {
165
165
  for (const space of spaces) {
166
166
  await space.waitUntilReady();
167
167
  for (const trigger of this._triggers) {
168
- await this.mount(new import_context.Context(), trigger, space);
168
+ await this.mount(new import_context.Context(), space, trigger);
169
169
  }
170
170
  }
171
171
  });
@@ -175,7 +175,7 @@ var TriggerManager = class {
175
175
  await this.unmount(name, spaceKey);
176
176
  }
177
177
  }
178
- async mount(ctx, trigger, space) {
178
+ async mount(ctx, space, trigger) {
179
179
  const key = {
180
180
  name: trigger.function,
181
181
  spaceKey: space.key
@@ -186,60 +186,56 @@ var TriggerManager = class {
186
186
  ctx,
187
187
  trigger
188
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
+ });
189
198
  if (ctx.disposed) {
190
199
  return;
191
200
  }
192
- let count = 0;
193
201
  const objectIds = /* @__PURE__ */ new Set();
194
202
  const task = new import_async2.DeferredTask(ctx, async () => {
195
- const updatedObjects = Array.from(objectIds);
196
- objectIds.clear();
197
203
  await this.invokeFunction(this._invokeOptions, trigger.function, {
198
204
  space: space.key,
199
- objects: updatedObjects
205
+ objects: Array.from(objectIds)
200
206
  });
201
207
  });
202
- const selection = (0, import_echo_schema.createSubscription)(({ added, updated }) => {
208
+ let count = 0;
209
+ const subscription = (0, import_echo_schema.createSubscription)(({ added, updated }) => {
203
210
  for (const object of added) {
204
211
  objectIds.add(object.id);
205
212
  }
206
213
  for (const object of updated) {
207
214
  objectIds.add(object.id);
208
215
  }
209
- import_log2.log.info("updated", {
216
+ (0, import_log2.log)("updated", {
217
+ trigger,
210
218
  space: space.key,
211
219
  objects: objectIds.size,
212
- added: added.length,
213
- updated: updated.length,
214
220
  count
215
221
  }, {
216
222
  F: __dxlog_file2,
217
- L: 86,
223
+ L: 82,
218
224
  S: this,
219
225
  C: (f, a) => f(...a)
220
226
  });
221
- if (count++) {
222
- task.schedule();
223
- }
227
+ task.schedule();
228
+ count++;
224
229
  });
225
- ctx.onDispose(() => selection.unsubscribe());
230
+ ctx.onDispose(() => subscription.unsubscribe());
226
231
  const query = space.db.query({
227
- ...trigger.subscription.props,
228
- "@type": trigger.subscription.type
232
+ "@type": trigger.subscription.type,
233
+ ...trigger.subscription.props
229
234
  });
230
235
  const unsubscribe = query.subscribe(({ objects }) => {
231
- selection.update(objects);
232
- });
233
- ctx.onDispose(unsubscribe);
234
- import_log2.log.info("mounted", {
235
- space: space.key,
236
- trigger
237
- }, {
238
- F: __dxlog_file2,
239
- L: 110,
240
- S: this,
241
- C: (f, a) => f(...a)
236
+ subscription.update(objects);
242
237
  });
238
+ ctx.onDispose(() => unsubscribe());
243
239
  }
244
240
  }
245
241
  async unmount(name, spaceKey) {
@@ -263,7 +259,7 @@ var TriggerManager = class {
263
259
  function: functionName
264
260
  }, {
265
261
  F: __dxlog_file2,
266
- L: 129,
262
+ L: 123,
267
263
  S: this,
268
264
  C: (f, a) => f(...a)
269
265
  });
@@ -280,7 +276,7 @@ var TriggerManager = class {
280
276
  result: await res.json()
281
277
  }, {
282
278
  F: __dxlog_file2,
283
- L: 139,
279
+ L: 133,
284
280
  S: this,
285
281
  C: (f, a) => f(...a)
286
282
  });
@@ -290,7 +286,7 @@ var TriggerManager = class {
290
286
  error: err.message
291
287
  }, {
292
288
  F: __dxlog_file2,
293
- L: 141,
289
+ L: 135,
294
290
  S: this,
295
291
  C: (f, a) => f(...a)
296
292
  });
@@ -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 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"]
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": "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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", "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":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
+ {"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":"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"}
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.499755c",
3
+ "version": "0.1.53-main.528b72b",
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.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"
24
+ "@dxos/async": "0.1.53-main.528b72b",
25
+ "@dxos/client": "0.1.53-main.528b72b",
26
+ "@dxos/context": "0.1.53-main.528b72b",
27
+ "@dxos/echo-schema": "0.1.53-main.528b72b",
28
+ "@dxos/log": "0.1.53-main.528b72b",
29
+ "@dxos/node-std": "0.1.53-main.528b72b",
30
+ "@dxos/util": "0.1.53-main.528b72b"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/express": "^4.17.17"
@@ -39,7 +39,7 @@ export class TriggerManager {
39
39
  await space.waitUntilReady();
40
40
  for (const trigger of this._triggers) {
41
41
  // TODO(burdon): New context? Shared?
42
- await this.mount(new Context(), trigger, space);
42
+ await this.mount(new Context(), space, trigger);
43
43
  }
44
44
  }
45
45
  });
@@ -51,31 +51,27 @@ export class TriggerManager {
51
51
  }
52
52
  }
53
53
 
54
- private async mount(ctx: Context, trigger: FunctionTrigger, space: Space) {
54
+ private async mount(ctx: Context, space: Space, trigger: FunctionTrigger) {
55
55
  const key = { name: trigger.function, spaceKey: space.key };
56
56
  const exists = this._mounts.get(key);
57
57
  if (!exists) {
58
58
  this._mounts.set(key, { ctx, trigger });
59
+ log('mount', { space: space.key, trigger });
59
60
  if (ctx.disposed) {
60
61
  return;
61
62
  }
62
63
 
63
- // TODO(burdon): Factor out subscription/result delta.
64
-
65
- let count = 0;
64
+ // TODO(burdon): Why DeferredTask? How to pass objectIds to function?
66
65
  const objectIds = new Set<string>();
67
66
  const task = new DeferredTask(ctx, async () => {
68
- const updatedObjects = Array.from(objectIds);
69
- objectIds.clear();
70
-
71
67
  await this.invokeFunction(this._invokeOptions, trigger.function, {
72
68
  space: space.key,
73
- objects: updatedObjects,
69
+ objects: Array.from(objectIds),
74
70
  });
75
71
  });
76
72
 
77
- // TODO(burdon): Removed?
78
- const selection = createSubscription(({ added, updated }) => {
73
+ let count = 0;
74
+ const subscription = createSubscription(({ added, updated }) => {
79
75
  for (const object of added) {
80
76
  objectIds.add(object.id);
81
77
  }
@@ -83,31 +79,29 @@ export class TriggerManager {
83
79
  objectIds.add(object.id);
84
80
  }
85
81
 
86
- log.info('updated', {
82
+ log('updated', {
83
+ trigger,
87
84
  space: space.key,
88
85
  objects: objectIds.size,
89
- added: added.length,
90
- updated: updated.length,
91
86
  count,
92
87
  });
93
- if (count++) {
94
- task.schedule();
95
- }
88
+
89
+ task.schedule();
90
+ count++;
96
91
  });
97
92
 
98
- ctx.onDispose(() => selection.unsubscribe());
93
+ ctx.onDispose(() => subscription.unsubscribe());
99
94
 
100
- 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 });
101
97
  const unsubscribe = query.subscribe(({ objects }) => {
102
- selection.update(objects);
98
+ subscription.update(objects);
103
99
  });
104
100
 
105
- // Trigger first update, but don't schedule task.
106
- // selection.update(query.objects);
107
-
108
- ctx.onDispose(unsubscribe);
101
+ // TODO(burdon): Option to trigger on first subscription.
102
+ // TODO(burdon): After restart not triggered.
109
103
 
110
- log.info('mounted', { space: space.key, trigger });
104
+ ctx.onDispose(() => unsubscribe());
111
105
  }
112
106
  }
113
107