@teamkeel/functions-runtime 0.365.15-prerelease2 → 0.365.15-prerelease9
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/package.json +1 -1
- package/src/consts.js +1 -0
- package/src/handleJob.js +2 -7
- package/src/handleJob.test.js +0 -1
- package/src/handleSubscriber.js +88 -0
- package/src/index.js +2 -0
- package/src/tryExecuteJob.js +3 -2
- package/src/tryExecuteSubscriber.js +10 -0
package/package.json
CHANGED
package/src/consts.js
CHANGED
package/src/handleJob.js
CHANGED
|
@@ -4,7 +4,6 @@ const {
|
|
|
4
4
|
JSONRPCErrorCode,
|
|
5
5
|
} = require("json-rpc-2.0");
|
|
6
6
|
const { getDatabaseClient } = require("./database");
|
|
7
|
-
const { tryExecuteFunction } = require("./tryExecuteFunction");
|
|
8
7
|
const { errorToJSONRPCResponse, RuntimeErrors } = require("./errors");
|
|
9
8
|
const opentelemetry = require("@opentelemetry/api");
|
|
10
9
|
const { withSpan } = require("./tracing");
|
|
@@ -54,15 +53,11 @@ async function handleJob(request, config) {
|
|
|
54
53
|
const db = getDatabaseClient();
|
|
55
54
|
const jobFunction = jobs[request.method];
|
|
56
55
|
const actionType = PROTO_ACTION_TYPES.JOB;
|
|
57
|
-
const permissionFns = new Object();
|
|
58
|
-
|
|
59
|
-
// Jobs will have no permission functions yet.
|
|
60
|
-
permissionFns[request.method] = [];
|
|
61
56
|
|
|
62
57
|
await tryExecuteJob(
|
|
63
|
-
{ request,
|
|
58
|
+
{ request, permitted, db, actionType },
|
|
64
59
|
async () => {
|
|
65
|
-
// Return the job function to the containing
|
|
60
|
+
// Return the job function to the containing tryExecuteJob block
|
|
66
61
|
return jobFunction(ctx, request.params);
|
|
67
62
|
}
|
|
68
63
|
);
|
package/src/handleJob.test.js
CHANGED
|
@@ -4,7 +4,6 @@ import { handleJob, RuntimeErrors } from "./handleJob";
|
|
|
4
4
|
import { test, expect, beforeEach, describe } from "vitest";
|
|
5
5
|
import { ModelAPI } from "./ModelAPI";
|
|
6
6
|
import { useDatabase } from "./database";
|
|
7
|
-
const { Permissions } = require("./permissions");
|
|
8
7
|
import KSUID from "ksuid";
|
|
9
8
|
|
|
10
9
|
test("when the job returns nothing as expected", async () => {
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const {
|
|
2
|
+
createJSONRPCErrorResponse,
|
|
3
|
+
createJSONRPCSuccessResponse,
|
|
4
|
+
JSONRPCErrorCode,
|
|
5
|
+
} = require("json-rpc-2.0");
|
|
6
|
+
const { getDatabaseClient } = require("./database");
|
|
7
|
+
const { errorToJSONRPCResponse, RuntimeErrors } = require("./errors");
|
|
8
|
+
const opentelemetry = require("@opentelemetry/api");
|
|
9
|
+
const { withSpan } = require("./tracing");
|
|
10
|
+
const { PROTO_ACTION_TYPES } = require("./consts");
|
|
11
|
+
const { tryExecuteSubscriber } = require("./tryExecuteSubscriber");
|
|
12
|
+
|
|
13
|
+
// Generic handler function that is agnostic to runtime environment (local or lambda)
|
|
14
|
+
// to execute a subscriber function based on the contents of a jsonrpc-2.0 payload object.
|
|
15
|
+
// To read more about jsonrpc request and response shapes, please read https://www.jsonrpc.org/specification
|
|
16
|
+
async function handleSubscriber(request, config) {
|
|
17
|
+
// Try to extract trace context from caller
|
|
18
|
+
const activeContext = opentelemetry.propagation.extract(
|
|
19
|
+
opentelemetry.context.active(),
|
|
20
|
+
request.meta?.tracing
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
// Run the whole request with the extracted context
|
|
24
|
+
return opentelemetry.context.with(activeContext, () => {
|
|
25
|
+
// Wrapping span for the whole request
|
|
26
|
+
return withSpan(request.method, async (span) => {
|
|
27
|
+
try {
|
|
28
|
+
const { createSubscriberContextAPI, subscribers } = config;
|
|
29
|
+
|
|
30
|
+
if (!(request.method in subscribers)) {
|
|
31
|
+
const message = `no corresponding subscriber found for '${request.method}'`;
|
|
32
|
+
span.setStatus({
|
|
33
|
+
code: opentelemetry.SpanStatusCode.ERROR,
|
|
34
|
+
message: message,
|
|
35
|
+
});
|
|
36
|
+
return createJSONRPCErrorResponse(
|
|
37
|
+
request.id,
|
|
38
|
+
JSONRPCErrorCode.MethodNotFound,
|
|
39
|
+
message
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// The ctx argument passed into the subscriber function.
|
|
44
|
+
const ctx = createSubscriberContextAPI({
|
|
45
|
+
meta: request.meta,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const db = getDatabaseClient();
|
|
49
|
+
const subscriberFunction = subscribers[request.method];
|
|
50
|
+
const actionType = PROTO_ACTION_TYPES.SUBSCRIBER;
|
|
51
|
+
|
|
52
|
+
await tryExecuteSubscriber({ db, actionType }, async () => {
|
|
53
|
+
// Return the subscriber function to the containing tryExecuteSubscriber block
|
|
54
|
+
return subscriberFunction(ctx, request.params);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return createJSONRPCSuccessResponse(request.id, null);
|
|
58
|
+
} catch (e) {
|
|
59
|
+
if (e instanceof Error) {
|
|
60
|
+
span.recordException(e);
|
|
61
|
+
span.setStatus({
|
|
62
|
+
code: opentelemetry.SpanStatusCode.ERROR,
|
|
63
|
+
message: e.message,
|
|
64
|
+
});
|
|
65
|
+
return errorToJSONRPCResponse(request, e);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const message = JSON.stringify(e);
|
|
69
|
+
|
|
70
|
+
span.setStatus({
|
|
71
|
+
code: opentelemetry.SpanStatusCode.ERROR,
|
|
72
|
+
message: message,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return createJSONRPCErrorResponse(
|
|
76
|
+
request.id,
|
|
77
|
+
RuntimeErrors.UnknownError,
|
|
78
|
+
message
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports = {
|
|
86
|
+
handleSubscriber,
|
|
87
|
+
RuntimeErrors,
|
|
88
|
+
};
|
package/src/index.js
CHANGED
|
@@ -2,6 +2,7 @@ const { ModelAPI } = require("./ModelAPI");
|
|
|
2
2
|
const { RequestHeaders } = require("./RequestHeaders");
|
|
3
3
|
const { handleRequest } = require("./handleRequest");
|
|
4
4
|
const { handleJob } = require("./handleJob");
|
|
5
|
+
const { handleSubscriber } = require("./handleSubscriber");
|
|
5
6
|
const KSUID = require("ksuid");
|
|
6
7
|
const { useDatabase } = require("./database");
|
|
7
8
|
const {
|
|
@@ -16,6 +17,7 @@ module.exports = {
|
|
|
16
17
|
RequestHeaders,
|
|
17
18
|
handleRequest,
|
|
18
19
|
handleJob,
|
|
20
|
+
handleSubscriber,
|
|
19
21
|
useDatabase,
|
|
20
22
|
Permissions,
|
|
21
23
|
PERMISSION_STATE,
|
package/src/tryExecuteJob.js
CHANGED
|
@@ -11,8 +11,9 @@ function tryExecuteJob({ db, permitted, actionType, request }, cb) {
|
|
|
11
11
|
return withPermissions(permitted, async ({ getPermissionState }) => {
|
|
12
12
|
return withDatabase(db, actionType, async ({ transaction }) => {
|
|
13
13
|
await cb();
|
|
14
|
-
|
|
15
|
-
// we need to check that the final state is unpermitted. if it's not, then it means that the user has taken no explicit action to permit/deny
|
|
14
|
+
// api.permissions maintains an internal state of whether the current operation has been *explicitly* permitted/denied by the user in the course of their custom function, or if execution has already been permitted by a role based permission (evaluated in the main runtime).
|
|
15
|
+
// we need to check that the final state is permitted or unpermitted. if it's not, then it means that the user has taken no explicit action to permit/deny
|
|
16
|
+
// and therefore we default to checking the permissions defined in the schema automatically.
|
|
16
17
|
if (getPermissionState() === PERMISSION_STATE.UNPERMITTED) {
|
|
17
18
|
throw new PermissionError(`Not permitted to access ${request.method}`);
|
|
18
19
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const { withDatabase } = require("./database");
|
|
2
|
+
|
|
3
|
+
// tryExecuteSubscriber will create a new database connection and execute the function call.
|
|
4
|
+
function tryExecuteSubscriber({ db, actionType }, cb) {
|
|
5
|
+
return withDatabase(db, actionType, async () => {
|
|
6
|
+
await cb();
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
module.exports.tryExecuteSubscriber = tryExecuteSubscriber;
|