@teamkeel/functions-runtime 0.460.1 → 0.461.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/dist/index.cjs +79 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +79 -29
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2954,30 +2954,30 @@ var FlowsAPI = class _FlowsAPI {
|
|
|
2954
2954
|
}
|
|
2955
2955
|
};
|
|
2956
2956
|
|
|
2957
|
-
// src/
|
|
2957
|
+
// src/auth/serviceToken.ts
|
|
2958
2958
|
import jwt3 from "jsonwebtoken";
|
|
2959
|
-
function
|
|
2960
|
-
const headers = { "Content-Type": "application/json" };
|
|
2959
|
+
function buildServiceAuthHeaders(audience) {
|
|
2961
2960
|
const base64pk = process.env.KEEL_PRIVATE_KEY;
|
|
2962
2961
|
if (!base64pk) {
|
|
2963
2962
|
throw new Error(
|
|
2964
|
-
|
|
2963
|
+
`KEEL_PRIVATE_KEY is not set; cannot sign the ${audience} service token`
|
|
2965
2964
|
);
|
|
2966
2965
|
}
|
|
2967
2966
|
const privateKey = Buffer.from(base64pk, "base64").toString("utf8");
|
|
2968
|
-
const
|
|
2969
|
-
headers["Authorization"] = "Bearer " + jwt3.sign({}, privateKey, {
|
|
2967
|
+
const token = jwt3.sign({}, privateKey, {
|
|
2970
2968
|
algorithm: "RS256",
|
|
2971
2969
|
expiresIn: 60 * 60 * 24,
|
|
2972
|
-
|
|
2973
|
-
// Scope the token to the integration proxy so it can't be mistaken for an ordinary user
|
|
2974
|
-
// access token; the runtime proxy verifies this audience before injecting credentials.
|
|
2975
|
-
audience: "integration-proxy",
|
|
2970
|
+
audience,
|
|
2976
2971
|
issuer: "https://keel.so"
|
|
2977
2972
|
});
|
|
2978
|
-
return
|
|
2973
|
+
return {
|
|
2974
|
+
"Content-Type": "application/json",
|
|
2975
|
+
Authorization: `Bearer ${token}`
|
|
2976
|
+
};
|
|
2979
2977
|
}
|
|
2980
|
-
__name(
|
|
2978
|
+
__name(buildServiceAuthHeaders, "buildServiceAuthHeaders");
|
|
2979
|
+
|
|
2980
|
+
// src/integrationServer.js
|
|
2981
2981
|
function getApiUrl3() {
|
|
2982
2982
|
const apiUrl = process.env.KEEL_API_URL;
|
|
2983
2983
|
if (!apiUrl) {
|
|
@@ -2994,7 +2994,7 @@ function createIntegrationServer(name, identity) {
|
|
|
2994
2994
|
)}/proxy`;
|
|
2995
2995
|
const response = await fetch(url, {
|
|
2996
2996
|
method: "POST",
|
|
2997
|
-
headers:
|
|
2997
|
+
headers: buildServiceAuthHeaders("integration-proxy"),
|
|
2998
2998
|
body: JSON.stringify(request ?? {})
|
|
2999
2999
|
});
|
|
3000
3000
|
if (!response.ok) {
|
|
@@ -4745,6 +4745,19 @@ var defaultOpts = {
|
|
|
4745
4745
|
retries: 4,
|
|
4746
4746
|
timeout: 6e4
|
|
4747
4747
|
};
|
|
4748
|
+
var STEP_VALUE_WARN_BYTES = 1024 * 1024;
|
|
4749
|
+
function serializeStepValue(span, name, value) {
|
|
4750
|
+
const serialized = JSON.stringify(value);
|
|
4751
|
+
const bytes = serialized == null ? 0 : Buffer.byteLength(serialized, "utf8");
|
|
4752
|
+
span.setAttribute("step.value.bytes", bytes);
|
|
4753
|
+
if (bytes > STEP_VALUE_WARN_BYTES) {
|
|
4754
|
+
console.warn(
|
|
4755
|
+
`flow step "${name}" returned a ${Math.round(bytes / 1024)}KB value. Step values are reloaded on every flow invocation during replay, so large values slow the whole run down. Consider storing large data as a file and returning a reference to it instead.`
|
|
4756
|
+
);
|
|
4757
|
+
}
|
|
4758
|
+
return serialized;
|
|
4759
|
+
}
|
|
4760
|
+
__name(serializeStepValue, "serializeStepValue");
|
|
4748
4761
|
async function insertNewStep(db, runId, name, stage) {
|
|
4749
4762
|
await db.transaction().execute(async (trx) => {
|
|
4750
4763
|
await trx.selectFrom("keel.flow_run").select("id").where("id", "=", runId).forUpdate().executeTakeFirst();
|
|
@@ -4765,6 +4778,30 @@ async function insertNewStep(db, runId, name, stage) {
|
|
|
4765
4778
|
__name(insertNewStep, "insertNewStep");
|
|
4766
4779
|
function createFlowContext(runId, data, action, callback, element, spanId, ctx) {
|
|
4767
4780
|
const usedNames = /* @__PURE__ */ new Set();
|
|
4781
|
+
let stepsSnapshot = null;
|
|
4782
|
+
let uiBoundaryCrossed = false;
|
|
4783
|
+
async function loadStepsSnapshot(db) {
|
|
4784
|
+
if (stepsSnapshot) {
|
|
4785
|
+
return stepsSnapshot;
|
|
4786
|
+
}
|
|
4787
|
+
const rows = await db.selectFrom("keel.flow_step").where("run_id", "=", runId).select(["id", "name", "status", "type", "action"]).select(sql4`value::text`.as("valueRaw")).execute();
|
|
4788
|
+
const map = /* @__PURE__ */ new Map();
|
|
4789
|
+
for (const row of rows) {
|
|
4790
|
+
const existing = map.get(row.name);
|
|
4791
|
+
if (existing) {
|
|
4792
|
+
existing.push(row);
|
|
4793
|
+
} else {
|
|
4794
|
+
map.set(row.name, [row]);
|
|
4795
|
+
}
|
|
4796
|
+
}
|
|
4797
|
+
stepsSnapshot = map;
|
|
4798
|
+
return map;
|
|
4799
|
+
}
|
|
4800
|
+
__name(loadStepsSnapshot, "loadStepsSnapshot");
|
|
4801
|
+
async function readStepRows(db, name) {
|
|
4802
|
+
return await db.selectFrom("keel.flow_step").where("run_id", "=", runId).where("name", "=", name).select(["id", "name", "status", "type", "action"]).select(sql4`value::text`.as("valueRaw")).execute();
|
|
4803
|
+
}
|
|
4804
|
+
__name(readStepRows, "readStepRows");
|
|
4768
4805
|
const context7 = {
|
|
4769
4806
|
identity: ctx.identity,
|
|
4770
4807
|
env: ctx.env,
|
|
@@ -4804,7 +4841,15 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
4804
4841
|
throw new Error(`Duplicate step name: ${name}`);
|
|
4805
4842
|
}
|
|
4806
4843
|
usedNames.add(name);
|
|
4807
|
-
|
|
4844
|
+
let past;
|
|
4845
|
+
if (uiBoundaryCrossed) {
|
|
4846
|
+
past = await readStepRows(db, name);
|
|
4847
|
+
} else {
|
|
4848
|
+
past = (await loadStepsSnapshot(db)).get(name) ?? [];
|
|
4849
|
+
if (!past.some((step) => step.status === "COMPLETED" /* COMPLETED */)) {
|
|
4850
|
+
past = await readStepRows(db, name);
|
|
4851
|
+
}
|
|
4852
|
+
}
|
|
4808
4853
|
const newSteps = past.filter(
|
|
4809
4854
|
(step) => step.status === "NEW" /* NEW */
|
|
4810
4855
|
);
|
|
@@ -4887,7 +4932,7 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
4887
4932
|
}
|
|
4888
4933
|
await db.updateTable("keel.flow_step").set({
|
|
4889
4934
|
status: "COMPLETED" /* COMPLETED */,
|
|
4890
|
-
value:
|
|
4935
|
+
value: serializeStepValue(span, name, result),
|
|
4891
4936
|
spanId,
|
|
4892
4937
|
endTime: /* @__PURE__ */ new Date()
|
|
4893
4938
|
}).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
|
|
@@ -4925,6 +4970,20 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
4925
4970
|
throw new Error(`Duplicate step name: ${name}`);
|
|
4926
4971
|
}
|
|
4927
4972
|
usedNames.add(name);
|
|
4973
|
+
const replayCompletedUiStep = /* @__PURE__ */ __name(async (completed) => {
|
|
4974
|
+
span.setAttribute(KEEL_INTERNAL_ATTR, KEEL_INTERNAL_CHILDREN);
|
|
4975
|
+
span.setAttribute("step.status", "COMPLETED" /* COMPLETED */);
|
|
4976
|
+
const rawValue = completed.valueRaw;
|
|
4977
|
+
const storedData = rawValue == null ? null : JSON.parse(rawValue);
|
|
4978
|
+
const parsedData2 = await applyElementGetData(
|
|
4979
|
+
options.content,
|
|
4980
|
+
transformRichDataTypes(storedData)
|
|
4981
|
+
);
|
|
4982
|
+
if (completed.action) {
|
|
4983
|
+
return { data: parsedData2, action: completed.action };
|
|
4984
|
+
}
|
|
4985
|
+
return parsedData2;
|
|
4986
|
+
}, "replayCompletedUiStep");
|
|
4928
4987
|
const { step, inserted } = await db.transaction().execute(async (trx) => {
|
|
4929
4988
|
await trx.selectFrom("keel.flow_run").select("id").where("id", "=", runId).forUpdate().executeTakeFirst();
|
|
4930
4989
|
const existing = await trx.selectFrom("keel.flow_step").where("run_id", "=", runId).where("name", "=", name).selectAll().select(sql4`value::text`.as("valueRaw")).executeTakeFirst();
|
|
@@ -4943,18 +5002,8 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
4943
5002
|
return { step: created, inserted: true };
|
|
4944
5003
|
});
|
|
4945
5004
|
if (step && step.status === "COMPLETED" /* COMPLETED */) {
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
const rawValue = step.valueRaw;
|
|
4949
|
-
const storedData = rawValue == null ? null : JSON.parse(rawValue);
|
|
4950
|
-
const parsedData2 = await applyElementGetData(
|
|
4951
|
-
options.content,
|
|
4952
|
-
transformRichDataTypes(storedData)
|
|
4953
|
-
);
|
|
4954
|
-
if (step.action) {
|
|
4955
|
-
return { data: parsedData2, action: step.action };
|
|
4956
|
-
}
|
|
4957
|
-
return parsedData2;
|
|
5005
|
+
uiBoundaryCrossed = true;
|
|
5006
|
+
return replayCompletedUiStep(step);
|
|
4958
5007
|
}
|
|
4959
5008
|
if (inserted) {
|
|
4960
5009
|
span.setAttribute("rendered", true);
|
|
@@ -5013,12 +5062,13 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
5013
5062
|
}
|
|
5014
5063
|
await db.updateTable("keel.flow_step").set({
|
|
5015
5064
|
status: "COMPLETED" /* COMPLETED */,
|
|
5016
|
-
value:
|
|
5065
|
+
value: serializeStepValue(span, name, data),
|
|
5017
5066
|
action,
|
|
5018
5067
|
spanId,
|
|
5019
5068
|
endTime: /* @__PURE__ */ new Date()
|
|
5020
5069
|
}).where("id", "=", step.id).returningAll().executeTakeFirst();
|
|
5021
5070
|
span.setAttribute("step.status", "COMPLETED" /* COMPLETED */);
|
|
5071
|
+
uiBoundaryCrossed = true;
|
|
5022
5072
|
const parsedData = await applyElementGetData(
|
|
5023
5073
|
options.content,
|
|
5024
5074
|
transformRichDataTypes(data)
|
|
@@ -5432,7 +5482,7 @@ async function notifyEmail(input) {
|
|
|
5432
5482
|
};
|
|
5433
5483
|
const response = await fetch(`${getApiUrl4()}/notifications/json/email`, {
|
|
5434
5484
|
method: "POST",
|
|
5435
|
-
headers:
|
|
5485
|
+
headers: buildServiceAuthHeaders("notifications"),
|
|
5436
5486
|
body: JSON.stringify(body)
|
|
5437
5487
|
});
|
|
5438
5488
|
if (!response.ok) {
|