@teamkeel/functions-runtime 0.411.0-next.2 → 0.411.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teamkeel/functions-runtime",
3
- "version": "0.411.0-next.2",
3
+ "version": "0.411.0",
4
4
  "description": "Internal package used by @teamkeel/sdk",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -25,6 +25,10 @@ class KeelCamelCasePlugin {
25
25
  }
26
26
  mapRow(row) {
27
27
  return Object.keys(row).reduce((obj, key) => {
28
+ // Fields using @sequence will have a corresponding __sequence field which we drop as we don't want to return it
29
+ if (key.endsWith("__sequence")) {
30
+ return obj;
31
+ }
28
32
  let value = row[key];
29
33
  if (Array.isArray(value)) {
30
34
  value = value.map((it) =>
package/src/consts.js CHANGED
@@ -9,7 +9,6 @@ const PROTO_ACTION_TYPES = {
9
9
  WRITE: "ACTION_TYPE_WRITE",
10
10
  JOB: "JOB_TYPE",
11
11
  SUBSCRIBER: "SUBSCRIBER_TYPE",
12
- FLOW: "FLOW_TYPE",
13
12
  };
14
13
 
15
14
  module.exports.PROTO_ACTION_TYPES = PROTO_ACTION_TYPES;
package/src/index.js CHANGED
@@ -4,7 +4,6 @@ const { handleRequest } = require("./handleRequest");
4
4
  const { handleJob } = require("./handleJob");
5
5
  const { handleSubscriber } = require("./handleSubscriber");
6
6
  const { handleRoute } = require("./handleRoute");
7
- const { handleFlow } = require("./handleFlow");
8
7
  const KSUID = require("ksuid");
9
8
  const { useDatabase } = require("./database");
10
9
  const {
@@ -16,7 +15,6 @@ const tracing = require("./tracing");
16
15
  const { InlineFile, File } = require("./File");
17
16
  const { Duration } = require("./Duration");
18
17
  const { ErrorPresets } = require("./errors");
19
- const { StepRunner } = require("./StepRunner");
20
18
 
21
19
  module.exports = {
22
20
  ModelAPI,
@@ -25,18 +23,15 @@ module.exports = {
25
23
  handleJob,
26
24
  handleSubscriber,
27
25
  handleRoute,
28
- handleFlow,
29
- KSUID,
30
26
  useDatabase,
27
+ Duration,
28
+ InlineFile,
29
+ File,
31
30
  Permissions,
32
31
  PERMISSION_STATE,
33
32
  checkBuiltInPermissions,
34
33
  tracing,
35
- InlineFile,
36
- File,
37
- Duration,
38
34
  ErrorPresets,
39
- StepRunner,
40
35
  ksuid() {
41
36
  return KSUID.randomSync().string;
42
37
  },
package/src/StepRunner.js DELETED
@@ -1,97 +0,0 @@
1
- const { useDatabase } = require("./database");
2
-
3
- const STEP_STATUS = {
4
- NEW: "NEW",
5
- COMPLETED: "COMPLETED",
6
- FAILED: "FAILED",
7
- };
8
-
9
- const STEP_TYPE = {
10
- FUNCTION: "FUNCTION",
11
- IO: "IO",
12
- DELAY: "DELAY",
13
- };
14
-
15
- const defaultOpts = {
16
- maxRetries: 5,
17
- timeoutInMs: 60000,
18
- };
19
-
20
- // This is a special type that is thrown to disrupt the execution of a flow
21
- class FlowDisrupt {
22
- constructor() {}
23
- }
24
-
25
- class StepRunner {
26
- constructor(runId) {
27
- this.runId = runId;
28
- }
29
-
30
- async run(name, fn, opts) {
31
- const db = useDatabase();
32
-
33
- // First check if we already have a result for this step
34
- const completed = await db
35
- .selectFrom("keel_flow_step")
36
- .where("run_id", "=", this.runId)
37
- .where("name", "=", name)
38
- .where("status", "=", STEP_STATUS.COMPLETED)
39
- .selectAll()
40
- .executeTakeFirst();
41
-
42
- if (completed) {
43
- return completed.value;
44
- }
45
-
46
- // The step hasn't yet run successfully, so we need to create a NEW run
47
- const step = await db
48
- .insertInto("keel_flow_step")
49
- .values({
50
- run_id: this.runId,
51
- name: name,
52
- status: STEP_STATUS.NEW,
53
- type: STEP_TYPE.FUNCTION,
54
- maxRetries: opts?.maxRetries ?? defaultOpts.maxRetries,
55
- timeoutInMs: opts?.timeoutInMs ?? defaultOpts.timeoutInMs,
56
- })
57
- .returningAll()
58
- .executeTakeFirst();
59
-
60
- let outcome = STEP_STATUS.COMPLETED;
61
-
62
- let result = null;
63
- try {
64
- result = await withTimeout(fn(), step.timeoutInMs);
65
- } catch (e) {
66
- outcome = STEP_STATUS.FAILED;
67
- }
68
-
69
- // Very crudely store the result in the database
70
- await db
71
- .updateTable("keel_flow_step")
72
- .set({
73
- status: outcome,
74
- value: JSON.stringify(result),
75
- })
76
- .where("id", "=", step.id)
77
- .returningAll()
78
- .executeTakeFirst();
79
-
80
- throw new FlowDisrupt();
81
- }
82
- }
83
-
84
- function wait(milliseconds) {
85
- return new Promise((resolve) => setTimeout(resolve, milliseconds));
86
- }
87
-
88
- function withTimeout(promiseFn, timeout) {
89
- return Promise.race([
90
- promiseFn,
91
- wait(timeout).then(() => {
92
- throw new Error(`flow times out after ${timeout}ms`);
93
- }),
94
- ]);
95
- }
96
-
97
- module.exports = { StepRunner, FlowDisrupt, withTimeout };
package/src/handleFlow.js DELETED
@@ -1,126 +0,0 @@
1
- const {
2
- createJSONRPCErrorResponse,
3
- createJSONRPCSuccessResponse,
4
- JSONRPCErrorCode,
5
- } = require("json-rpc-2.0");
6
- const { createDatabaseClient } = require("./database");
7
- const { errorToJSONRPCResponse, RuntimeErrors } = require("./errors");
8
- const opentelemetry = require("@opentelemetry/api");
9
- const { withSpan } = require("./tracing");
10
- const { tryExecuteFlow } = require("./tryExecuteFlow");
11
- const { parseInputs } = require("./parsing");
12
- const { FlowDisrupt } = require("./StepRunner");
13
-
14
- async function handleFlow(request, config) {
15
- // Try to extract trace context from caller
16
- const activeContext = opentelemetry.propagation.extract(
17
- opentelemetry.context.active(),
18
- request.meta?.tracing
19
- );
20
-
21
- // Run the whole request with the extracted context
22
- return opentelemetry.context.with(activeContext, () => {
23
- // Wrapping span for the whole request
24
- return withSpan(request.method, async (span) => {
25
- let db = null;
26
-
27
- const runId = request.meta?.runId;
28
-
29
- try {
30
- if (!runId) {
31
- throw new Error("no runId provided");
32
- }
33
-
34
- const { createFlowContextAPI, flows } = config;
35
-
36
- if (!(request.method in flows)) {
37
- const message = `no corresponding flow found for '${request.method}'`;
38
- span.setStatus({
39
- code: opentelemetry.SpanStatusCode.ERROR,
40
- message: message,
41
- });
42
- return createJSONRPCErrorResponse(
43
- request.id,
44
- JSONRPCErrorCode.MethodNotFound,
45
- message
46
- );
47
- }
48
-
49
- // The ctx argument passed into the flow function.
50
- const ctx = createFlowContextAPI({
51
- meta: request.meta,
52
- });
53
-
54
- db = createDatabaseClient({
55
- connString: request.meta?.secrets?.KEEL_DB_CONN,
56
- });
57
-
58
- const flowRun = await db
59
- .selectFrom("keel_flow_run")
60
- .where("id", "=", runId)
61
- .selectAll()
62
- .executeTakeFirst();
63
-
64
- if (!flowRun) {
65
- throw new Error("no flow run found");
66
- }
67
-
68
- const flowFunction = flows[request.method];
69
-
70
- await tryExecuteFlow(db, async () => {
71
- // parse request params to convert objects into rich field types (e.g. InlineFile)
72
- const inputs = parseInputs(flowRun.input);
73
-
74
- return flowFunction(ctx, inputs);
75
- });
76
-
77
- // If we reach this point, then we know the entire flow completed successfully
78
- // TODO: Send FlowRunUpdated event with run_completed = true
79
- return createJSONRPCSuccessResponse(request.id, {
80
- runId: runId,
81
- runCompleted: true,
82
- });
83
- } catch (e) {
84
- // If the flow is disrupted, then we know that a step either completed successfully or failed
85
- if (e instanceof FlowDisrupt) {
86
- // TODO: Send FlowRunUpdated event with run_completed = false
87
- return createJSONRPCSuccessResponse(request.id, {
88
- runId: runId,
89
- runCompleted: false,
90
- });
91
- }
92
-
93
- if (e instanceof Error) {
94
- span.recordException(e);
95
- span.setStatus({
96
- code: opentelemetry.SpanStatusCode.ERROR,
97
- message: e.message,
98
- });
99
- return errorToJSONRPCResponse(request, e);
100
- }
101
-
102
- const message = JSON.stringify(e);
103
-
104
- span.setStatus({
105
- code: opentelemetry.SpanStatusCode.ERROR,
106
- message: message,
107
- });
108
-
109
- return createJSONRPCErrorResponse(
110
- request.id,
111
- RuntimeErrors.UnknownError,
112
- message
113
- );
114
- } finally {
115
- if (db) {
116
- await db.destroy();
117
- }
118
- }
119
- });
120
- });
121
- }
122
-
123
- module.exports = {
124
- handleFlow,
125
- RuntimeErrors,
126
- };
@@ -1,16 +0,0 @@
1
- import { RouteFunction } from "@teamkeel/sdk";
2
-
3
- const handler: RouteFunction = async (request, ctx) => {
4
- return {
5
- body: JSON.stringify({
6
- message: "This is a raw HTTP response",
7
- timestamp: new Date().toISOString(),
8
- }),
9
- statusCode: 200,
10
- headers: {
11
- "Content-Type": "application/json",
12
- },
13
- };
14
- };
15
-
16
- export default handler;
@@ -1,9 +0,0 @@
1
- const { withDatabase } = require("./database");
2
-
3
- function tryExecuteFlow(db, cb) {
4
- return withDatabase(db, false, async () => {
5
- return cb();
6
- });
7
- }
8
-
9
- module.exports.tryExecuteFlow = tryExecuteFlow;