@dxos/functions 0.5.3-main.b41a319 → 0.5.3-main.c3feabc
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/dist/lib/browser/index.mjs +54 -77
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +54 -77
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/handler.d.ts +12 -32
- package/dist/types/src/handler.d.ts.map +1 -1
- package/dist/types/src/runtime/dev-server.d.ts.map +1 -1
- package/dist/types/src/runtime/scheduler.d.ts +1 -1
- package/dist/types/src/runtime/scheduler.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +4 -4
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +11 -11
- package/schema/functions.json +2 -7
- package/src/handler.ts +27 -50
- package/src/runtime/dev-server.ts +4 -4
- package/src/runtime/scheduler.ts +40 -47
- package/src/types.ts +2 -4
|
@@ -1,44 +1,24 @@
|
|
|
1
1
|
import { type Client } from '@dxos/client';
|
|
2
2
|
import { type Space } from '@dxos/client/echo';
|
|
3
3
|
import { type EchoReactiveObject } from '@dxos/echo-schema';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export type FunctionHandler<TData = {}, TMeta = {}> = (params: {
|
|
8
|
-
context: FunctionContext;
|
|
9
|
-
event: FunctionEvent<TData, TMeta>;
|
|
10
|
-
response: FunctionResponse;
|
|
11
|
-
}) => Promise<FunctionResponse | void>;
|
|
12
|
-
/**
|
|
13
|
-
* Function context.
|
|
14
|
-
*/
|
|
4
|
+
export interface Response {
|
|
5
|
+
status(code: number): Response;
|
|
6
|
+
}
|
|
15
7
|
export interface FunctionContext {
|
|
16
8
|
client: Client;
|
|
17
9
|
dataDir?: string;
|
|
10
|
+
data?: any;
|
|
18
11
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Metadata from trigger.
|
|
27
|
-
*/
|
|
28
|
-
export type FunctionEventMeta<TMeta = {}> = {
|
|
29
|
-
meta: TMeta;
|
|
30
|
-
};
|
|
31
|
-
/**
|
|
32
|
-
* Function response.
|
|
33
|
-
*/
|
|
34
|
-
export interface FunctionResponse {
|
|
35
|
-
status(code: number): FunctionResponse;
|
|
36
|
-
}
|
|
37
|
-
export type RawSubscriptionData = {
|
|
12
|
+
export type FunctionHandler<T extends {}> = (params: {
|
|
13
|
+
event: T;
|
|
14
|
+
context: FunctionContext;
|
|
15
|
+
response: Response;
|
|
16
|
+
}) => Promise<Response | void>;
|
|
17
|
+
export type RawSubscriptionEvent = {
|
|
38
18
|
spaceKey?: string;
|
|
39
19
|
objects?: string[];
|
|
40
20
|
};
|
|
41
|
-
export type
|
|
21
|
+
export type SubscriptionEvent = {
|
|
42
22
|
space?: Space;
|
|
43
23
|
objects?: EchoReactiveObject<any>[];
|
|
44
24
|
};
|
|
@@ -52,5 +32,5 @@ export type SubscriptionData = {
|
|
|
52
32
|
*
|
|
53
33
|
* NOTE: Get space key from devtools or `dx space list --json`
|
|
54
34
|
*/
|
|
55
|
-
export declare const subscriptionHandler:
|
|
35
|
+
export declare const subscriptionHandler: (handler: FunctionHandler<SubscriptionEvent>) => FunctionHandler<RawSubscriptionEvent>;
|
|
56
36
|
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/handler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,MAAM,EAAa,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/handler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,MAAM,EAAa,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAU5D,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;CAChC;AAED,MAAM,WAAW,eAAe;IAE9B,MAAM,EAAE,MAAM,CAAC;IAEf,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAGD,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,oBAAoB,GAAG;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;CACrC,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,YACrB,gBAAgB,iBAAiB,CAAC,KAC1C,gBAAgB,oBAAoB,CAgBtC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../../../src/runtime/dev-server.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,EAAW,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAI3C,OAAO,
|
|
1
|
+
{"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../../../src/runtime/dev-server.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,EAAW,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAI3C,OAAO,EAAwB,KAAK,eAAe,EAAiB,MAAM,YAAY,CAAC;AACvF,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEnE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;GAEG;AACH,qBAAa,SAAS;IAclB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAb3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAErG,OAAO,CAAC,OAAO,CAAC,CAAc;IAC9B,OAAO,CAAC,KAAK,CAAC,CAAS;IACvB,OAAO,CAAC,4BAA4B,CAAC,CAAS;IAC9C,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,IAAI,CAAK;IAEjB,SAAgB,MAAM,gBAAuB;gBAI1B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,gBAAgB;IAG7C,IAAI,KAAK;;MAIR;IAED,IAAI,QAAQ,WAGX;IAED,IAAI,KAAK,uBAER;IAED,IAAI,SAAS;;;;;;;;QAEZ;IAEK,UAAU;IAUV,KAAK;IAgDL,IAAI;IA+BV;;OAEG;YACW,KAAK;IAuBnB;;OAEG;IACU,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;YAY/C,OAAO;CAoBtB"}
|
|
@@ -16,7 +16,7 @@ export declare class Scheduler {
|
|
|
16
16
|
constructor(_client: Client, _manifest: FunctionManifest, _options?: SchedulerOptions);
|
|
17
17
|
get mounts(): {
|
|
18
18
|
readonly function: string;
|
|
19
|
-
readonly
|
|
19
|
+
readonly context?: {
|
|
20
20
|
readonly [x: string]: any;
|
|
21
21
|
} | undefined;
|
|
22
22
|
readonly timer?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../../../src/runtime/scheduler.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,KAAK,MAAM,EAAkB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../../../src/runtime/scheduler.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,KAAK,MAAM,EAAkB,MAAM,cAAc,CAAC;AAO3D,OAAO,EAEL,KAAK,gBAAgB,EAMtB,MAAM,UAAU,CAAC;AAElB,MAAM,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;AAE7D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,qBAAa,SAAS;IAQlB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAR3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAG6B;gBAGlC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,GAAE,gBAAqB;IAGlD,IAAI,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAKT;IAEK,KAAK;IAWL,IAAI;IAMV;;OAEG;YACW,KAAK;YAoCL,OAAO;YAUP,aAAa;IAwC3B;;OAEG;YACW,YAAY;IA8B1B;;OAEG;YACW,cAAc;IAiC5B;;;OAGG;YACW,gBAAgB;IAoE9B;;OAEG;YACW,mBAAmB;CAsDlC"}
|
|
@@ -34,7 +34,7 @@ declare const SubscriptionTriggerSchema: S.struct<{
|
|
|
34
34
|
}>;
|
|
35
35
|
declare const FunctionTriggerSchema: S.struct<{
|
|
36
36
|
function: S.$string;
|
|
37
|
-
|
|
37
|
+
context: S.PropertySignature<"?:", {
|
|
38
38
|
readonly [x: string]: any;
|
|
39
39
|
} | undefined, never, "?:", {
|
|
40
40
|
readonly [x: string]: any;
|
|
@@ -88,11 +88,11 @@ declare const FunctionTriggerSchema: S.struct<{
|
|
|
88
88
|
} | undefined;
|
|
89
89
|
} | undefined, never>;
|
|
90
90
|
}>;
|
|
91
|
-
export type FunctionTrigger = S.Schema.Type<typeof FunctionTriggerSchema>;
|
|
92
91
|
export type TimerTrigger = S.Schema.Type<typeof TimerTriggerSchema>;
|
|
93
92
|
export type WebhookTrigger = S.Schema.Type<typeof WebhookTriggerSchema>;
|
|
94
93
|
export type WebsocketTrigger = S.Schema.Type<typeof WebsocketTriggerSchema>;
|
|
95
94
|
export type SubscriptionTrigger = S.Schema.Type<typeof SubscriptionTriggerSchema>;
|
|
95
|
+
export type FunctionTrigger = S.Schema.Type<typeof FunctionTriggerSchema>;
|
|
96
96
|
/**
|
|
97
97
|
* Function definition.
|
|
98
98
|
*/
|
|
@@ -115,7 +115,7 @@ export declare const FunctionManifestSchema: S.struct<{
|
|
|
115
115
|
}>>>;
|
|
116
116
|
triggers: S.PropertySignature<"?:", {
|
|
117
117
|
readonly function: string;
|
|
118
|
-
readonly
|
|
118
|
+
readonly context?: {
|
|
119
119
|
readonly [x: string]: any;
|
|
120
120
|
} | undefined;
|
|
121
121
|
readonly timer?: {
|
|
@@ -146,7 +146,7 @@ export declare const FunctionManifestSchema: S.struct<{
|
|
|
146
146
|
} | undefined;
|
|
147
147
|
}[] | undefined, never, "?:", {
|
|
148
148
|
readonly function: string;
|
|
149
|
-
readonly
|
|
149
|
+
readonly context?: {
|
|
150
150
|
readonly [x: string]: any;
|
|
151
151
|
} | undefined;
|
|
152
152
|
readonly timer?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,CAAC,MAAM,uBAAuB,CAAC;AAE3C,QAAA,MAAM,kBAAkB;;EAEtB,CAAC;AAEH,QAAA,MAAM,oBAAoB;;;GAMzB,CAAC;AAEF,QAAA,MAAM,sBAAsB;;;;;;;EAG1B,CAAC;AAEH,QAAA,MAAM,yBAAyB;;;;;;;;;;;;;;;;;EAiB7B,CAAC;AAEH,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWzB,CAAC;AAEH,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,CAAC,MAAM,uBAAuB,CAAC;AAE3C,QAAA,MAAM,kBAAkB;;EAEtB,CAAC;AAEH,QAAA,MAAM,oBAAoB;;;GAMzB,CAAC;AAEF,QAAA,MAAM,sBAAsB;;;;;;;EAG1B,CAAC;AAEH,QAAA,MAAM,yBAAyB;;;;;;;;;;;;;;;;;EAiB7B,CAAC;AAEH,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWzB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,kBAAkB,CAAC,CAAC;AACpE,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACxE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC5E,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAClF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE1E;;GAEG;AAEH,QAAA,MAAM,iBAAiB;;;;;EAOrB,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE;;GAEG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGjC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/functions",
|
|
3
|
-
"version": "0.5.3-main.
|
|
3
|
+
"version": "0.5.3-main.c3feabc",
|
|
4
4
|
"description": "Functions SDK and runtime.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -27,20 +27,20 @@
|
|
|
27
27
|
"express": "^4.19.2",
|
|
28
28
|
"get-port-please": "^3.1.1",
|
|
29
29
|
"ws": "^8.14.2",
|
|
30
|
-
"@braneframe/types": "0.5.3-main.
|
|
31
|
-
"@dxos/
|
|
32
|
-
"@dxos/
|
|
33
|
-
"@dxos/context": "0.5.3-main.
|
|
34
|
-
"@dxos/
|
|
35
|
-
"@dxos/
|
|
36
|
-
"@dxos/
|
|
37
|
-
"@dxos/
|
|
38
|
-
"@dxos/
|
|
30
|
+
"@braneframe/types": "0.5.3-main.c3feabc",
|
|
31
|
+
"@dxos/async": "0.5.3-main.c3feabc",
|
|
32
|
+
"@dxos/client": "0.5.3-main.c3feabc",
|
|
33
|
+
"@dxos/context": "0.5.3-main.c3feabc",
|
|
34
|
+
"@dxos/node-std": "0.5.3-main.c3feabc",
|
|
35
|
+
"@dxos/invariant": "0.5.3-main.c3feabc",
|
|
36
|
+
"@dxos/echo-schema": "0.5.3-main.c3feabc",
|
|
37
|
+
"@dxos/log": "0.5.3-main.c3feabc",
|
|
38
|
+
"@dxos/util": "0.5.3-main.c3feabc"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/express": "^4.17.17",
|
|
42
42
|
"@types/ws": "^7.4.0",
|
|
43
|
-
"@dxos/agent": "0.5.3-main.
|
|
43
|
+
"@dxos/agent": "0.5.3-main.c3feabc"
|
|
44
44
|
},
|
|
45
45
|
"publishConfig": {
|
|
46
46
|
"access": "public"
|
package/schema/functions.json
CHANGED
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"description": "Function ID/URI.",
|
|
53
53
|
"title": "string"
|
|
54
54
|
},
|
|
55
|
-
"
|
|
55
|
+
"context": {
|
|
56
56
|
"type": "object",
|
|
57
57
|
"required": [],
|
|
58
58
|
"properties": {},
|
|
@@ -78,14 +78,9 @@
|
|
|
78
78
|
"webhook": {
|
|
79
79
|
"type": "object",
|
|
80
80
|
"required": [
|
|
81
|
-
"
|
|
81
|
+
"port"
|
|
82
82
|
],
|
|
83
83
|
"properties": {
|
|
84
|
-
"method": {
|
|
85
|
-
"type": "string",
|
|
86
|
-
"description": "a string",
|
|
87
|
-
"title": "string"
|
|
88
|
-
},
|
|
89
84
|
"port": {
|
|
90
85
|
"type": "number",
|
|
91
86
|
"description": "a number",
|
package/src/handler.ts
CHANGED
|
@@ -8,61 +8,38 @@ import { type EchoReactiveObject } from '@dxos/echo-schema';
|
|
|
8
8
|
import { log } from '@dxos/log';
|
|
9
9
|
import { nonNullable } from '@dxos/util';
|
|
10
10
|
|
|
11
|
-
//
|
|
12
|
-
// https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html
|
|
11
|
+
// Lambda-like function definitions.
|
|
13
12
|
// https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml/#functions
|
|
14
13
|
// https://www.npmjs.com/package/aws-lambda
|
|
14
|
+
// https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
context: FunctionContext;
|
|
21
|
-
event: FunctionEvent<TData, TMeta>;
|
|
22
|
-
response: FunctionResponse;
|
|
23
|
-
}) => Promise<FunctionResponse | void>;
|
|
16
|
+
// TODO(burdon): No response?
|
|
17
|
+
export interface Response {
|
|
18
|
+
status(code: number): Response;
|
|
19
|
+
}
|
|
24
20
|
|
|
25
|
-
/**
|
|
26
|
-
* Function context.
|
|
27
|
-
*/
|
|
28
21
|
export interface FunctionContext {
|
|
29
22
|
// TODO(burdon): Limit access to individual space.
|
|
30
23
|
client: Client;
|
|
31
24
|
// TODO(burdon): Replace with storage service abstraction.
|
|
32
25
|
dataDir?: string;
|
|
26
|
+
// Data passed to function invocation.
|
|
27
|
+
data?: any;
|
|
33
28
|
}
|
|
34
29
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Metadata from trigger.
|
|
44
|
-
*/
|
|
45
|
-
export type FunctionEventMeta<TMeta = {}> = {
|
|
46
|
-
meta: TMeta;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Function response.
|
|
51
|
-
*/
|
|
52
|
-
export interface FunctionResponse {
|
|
53
|
-
status(code: number): FunctionResponse;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
//
|
|
57
|
-
// Subscription utils.
|
|
58
|
-
//
|
|
30
|
+
// TODO(burdon): Model after http request. Ref Lambda/OpenFaaS.
|
|
31
|
+
export type FunctionHandler<T extends {}> = (params: {
|
|
32
|
+
event: T;
|
|
33
|
+
context: FunctionContext;
|
|
34
|
+
response: Response;
|
|
35
|
+
}) => Promise<Response | void>;
|
|
59
36
|
|
|
60
|
-
export type
|
|
37
|
+
export type RawSubscriptionEvent = {
|
|
61
38
|
spaceKey?: string;
|
|
62
39
|
objects?: string[];
|
|
63
40
|
};
|
|
64
41
|
|
|
65
|
-
export type
|
|
42
|
+
export type SubscriptionEvent = {
|
|
66
43
|
space?: Space;
|
|
67
44
|
objects?: EchoReactiveObject<any>[];
|
|
68
45
|
};
|
|
@@ -77,22 +54,22 @@ export type SubscriptionData = {
|
|
|
77
54
|
*
|
|
78
55
|
* NOTE: Get space key from devtools or `dx space list --json`
|
|
79
56
|
*/
|
|
80
|
-
export const subscriptionHandler =
|
|
81
|
-
handler: FunctionHandler<
|
|
82
|
-
): FunctionHandler<
|
|
83
|
-
return ({ event
|
|
57
|
+
export const subscriptionHandler = (
|
|
58
|
+
handler: FunctionHandler<SubscriptionEvent>,
|
|
59
|
+
): FunctionHandler<RawSubscriptionEvent> => {
|
|
60
|
+
return ({ event, context, ...rest }) => {
|
|
84
61
|
const { client } = context;
|
|
85
|
-
const space =
|
|
86
|
-
const objects =
|
|
87
|
-
|
|
88
|
-
|
|
62
|
+
const space = event.spaceKey ? client.spaces.get(PublicKey.from(event.spaceKey)) : undefined;
|
|
63
|
+
const objects =
|
|
64
|
+
space &&
|
|
65
|
+
event.objects?.map<EchoReactiveObject<any> | undefined>((id) => space!.db.getObjectById(id)).filter(nonNullable);
|
|
89
66
|
|
|
90
|
-
if (!!
|
|
91
|
-
log.warn('invalid space', {
|
|
67
|
+
if (!!event.spaceKey && !space) {
|
|
68
|
+
log.warn('invalid space', { event });
|
|
92
69
|
} else {
|
|
93
70
|
log.info('handler', { space: space?.key.truncate(), objects: objects?.length });
|
|
94
71
|
}
|
|
95
72
|
|
|
96
|
-
return handler({ event: {
|
|
73
|
+
return handler({ event: { space, objects }, context, ...rest });
|
|
97
74
|
};
|
|
98
75
|
};
|
|
@@ -12,7 +12,7 @@ import { type Client } from '@dxos/client';
|
|
|
12
12
|
import { invariant } from '@dxos/invariant';
|
|
13
13
|
import { log } from '@dxos/log';
|
|
14
14
|
|
|
15
|
-
import { type FunctionContext, type
|
|
15
|
+
import { type FunctionContext, type FunctionHandler, type Response } from '../handler';
|
|
16
16
|
import { type FunctionDef, type FunctionManifest } from '../types';
|
|
17
17
|
|
|
18
18
|
export type DevServerOptions = {
|
|
@@ -186,14 +186,14 @@ export class DevServer {
|
|
|
186
186
|
const now = Date.now();
|
|
187
187
|
|
|
188
188
|
log.info('req', { seq, path });
|
|
189
|
-
const statusCode = await this._invoke(path,
|
|
189
|
+
const statusCode = await this._invoke(path, data);
|
|
190
190
|
|
|
191
191
|
log.info('res', { seq, path, statusCode, duration: Date.now() - now });
|
|
192
192
|
this.update.emit(statusCode);
|
|
193
193
|
return statusCode;
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
private async _invoke(path: string, event:
|
|
196
|
+
private async _invoke(path: string, event: any) {
|
|
197
197
|
const { handler } = this._handlers[path] ?? {};
|
|
198
198
|
invariant(handler, `invalid path: ${path}`);
|
|
199
199
|
|
|
@@ -203,7 +203,7 @@ export class DevServer {
|
|
|
203
203
|
};
|
|
204
204
|
|
|
205
205
|
let statusCode = 200;
|
|
206
|
-
const response:
|
|
206
|
+
const response: Response = {
|
|
207
207
|
status: (code: number) => {
|
|
208
208
|
statusCode = code;
|
|
209
209
|
return response;
|
package/src/runtime/scheduler.ts
CHANGED
|
@@ -17,8 +17,15 @@ import { invariant } from '@dxos/invariant';
|
|
|
17
17
|
import { log } from '@dxos/log';
|
|
18
18
|
import { ComplexMap } from '@dxos/util';
|
|
19
19
|
|
|
20
|
-
import {
|
|
21
|
-
|
|
20
|
+
import {
|
|
21
|
+
type FunctionDef,
|
|
22
|
+
type FunctionManifest,
|
|
23
|
+
type FunctionTrigger,
|
|
24
|
+
type SubscriptionTrigger,
|
|
25
|
+
type TimerTrigger,
|
|
26
|
+
type WebhookTrigger,
|
|
27
|
+
type WebsocketTrigger,
|
|
28
|
+
} from '../types';
|
|
22
29
|
|
|
23
30
|
export type Callback = (data: any) => Promise<void | number>;
|
|
24
31
|
|
|
@@ -89,19 +96,19 @@ export class Scheduler {
|
|
|
89
96
|
//
|
|
90
97
|
|
|
91
98
|
if (trigger.timer) {
|
|
92
|
-
await this._createTimer(ctx, space, def, trigger);
|
|
99
|
+
await this._createTimer(ctx, space, def, trigger.timer);
|
|
93
100
|
}
|
|
94
101
|
|
|
95
102
|
if (trigger.webhook) {
|
|
96
|
-
await this._createWebhook(ctx, space, def, trigger);
|
|
103
|
+
await this._createWebhook(ctx, space, def, trigger.webhook);
|
|
97
104
|
}
|
|
98
105
|
|
|
99
106
|
if (trigger.websocket) {
|
|
100
|
-
await this._createWebsocket(ctx, space, def, trigger);
|
|
107
|
+
await this._createWebsocket(ctx, space, def, trigger.websocket);
|
|
101
108
|
}
|
|
102
109
|
|
|
103
110
|
if (trigger.subscription) {
|
|
104
|
-
await this._createSubscription(ctx, space, def, trigger);
|
|
111
|
+
await this._createSubscription(ctx, space, def, trigger.subscription);
|
|
105
112
|
}
|
|
106
113
|
}
|
|
107
114
|
}
|
|
@@ -115,12 +122,10 @@ export class Scheduler {
|
|
|
115
122
|
}
|
|
116
123
|
}
|
|
117
124
|
|
|
118
|
-
|
|
119
|
-
|
|
125
|
+
// TODO(burdon): Pass in Space key (common context).
|
|
126
|
+
private async _execFunction(def: FunctionDef, data: any): Promise<number> {
|
|
120
127
|
try {
|
|
121
|
-
|
|
122
|
-
const payload = Object.assign({}, { meta: trigger.meta as TMeta } satisfies FunctionEventMeta<TMeta>, data);
|
|
123
|
-
|
|
128
|
+
let status = 0;
|
|
124
129
|
const { endpoint, callback } = this._options;
|
|
125
130
|
if (endpoint) {
|
|
126
131
|
// TODO(burdon): Move out of scheduler (generalize as callback).
|
|
@@ -131,13 +136,13 @@ export class Scheduler {
|
|
|
131
136
|
headers: {
|
|
132
137
|
'Content-Type': 'application/json',
|
|
133
138
|
},
|
|
134
|
-
body: JSON.stringify(
|
|
139
|
+
body: JSON.stringify(data),
|
|
135
140
|
});
|
|
136
141
|
|
|
137
142
|
status = response.status;
|
|
138
143
|
} else if (callback) {
|
|
139
144
|
log.info('exec', { function: def.id });
|
|
140
|
-
status = (await callback(
|
|
145
|
+
status = (await callback(data)) ?? 200;
|
|
141
146
|
}
|
|
142
147
|
|
|
143
148
|
// Check errors.
|
|
@@ -147,12 +152,11 @@ export class Scheduler {
|
|
|
147
152
|
|
|
148
153
|
// const result = await response.json();
|
|
149
154
|
log.info('done', { function: def.id, status });
|
|
155
|
+
return status;
|
|
150
156
|
} catch (err: any) {
|
|
151
157
|
log.error('error', { function: def.id, error: err.message });
|
|
152
|
-
|
|
158
|
+
return 500;
|
|
153
159
|
}
|
|
154
|
-
|
|
155
|
-
return status;
|
|
156
160
|
}
|
|
157
161
|
|
|
158
162
|
//
|
|
@@ -162,19 +166,19 @@ export class Scheduler {
|
|
|
162
166
|
/**
|
|
163
167
|
* Cron timer.
|
|
164
168
|
*/
|
|
165
|
-
private async _createTimer(ctx: Context, space: Space, def: FunctionDef, trigger:
|
|
169
|
+
private async _createTimer(ctx: Context, space: Space, def: FunctionDef, trigger: TimerTrigger) {
|
|
166
170
|
log.info('timer', { space: space.key, trigger });
|
|
167
|
-
const
|
|
171
|
+
const { cron } = trigger;
|
|
168
172
|
|
|
169
173
|
const task = new DeferredTask(ctx, async () => {
|
|
170
|
-
await this._execFunction(def,
|
|
174
|
+
await this._execFunction(def, { spaceKey: space.key });
|
|
171
175
|
});
|
|
172
176
|
|
|
173
177
|
let last = 0;
|
|
174
178
|
let run = 0;
|
|
175
179
|
// https://www.npmjs.com/package/cron#constructor
|
|
176
180
|
const job = CronJob.from({
|
|
177
|
-
cronTime:
|
|
181
|
+
cronTime: cron,
|
|
178
182
|
runOnInit: false,
|
|
179
183
|
onTick: () => {
|
|
180
184
|
// TODO(burdon): Check greater than 30s (use cron-parser).
|
|
@@ -195,18 +199,17 @@ export class Scheduler {
|
|
|
195
199
|
/**
|
|
196
200
|
* Webhook.
|
|
197
201
|
*/
|
|
198
|
-
private async _createWebhook(ctx: Context, space: Space, def: FunctionDef, trigger:
|
|
202
|
+
private async _createWebhook(ctx: Context, space: Space, def: FunctionDef, trigger: WebhookTrigger) {
|
|
199
203
|
log.info('webhook', { space: space.key, trigger });
|
|
200
|
-
const spec = trigger.webhook!;
|
|
201
204
|
|
|
202
205
|
// TODO(burdon): Enable POST hook with payload.
|
|
203
206
|
const server = http.createServer(async (req, res) => {
|
|
204
|
-
if (req.method !==
|
|
207
|
+
if (req.method !== trigger.method) {
|
|
205
208
|
res.statusCode = 405;
|
|
206
209
|
return res.end();
|
|
207
210
|
}
|
|
208
211
|
|
|
209
|
-
res.statusCode = await this._execFunction(def,
|
|
212
|
+
res.statusCode = await this._execFunction(def, { spaceKey: space.key });
|
|
210
213
|
res.end();
|
|
211
214
|
});
|
|
212
215
|
|
|
@@ -221,7 +224,7 @@ export class Scheduler {
|
|
|
221
224
|
// TODO(burdon): Update trigger object with actual port.
|
|
222
225
|
server.listen(port, () => {
|
|
223
226
|
log.info('started webhook', { port });
|
|
224
|
-
|
|
227
|
+
trigger.port = port;
|
|
225
228
|
});
|
|
226
229
|
|
|
227
230
|
ctx.onDispose(() => {
|
|
@@ -237,7 +240,7 @@ export class Scheduler {
|
|
|
237
240
|
ctx: Context,
|
|
238
241
|
space: Space,
|
|
239
242
|
def: FunctionDef,
|
|
240
|
-
trigger:
|
|
243
|
+
trigger: WebsocketTrigger,
|
|
241
244
|
options: {
|
|
242
245
|
retryDelay: number;
|
|
243
246
|
maxAttempts: number;
|
|
@@ -247,8 +250,7 @@ export class Scheduler {
|
|
|
247
250
|
},
|
|
248
251
|
) {
|
|
249
252
|
log.info('websocket', { space: space.key, trigger });
|
|
250
|
-
const
|
|
251
|
-
const { url, init } = spec;
|
|
253
|
+
const { url } = trigger;
|
|
252
254
|
|
|
253
255
|
let ws: WebSocket;
|
|
254
256
|
for (let attempt = 1; attempt <= options.maxAttempts; attempt++) {
|
|
@@ -258,24 +260,16 @@ export class Scheduler {
|
|
|
258
260
|
Object.assign(ws, {
|
|
259
261
|
onopen: () => {
|
|
260
262
|
log.info('opened', { url });
|
|
261
|
-
if (
|
|
262
|
-
ws.send(new TextEncoder().encode(JSON.stringify(init)));
|
|
263
|
+
if (trigger.init) {
|
|
264
|
+
ws.send(new TextEncoder().encode(JSON.stringify(trigger.init)));
|
|
263
265
|
}
|
|
264
266
|
|
|
265
267
|
open.wake(true);
|
|
266
268
|
},
|
|
267
269
|
|
|
270
|
+
// TODO(burdon): Config retry if server closes?
|
|
268
271
|
onclose: (event) => {
|
|
269
272
|
log.info('closed', { url, code: event.code });
|
|
270
|
-
// Reconnect if server closes (e.g., CF restart).
|
|
271
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code
|
|
272
|
-
if (event.code === 1006) {
|
|
273
|
-
setTimeout(async () => {
|
|
274
|
-
log.info(`reconnecting in ${options.retryDelay}s...`, { url });
|
|
275
|
-
await this._createWebsocket(ctx, space, def, trigger, options);
|
|
276
|
-
}, options.retryDelay * 1_000);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
273
|
open.wake(false);
|
|
280
274
|
},
|
|
281
275
|
|
|
@@ -286,7 +280,7 @@ export class Scheduler {
|
|
|
286
280
|
onmessage: async (event) => {
|
|
287
281
|
try {
|
|
288
282
|
const data = JSON.parse(new TextDecoder().decode(event.data as Uint8Array));
|
|
289
|
-
await this._execFunction(def,
|
|
283
|
+
await this._execFunction(def, { spaceKey: space.key, data });
|
|
290
284
|
} catch (err) {
|
|
291
285
|
log.catch(err, { url });
|
|
292
286
|
}
|
|
@@ -313,17 +307,15 @@ export class Scheduler {
|
|
|
313
307
|
/**
|
|
314
308
|
* ECHO subscription.
|
|
315
309
|
*/
|
|
316
|
-
private async _createSubscription(ctx: Context, space: Space, def: FunctionDef, trigger:
|
|
310
|
+
private async _createSubscription(ctx: Context, space: Space, def: FunctionDef, trigger: SubscriptionTrigger) {
|
|
317
311
|
log.info('subscription', { space: space.key, trigger });
|
|
318
|
-
const spec = trigger.subscription!;
|
|
319
|
-
|
|
320
312
|
const objectIds = new Set<string>();
|
|
321
313
|
const task = new DeferredTask(ctx, async () => {
|
|
322
|
-
await this._execFunction(def,
|
|
314
|
+
await this._execFunction(def, { spaceKey: space.key, objects: Array.from(objectIds) });
|
|
323
315
|
});
|
|
324
316
|
|
|
325
|
-
// TODO(burdon): Don't fire initially
|
|
326
|
-
// TODO(burdon):
|
|
317
|
+
// TODO(burdon): Don't fire initially.
|
|
318
|
+
// TODO(burdon): Subscription is called THREE times.
|
|
327
319
|
const subscriptions: (() => void)[] = [];
|
|
328
320
|
const subscription = createSubscription(({ added, updated }) => {
|
|
329
321
|
log.info('updated', { added: added.length, updated: updated.length });
|
|
@@ -339,8 +331,9 @@ export class Scheduler {
|
|
|
339
331
|
|
|
340
332
|
subscriptions.push(() => subscription.unsubscribe());
|
|
341
333
|
|
|
334
|
+
// TODO(burdon): Create queue. Only allow one invocation per trigger at a time?
|
|
342
335
|
// TODO(burdon): Disable trigger if keeps failing.
|
|
343
|
-
const { filter, options: { deep, delay } = {} } =
|
|
336
|
+
const { filter, options: { deep, delay } = {} } = trigger;
|
|
344
337
|
const update = ({ objects }: Query) => {
|
|
345
338
|
subscription.update(objects);
|
|
346
339
|
|
package/src/types.ts
CHANGED
|
@@ -44,7 +44,7 @@ const FunctionTriggerSchema = S.struct({
|
|
|
44
44
|
function: S.string.pipe(S.description('Function ID/URI.')),
|
|
45
45
|
|
|
46
46
|
// Context passed to function.
|
|
47
|
-
|
|
47
|
+
context: S.optional(S.record(S.string, S.any)),
|
|
48
48
|
|
|
49
49
|
// Triggers.
|
|
50
50
|
timer: S.optional(TimerTriggerSchema),
|
|
@@ -53,12 +53,11 @@ const FunctionTriggerSchema = S.struct({
|
|
|
53
53
|
subscription: S.optional(SubscriptionTriggerSchema),
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
-
export type FunctionTrigger = S.Schema.Type<typeof FunctionTriggerSchema>;
|
|
57
|
-
|
|
58
56
|
export type TimerTrigger = S.Schema.Type<typeof TimerTriggerSchema>;
|
|
59
57
|
export type WebhookTrigger = S.Schema.Type<typeof WebhookTriggerSchema>;
|
|
60
58
|
export type WebsocketTrigger = S.Schema.Type<typeof WebsocketTriggerSchema>;
|
|
61
59
|
export type SubscriptionTrigger = S.Schema.Type<typeof SubscriptionTriggerSchema>;
|
|
60
|
+
export type FunctionTrigger = S.Schema.Type<typeof FunctionTriggerSchema>;
|
|
62
61
|
|
|
63
62
|
/**
|
|
64
63
|
* Function definition.
|
|
@@ -68,7 +67,6 @@ const FunctionDefSchema = S.struct({
|
|
|
68
67
|
id: S.string,
|
|
69
68
|
// name: S.string,
|
|
70
69
|
description: S.optional(S.string),
|
|
71
|
-
// TODO(burdon): Rename route?
|
|
72
70
|
path: S.string,
|
|
73
71
|
// TODO(burdon): NPM/GitHub/Docker/CF URL?
|
|
74
72
|
handler: S.string,
|