@dxos/functions 0.3.8-next.f4e0086 → 0.3.8
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 +2 -2
- package/dist/lib/browser/index.mjs +203 -164
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +218 -178
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/handler.d.ts +2 -6
- package/dist/types/src/handler.d.ts.map +1 -1
- package/dist/types/src/manifest.d.ts +3 -2
- package/dist/types/src/manifest.d.ts.map +1 -1
- package/dist/types/src/runtime/dev-server.d.ts +14 -2
- package/dist/types/src/runtime/dev-server.d.ts.map +1 -1
- package/dist/types/src/runtime/index.d.ts +1 -1
- package/dist/types/src/runtime/index.d.ts.map +1 -1
- package/dist/types/src/runtime/{trigger-manager.d.ts → scheduler.d.ts} +9 -7
- package/dist/types/src/runtime/scheduler.d.ts.map +1 -0
- package/package.json +11 -10
- package/src/handler.ts +7 -8
- package/src/manifest.ts +8 -4
- package/src/runtime/dev-server.ts +91 -58
- package/src/runtime/index.ts +1 -1
- package/src/runtime/scheduler.ts +145 -0
- package/dist/types/src/runtime/trigger-manager.d.ts.map +0 -1
- package/src/runtime/trigger-manager.ts +0 -140
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../src/
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["
|
|
3
|
+
"sources": ["../../../src/runtime/dev-server.ts", "../../../src/runtime/scheduler.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport express from 'express';\nimport { getPort } from 'get-port-please';\nimport type http from 'http';\nimport { join } from 'node:path';\n\nimport { Trigger } from '@dxos/async';\nimport { type Client } from '@dxos/client';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\n\nimport { type FunctionContext, type FunctionHandler, type Response } from '../handler';\nimport { type FunctionDef, type FunctionManifest } from '../manifest';\n\nexport type DevServerOptions = {\n port?: number;\n directory: string;\n manifest: FunctionManifest;\n reload?: boolean;\n};\n\n/**\n * Functions dev server provides a local HTTP server for testing functions.\n */\nexport class DevServer {\n // Function handlers indexed by name (URL path).\n private readonly _handlers: Record<string, { def: FunctionDef; handler: FunctionHandler<any> }> = {};\n\n private _server?: http.Server;\n private _port?: number;\n private _registrationId?: string;\n private _proxy?: string;\n private _seq = 0;\n\n // prettier-ignore\n constructor(\n private readonly _client: Client,\n private readonly _options: DevServerOptions,\n ) {}\n\n get endpoint() {\n invariant(this._port);\n return `http://localhost:${this._port}`;\n }\n\n get proxy() {\n return this._proxy;\n }\n\n get functions() {\n return Object.values(this._handlers);\n }\n\n async initialize() {\n for (const def of this._options.manifest.functions) {\n try {\n await this._load(def);\n } catch (err) {\n log.error('parsing function (check manifest)', err);\n }\n }\n }\n\n async start() {\n const app = express();\n app.use(express.json());\n\n app.post('/:name', async (req, res) => {\n const { name } = req.params;\n try {\n if (this._options.reload) {\n const { def } = this._handlers[name];\n await this._load(def, true);\n }\n\n res.statusCode = await this._invoke(name, req.body);\n res.end();\n } catch (err: any) {\n log.error(err);\n res.statusCode = 500;\n res.end();\n }\n });\n\n this._port = await getPort({ port: 7200, portRange: [7200, 7299] });\n this._server = app.listen(this._port);\n\n try {\n // Register functions.\n const { registrationId, endpoint } = await this._client.services.services.FunctionRegistryService!.register({\n endpoint: this.endpoint,\n functions: this.functions.map(({ def: { name } }) => ({ name })),\n });\n\n log.info('registered', { registrationId, endpoint });\n this._registrationId = registrationId;\n this._proxy = endpoint;\n } catch (err: any) {\n await this.stop();\n throw new Error('FunctionRegistryService not available (check plugin is configured).');\n }\n }\n\n async stop() {\n const trigger = new Trigger();\n this._server?.close(async () => {\n if (this._registrationId) {\n await this._client.services.services.FunctionRegistryService!.unregister({\n registrationId: this._registrationId,\n });\n\n log.info('unregistered', { registrationId: this._registrationId });\n this._registrationId = undefined;\n this._proxy = undefined;\n }\n\n trigger.wake();\n });\n\n await trigger.wait();\n this._port = undefined;\n this._server = undefined;\n }\n\n /**\n * Load function.\n */\n private async _load(def: FunctionDef, flush = false) {\n const { id, name, handler } = def;\n const path = join(this._options.directory, handler);\n log.info('loading', { id });\n\n // Remove from cache.\n if (flush) {\n Object.keys(require.cache)\n .filter((key) => key.startsWith(path))\n .forEach((key) => delete require.cache[key]);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const module = require(path);\n if (typeof module.default !== 'function') {\n throw new Error(`Handler must export default function: ${id}`);\n }\n\n this._handlers[name] = { def, handler: module.default };\n }\n\n /**\n * Invoke function handler.\n */\n private async _invoke(name: string, event: any) {\n const seq = ++this._seq;\n const now = Date.now();\n\n log.info('req', { seq, name });\n const { handler } = this._handlers[name];\n\n const context: FunctionContext = {\n client: this._client,\n };\n\n let statusCode = 200;\n const response: Response = {\n status: (code: number) => {\n statusCode = code;\n return response;\n },\n };\n\n await handler({ context, event, response });\n log.info('res', { seq, name, statusCode, duration: Date.now() - now });\n\n return statusCode;\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { CronJob } from 'cron';\n\nimport { DeferredTask } from '@dxos/async';\nimport { type Client, type PublicKey } from '@dxos/client';\nimport { type Space } from '@dxos/client/echo';\nimport { Context } from '@dxos/context';\nimport { Filter, createSubscription } from '@dxos/echo-schema';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\nimport { ComplexMap } from '@dxos/util';\n\nimport { type FunctionDef, type FunctionManifest, type FunctionTrigger } from '../manifest';\n\ntype SchedulerOptions = {\n endpoint: string;\n};\n\n/**\n * Functions scheduler.\n */\n// TODO(burdon): Create tests.\nexport class Scheduler {\n // Map of mounted functions.\n private readonly _mounts = new ComplexMap<\n { id: string; spaceKey: PublicKey },\n { ctx: Context; trigger: FunctionTrigger }\n >(({ id, spaceKey }) => `${spaceKey.toHex()}:${id}`);\n\n constructor(\n private readonly _client: Client,\n private readonly _manifest: FunctionManifest,\n private readonly _options: SchedulerOptions,\n ) {}\n\n async start() {\n this._client.spaces.subscribe(async (spaces) => {\n for (const space of spaces) {\n await space.waitUntilReady();\n for (const trigger of this._manifest.triggers ?? []) {\n await this.mount(new Context(), space, trigger);\n }\n }\n });\n }\n\n async stop() {\n for (const { id, spaceKey } of this._mounts.keys()) {\n await this.unmount(id, spaceKey);\n }\n }\n\n private async mount(ctx: Context, space: Space, trigger: FunctionTrigger) {\n const key = { id: trigger.function, spaceKey: space.key };\n const def = this._manifest.functions.find((config) => config.id === trigger.function);\n invariant(def, `Function not found: ${trigger.function}`);\n\n 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 // Cron schedule.\n if (trigger.schedule) {\n const task = new DeferredTask(ctx, async () => {\n await this.execFunction(def, {\n space: space.key,\n });\n });\n\n // TODO(burdon): Check greater than 30s min (use cron-parser).\n const job = new CronJob(trigger.schedule, () => task.schedule());\n\n job.start();\n ctx.onDispose(() => job.stop());\n }\n\n // ECHO subscription.\n if (trigger.subscription) {\n const objectIds = new Set<string>();\n const task = new DeferredTask(ctx, async () => {\n await this.execFunction(def, {\n space: space.key,\n objects: Array.from(objectIds),\n });\n });\n\n const subscription = createSubscription(({ added, updated }) => {\n for (const object of added) {\n objectIds.add(object.id);\n }\n for (const object of updated) {\n objectIds.add(object.id);\n }\n\n task.schedule();\n });\n\n const { type, props } = trigger.subscription;\n const query = space.db.query(Filter.typename(type, props));\n const unsubscribe = query.subscribe(({ objects }) => {\n subscription.update(objects);\n }, true);\n\n ctx.onDispose(() => {\n subscription.unsubscribe();\n unsubscribe();\n });\n }\n }\n }\n\n private async unmount(id: string, spaceKey: PublicKey) {\n const key = { id, spaceKey };\n const { ctx } = this._mounts.get(key) ?? {};\n if (ctx) {\n this._mounts.delete(key);\n await ctx.dispose();\n }\n }\n\n private async execFunction(def: FunctionDef, data: any) {\n try {\n log('request', { function: def.id });\n const response = await fetch(`${this._options.endpoint}/${def.name}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(data),\n });\n\n // const result = await response.json();\n log('result', { function: def.id, result: response.status });\n } catch (err: any) {\n log.error('error', { function: def.id, error: err.message });\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_async", "import_invariant", "import_log", "DevServer", "constructor", "_client", "_options", "_handlers", "_seq", "endpoint", "invariant", "_port", "proxy", "_proxy", "functions", "Object", "values", "initialize", "def", "manifest", "_load", "err", "log", "error", "start", "app", "express", "use", "json", "post", "req", "res", "name", "params", "reload", "statusCode", "_invoke", "body", "end", "getPort", "port", "portRange", "_server", "listen", "registrationId", "services", "FunctionRegistryService", "register", "map", "info", "_registrationId", "stop", "Error", "trigger", "Trigger", "close", "unregister", "undefined", "wake", "wait", "flush", "id", "handler", "path", "join", "directory", "keys", "require", "cache", "filter", "key", "startsWith", "forEach", "module", "default", "event", "seq", "now", "Date", "context", "client", "response", "status", "code", "duration", "Scheduler", "_manifest", "_mounts", "ComplexMap", "spaceKey", "toHex", "spaces", "subscribe", "space", "waitUntilReady", "triggers", "mount", "Context", "unmount", "ctx", "function", "find", "config", "exists", "get", "set", "disposed", "schedule", "task", "DeferredTask", "execFunction", "job", "CronJob", "onDispose", "subscription", "objectIds", "Set", "objects", "Array", "from", "createSubscription", "added", "updated", "object", "add", "type", "props", "query", "db", "Filter", "typename", "unsubscribe", "update", "delete", "dispose", "data", "fetch", "method", "headers", "JSON", "stringify", "result", "message"]
|
|
7
7
|
}
|
package/dist/lib/node/meta.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"packages/core/functions/src/handler.ts":{"bytes":
|
|
1
|
+
{"inputs":{"packages/core/functions/src/handler.ts":{"bytes":1308,"imports":[],"format":"esm"},"packages/core/functions/src/manifest.ts":{"bytes":1730,"imports":[],"format":"esm"},"packages/core/functions/src/runtime/dev-server.ts":{"bytes":18548,"imports":[{"path":"express","kind":"import-statement","external":true},{"path":"get-port-please","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/runtime/scheduler.ts":{"bytes":16636,"imports":[{"path":"cron","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/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/core/functions/src/runtime/index.ts":{"bytes":561,"imports":[{"path":"packages/core/functions/src/runtime/dev-server.ts","kind":"import-statement","original":"./dev-server"},{"path":"packages/core/functions/src/runtime/scheduler.ts","kind":"import-statement","original":"./scheduler"}],"format":"esm"},"packages/core/functions/src/index.ts":{"bytes":632,"imports":[{"path":"packages/core/functions/src/handler.ts","kind":"import-statement","original":"./handler"},{"path":"packages/core/functions/src/manifest.ts","kind":"import-statement","original":"./manifest"},{"path":"packages/core/functions/src/runtime/index.ts","kind":"import-statement","original":"./runtime"}],"format":"esm"}},"outputs":{"packages/core/functions/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":16608},"packages/core/functions/dist/lib/node/index.cjs":{"imports":[{"path":"express","kind":"import-statement","external":true},{"path":"get-port-please","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"cron","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/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["DevServer","Scheduler"],"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":4724},"packages/core/functions/src/runtime/index.ts":{"bytesInOutput":0},"packages/core/functions/src/runtime/scheduler.ts":{"bytesInOutput":4184}},"bytes":9456}}}
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import { type Client } from '@dxos/client';
|
|
2
2
|
export interface Response {
|
|
3
3
|
status(code: number): Response;
|
|
4
|
-
succeed(data?: object): Response;
|
|
5
4
|
}
|
|
6
5
|
export interface FunctionContext {
|
|
7
6
|
client: Client;
|
|
8
|
-
status(code: number): Response;
|
|
9
7
|
}
|
|
10
|
-
/**
|
|
11
|
-
* Function handler.
|
|
12
|
-
*/
|
|
13
8
|
export type FunctionHandler<T extends {}> = (params: {
|
|
14
|
-
context: FunctionContext;
|
|
15
9
|
event: T;
|
|
10
|
+
context: FunctionContext;
|
|
11
|
+
response: Response;
|
|
16
12
|
}) => Promise<Response | void>;
|
|
17
13
|
export type FunctionSubscriptionEvent = {
|
|
18
14
|
space: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/handler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/handler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;CAChC;AAGD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE;IACnD,KAAK,EAAE,CAAC,CAAC;IACT,OAAO,EAAE,eAAe,CAAC;IACzB,QAAQ,EAAE,QAAQ,CAAC;CACpB,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;AAE/B,MAAM,MAAM,yBAAyB,GAAG;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type FunctionDef = {
|
|
2
2
|
id: string;
|
|
3
|
-
|
|
3
|
+
name: string;
|
|
4
4
|
handler: string;
|
|
5
5
|
description?: string;
|
|
6
6
|
};
|
|
@@ -12,7 +12,8 @@ export type TriggerSubscription = {
|
|
|
12
12
|
};
|
|
13
13
|
export type FunctionTrigger = {
|
|
14
14
|
function: string;
|
|
15
|
-
|
|
15
|
+
schedule?: string;
|
|
16
|
+
subscription?: TriggerSubscription;
|
|
16
17
|
};
|
|
17
18
|
/**
|
|
18
19
|
* Function manifest file.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/manifest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/manifest.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,WAAW,GAAG;IAExB,EAAE,EAAE,MAAM,CAAC;IAEX,IAAI,EAAE,MAAM,CAAC;IAEb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAKF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,WAAW,EAAE,CAAC;IACzB,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B,CAAC"}
|
|
@@ -2,8 +2,10 @@ import { type Client } from '@dxos/client';
|
|
|
2
2
|
import { type FunctionHandler } from '../handler';
|
|
3
3
|
import { type FunctionDef, type FunctionManifest } from '../manifest';
|
|
4
4
|
export type DevServerOptions = {
|
|
5
|
+
port?: number;
|
|
5
6
|
directory: string;
|
|
6
7
|
manifest: FunctionManifest;
|
|
8
|
+
reload?: boolean;
|
|
7
9
|
};
|
|
8
10
|
/**
|
|
9
11
|
* Functions dev server provides a local HTTP server for testing functions.
|
|
@@ -15,9 +17,11 @@ export declare class DevServer {
|
|
|
15
17
|
private _server?;
|
|
16
18
|
private _port?;
|
|
17
19
|
private _registrationId?;
|
|
20
|
+
private _proxy?;
|
|
21
|
+
private _seq;
|
|
18
22
|
constructor(_client: Client, _options: DevServerOptions);
|
|
19
|
-
get
|
|
20
|
-
get
|
|
23
|
+
get endpoint(): string;
|
|
24
|
+
get proxy(): string | undefined;
|
|
21
25
|
get functions(): {
|
|
22
26
|
def: FunctionDef;
|
|
23
27
|
handler: FunctionHandler<any>;
|
|
@@ -25,5 +29,13 @@ export declare class DevServer {
|
|
|
25
29
|
initialize(): Promise<void>;
|
|
26
30
|
start(): Promise<void>;
|
|
27
31
|
stop(): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Load function.
|
|
34
|
+
*/
|
|
35
|
+
private _load;
|
|
36
|
+
/**
|
|
37
|
+
* Invoke function handler.
|
|
38
|
+
*/
|
|
39
|
+
private _invoke;
|
|
28
40
|
}
|
|
29
41
|
//# sourceMappingURL=dev-server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../../../src/runtime/dev-server.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../../../src/runtime/dev-server.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAI3C,OAAO,EAAwB,KAAK,eAAe,EAAiB,MAAM,YAAY,CAAC;AACvF,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEtE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;GAEG;AACH,qBAAa,SAAS;IAYlB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAX3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAErG,OAAO,CAAC,OAAO,CAAC,CAAc;IAC9B,OAAO,CAAC,KAAK,CAAC,CAAS;IACvB,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,IAAI,CAAK;gBAIE,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,gBAAgB;IAG7C,IAAI,QAAQ,WAGX;IAED,IAAI,KAAK,uBAER;IAED,IAAI,SAAS;;;QAEZ;IAEK,UAAU;IAUV,KAAK;IAwCL,IAAI;IAqBV;;OAEG;YACW,KAAK;IAqBnB;;OAEG;YACW,OAAO;CAwBtB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/runtime/index.ts"],"names":[],"mappings":"AAIA,cAAc,cAAc,CAAC;AAC7B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/runtime/index.ts"],"names":[],"mappings":"AAIA,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { type Client } from '@dxos/client';
|
|
2
2
|
import { type FunctionManifest } from '../manifest';
|
|
3
|
-
|
|
3
|
+
type SchedulerOptions = {
|
|
4
4
|
endpoint: string;
|
|
5
|
-
runtime: string;
|
|
6
5
|
};
|
|
7
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Functions scheduler.
|
|
8
|
+
*/
|
|
9
|
+
export declare class Scheduler {
|
|
8
10
|
private readonly _client;
|
|
9
11
|
private readonly _manifest;
|
|
10
|
-
private readonly
|
|
12
|
+
private readonly _options;
|
|
11
13
|
private readonly _mounts;
|
|
12
|
-
|
|
13
|
-
constructor(_client: Client, _manifest: FunctionManifest, _invokeOptions: InvokeOptions);
|
|
14
|
+
constructor(_client: Client, _manifest: FunctionManifest, _options: SchedulerOptions);
|
|
14
15
|
start(): Promise<void>;
|
|
15
16
|
stop(): Promise<void>;
|
|
16
17
|
private mount;
|
|
17
18
|
private unmount;
|
|
18
19
|
private execFunction;
|
|
19
20
|
}
|
|
20
|
-
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=scheduler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../../../src/runtime/scheduler.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,MAAM,EAAkB,MAAM,cAAc,CAAC;AAQ3D,OAAO,EAAoB,KAAK,gBAAgB,EAAwB,MAAM,aAAa,CAAC;AAE5F,KAAK,gBAAgB,GAAG;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;GAEG;AAEH,qBAAa,SAAS;IAQlB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAR3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAG6B;gBAGlC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,EAAE,gBAAgB;IAGvC,KAAK;IAWL,IAAI;YAMI,KAAK;YA+DL,OAAO;YASP,YAAY;CAiB3B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/functions",
|
|
3
|
-
"version": "0.3.8
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"description": "Functions SDK and runtime.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -19,16 +19,17 @@
|
|
|
19
19
|
"src"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
+
"cron": "^3.1.6",
|
|
22
23
|
"express": "^4.17.1",
|
|
23
|
-
"
|
|
24
|
-
"@dxos/async": "0.3.8
|
|
25
|
-
"@dxos/
|
|
26
|
-
"@dxos/
|
|
27
|
-
"@dxos/
|
|
28
|
-
"@dxos/invariant": "0.3.8
|
|
29
|
-
"@dxos/log": "0.3.8
|
|
30
|
-
"@dxos/node-std": "0.3.8
|
|
31
|
-
"@dxos/util": "0.3.8
|
|
24
|
+
"get-port-please": "^3.1.1",
|
|
25
|
+
"@dxos/async": "0.3.8",
|
|
26
|
+
"@dxos/context": "0.3.8",
|
|
27
|
+
"@dxos/client": "0.3.8",
|
|
28
|
+
"@dxos/echo-schema": "0.3.8",
|
|
29
|
+
"@dxos/invariant": "0.3.8",
|
|
30
|
+
"@dxos/log": "0.3.8",
|
|
31
|
+
"@dxos/node-std": "0.3.8",
|
|
32
|
+
"@dxos/util": "0.3.8"
|
|
32
33
|
},
|
|
33
34
|
"devDependencies": {
|
|
34
35
|
"@types/express": "^4.17.17"
|
package/src/handler.ts
CHANGED
|
@@ -4,26 +4,25 @@
|
|
|
4
4
|
|
|
5
5
|
import { type Client } from '@dxos/client';
|
|
6
6
|
|
|
7
|
+
// TODO(burdon): No response?
|
|
7
8
|
export interface Response {
|
|
8
9
|
status(code: number): Response;
|
|
9
|
-
succeed(data?: object): Response;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
// TODO(burdon): Limit access to individual space?
|
|
12
13
|
export interface FunctionContext {
|
|
13
14
|
client: Client;
|
|
14
|
-
status(code: number): Response;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*/
|
|
17
|
+
// TODO(burdon): Model after http request. Ref Lambda/OpenFaaS.
|
|
18
|
+
// https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html
|
|
20
19
|
export type FunctionHandler<T extends {}> = (params: {
|
|
21
|
-
context: FunctionContext;
|
|
22
20
|
event: T;
|
|
21
|
+
context: FunctionContext;
|
|
22
|
+
response: Response;
|
|
23
23
|
}) => Promise<Response | void>;
|
|
24
24
|
|
|
25
|
-
// TODO(burdon): Types.
|
|
26
25
|
export type FunctionSubscriptionEvent = {
|
|
27
|
-
space: string;
|
|
26
|
+
space: string; // TODO(burdon): Convert to PublicKey.
|
|
28
27
|
objects: string[];
|
|
29
28
|
};
|
package/src/manifest.ts
CHANGED
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
// Lambda-like function definitions.
|
|
6
|
+
// See: https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml/#functions
|
|
7
|
+
|
|
5
8
|
export type FunctionDef = {
|
|
6
9
|
// FQ function name.
|
|
7
10
|
id: string;
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
//
|
|
11
|
+
// URL path.
|
|
12
|
+
name: string;
|
|
13
|
+
// File path of handler.
|
|
11
14
|
handler: string;
|
|
12
15
|
description?: string;
|
|
13
16
|
};
|
|
@@ -24,7 +27,8 @@ export type TriggerSubscription = {
|
|
|
24
27
|
// https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html
|
|
25
28
|
export type FunctionTrigger = {
|
|
26
29
|
function: string;
|
|
27
|
-
|
|
30
|
+
schedule?: string;
|
|
31
|
+
subscription?: TriggerSubscription;
|
|
28
32
|
};
|
|
29
33
|
|
|
30
34
|
/**
|
|
@@ -3,33 +3,37 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import express from 'express';
|
|
6
|
+
import { getPort } from 'get-port-please';
|
|
6
7
|
import type http from 'http';
|
|
7
8
|
import { join } from 'node:path';
|
|
8
|
-
import { getPortPromise } from 'portfinder';
|
|
9
9
|
|
|
10
10
|
import { Trigger } from '@dxos/async';
|
|
11
11
|
import { type Client } from '@dxos/client';
|
|
12
|
+
import { invariant } from '@dxos/invariant';
|
|
12
13
|
import { log } from '@dxos/log';
|
|
13
14
|
|
|
14
15
|
import { type FunctionContext, type FunctionHandler, type Response } from '../handler';
|
|
15
16
|
import { type FunctionDef, type FunctionManifest } from '../manifest';
|
|
16
17
|
|
|
17
|
-
const DEFAULT_PORT = 7001;
|
|
18
|
-
|
|
19
18
|
export type DevServerOptions = {
|
|
19
|
+
port?: number;
|
|
20
20
|
directory: string;
|
|
21
21
|
manifest: FunctionManifest;
|
|
22
|
+
reload?: boolean;
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Functions dev server provides a local HTTP server for testing functions.
|
|
26
27
|
*/
|
|
27
28
|
export class DevServer {
|
|
29
|
+
// Function handlers indexed by name (URL path).
|
|
28
30
|
private readonly _handlers: Record<string, { def: FunctionDef; handler: FunctionHandler<any> }> = {};
|
|
29
31
|
|
|
30
32
|
private _server?: http.Server;
|
|
31
33
|
private _port?: number;
|
|
32
34
|
private _registrationId?: string;
|
|
35
|
+
private _proxy?: string;
|
|
36
|
+
private _seq = 0;
|
|
33
37
|
|
|
34
38
|
// prettier-ignore
|
|
35
39
|
constructor(
|
|
@@ -37,12 +41,13 @@ export class DevServer {
|
|
|
37
41
|
private readonly _options: DevServerOptions,
|
|
38
42
|
) {}
|
|
39
43
|
|
|
40
|
-
get
|
|
41
|
-
|
|
44
|
+
get endpoint() {
|
|
45
|
+
invariant(this._port);
|
|
46
|
+
return `http://localhost:${this._port}`;
|
|
42
47
|
}
|
|
43
48
|
|
|
44
|
-
get
|
|
45
|
-
return this.
|
|
49
|
+
get proxy() {
|
|
50
|
+
return this._proxy;
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
get functions() {
|
|
@@ -51,20 +56,8 @@ export class DevServer {
|
|
|
51
56
|
|
|
52
57
|
async initialize() {
|
|
53
58
|
for (const def of this._options.manifest.functions) {
|
|
54
|
-
const { id, endpoint, handler: path } = def;
|
|
55
59
|
try {
|
|
56
|
-
|
|
57
|
-
const module = require(join(this._options.directory, path));
|
|
58
|
-
const handler = module.default;
|
|
59
|
-
if (typeof handler !== 'function') {
|
|
60
|
-
throw new Error(`Handler must export default function: ${id}`);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (this._handlers[endpoint]) {
|
|
64
|
-
log.warn(`Function already registered: ${id}`);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
this._handlers[endpoint] = { def, handler };
|
|
60
|
+
await this._load(def);
|
|
68
61
|
} catch (err) {
|
|
69
62
|
log.error('parsing function (check manifest)', err);
|
|
70
63
|
}
|
|
@@ -75,54 +68,39 @@ export class DevServer {
|
|
|
75
68
|
const app = express();
|
|
76
69
|
app.use(express.json());
|
|
77
70
|
|
|
78
|
-
app.post('/:
|
|
79
|
-
const {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return response;
|
|
85
|
-
},
|
|
86
|
-
|
|
87
|
-
succeed: (result = {}) => {
|
|
88
|
-
res.end(JSON.stringify(result));
|
|
89
|
-
return response;
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const context: FunctionContext = {
|
|
94
|
-
client: this._client,
|
|
95
|
-
status: response.status.bind(response),
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
void (async () => {
|
|
99
|
-
try {
|
|
100
|
-
log('invoking', { endpoint });
|
|
101
|
-
const { handler } = this._handlers[endpoint];
|
|
102
|
-
const response = await handler({ context, event: req.body });
|
|
103
|
-
log('done', { response });
|
|
104
|
-
} catch (err: any) {
|
|
105
|
-
res.statusCode = 500;
|
|
106
|
-
res.end(err.message);
|
|
71
|
+
app.post('/:name', async (req, res) => {
|
|
72
|
+
const { name } = req.params;
|
|
73
|
+
try {
|
|
74
|
+
if (this._options.reload) {
|
|
75
|
+
const { def } = this._handlers[name];
|
|
76
|
+
await this._load(def, true);
|
|
107
77
|
}
|
|
108
|
-
|
|
78
|
+
|
|
79
|
+
res.statusCode = await this._invoke(name, req.body);
|
|
80
|
+
res.end();
|
|
81
|
+
} catch (err: any) {
|
|
82
|
+
log.error(err);
|
|
83
|
+
res.statusCode = 500;
|
|
84
|
+
res.end();
|
|
85
|
+
}
|
|
109
86
|
});
|
|
110
87
|
|
|
111
|
-
this._port = await
|
|
88
|
+
this._port = await getPort({ port: 7200, portRange: [7200, 7299] });
|
|
112
89
|
this._server = app.listen(this._port);
|
|
113
90
|
|
|
114
|
-
// TODO(burdon): Check plugin is registered.
|
|
115
|
-
// TypeError: Cannot read properties of undefined (reading 'register')
|
|
116
91
|
try {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
92
|
+
// Register functions.
|
|
93
|
+
const { registrationId, endpoint } = await this._client.services.services.FunctionRegistryService!.register({
|
|
94
|
+
endpoint: this.endpoint,
|
|
95
|
+
functions: this.functions.map(({ def: { name } }) => ({ name })),
|
|
120
96
|
});
|
|
121
97
|
|
|
98
|
+
log.info('registered', { registrationId, endpoint });
|
|
122
99
|
this._registrationId = registrationId;
|
|
100
|
+
this._proxy = endpoint;
|
|
123
101
|
} catch (err: any) {
|
|
124
102
|
await this.stop();
|
|
125
|
-
throw new Error('FunctionRegistryService not available
|
|
103
|
+
throw new Error('FunctionRegistryService not available (check plugin is configured).');
|
|
126
104
|
}
|
|
127
105
|
}
|
|
128
106
|
|
|
@@ -133,14 +111,69 @@ export class DevServer {
|
|
|
133
111
|
await this._client.services.services.FunctionRegistryService!.unregister({
|
|
134
112
|
registrationId: this._registrationId,
|
|
135
113
|
});
|
|
114
|
+
|
|
115
|
+
log.info('unregistered', { registrationId: this._registrationId });
|
|
136
116
|
this._registrationId = undefined;
|
|
117
|
+
this._proxy = undefined;
|
|
137
118
|
}
|
|
138
119
|
|
|
139
120
|
trigger.wake();
|
|
140
121
|
});
|
|
141
122
|
|
|
142
123
|
await trigger.wait();
|
|
143
|
-
this._server = undefined;
|
|
144
124
|
this._port = undefined;
|
|
125
|
+
this._server = undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Load function.
|
|
130
|
+
*/
|
|
131
|
+
private async _load(def: FunctionDef, flush = false) {
|
|
132
|
+
const { id, name, handler } = def;
|
|
133
|
+
const path = join(this._options.directory, handler);
|
|
134
|
+
log.info('loading', { id });
|
|
135
|
+
|
|
136
|
+
// Remove from cache.
|
|
137
|
+
if (flush) {
|
|
138
|
+
Object.keys(require.cache)
|
|
139
|
+
.filter((key) => key.startsWith(path))
|
|
140
|
+
.forEach((key) => delete require.cache[key]);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
144
|
+
const module = require(path);
|
|
145
|
+
if (typeof module.default !== 'function') {
|
|
146
|
+
throw new Error(`Handler must export default function: ${id}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
this._handlers[name] = { def, handler: module.default };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Invoke function handler.
|
|
154
|
+
*/
|
|
155
|
+
private async _invoke(name: string, event: any) {
|
|
156
|
+
const seq = ++this._seq;
|
|
157
|
+
const now = Date.now();
|
|
158
|
+
|
|
159
|
+
log.info('req', { seq, name });
|
|
160
|
+
const { handler } = this._handlers[name];
|
|
161
|
+
|
|
162
|
+
const context: FunctionContext = {
|
|
163
|
+
client: this._client,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
let statusCode = 200;
|
|
167
|
+
const response: Response = {
|
|
168
|
+
status: (code: number) => {
|
|
169
|
+
statusCode = code;
|
|
170
|
+
return response;
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
await handler({ context, event, response });
|
|
175
|
+
log.info('res', { seq, name, statusCode, duration: Date.now() - now });
|
|
176
|
+
|
|
177
|
+
return statusCode;
|
|
145
178
|
}
|
|
146
179
|
}
|
package/src/runtime/index.ts
CHANGED