@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.cjs
CHANGED
|
@@ -3009,30 +3009,30 @@ var FlowsAPI = class _FlowsAPI {
|
|
|
3009
3009
|
}
|
|
3010
3010
|
};
|
|
3011
3011
|
|
|
3012
|
-
// src/
|
|
3012
|
+
// src/auth/serviceToken.ts
|
|
3013
3013
|
var import_jsonwebtoken3 = __toESM(require("jsonwebtoken"), 1);
|
|
3014
|
-
function
|
|
3015
|
-
const headers = { "Content-Type": "application/json" };
|
|
3014
|
+
function buildServiceAuthHeaders(audience) {
|
|
3016
3015
|
const base64pk = process.env.KEEL_PRIVATE_KEY;
|
|
3017
3016
|
if (!base64pk) {
|
|
3018
3017
|
throw new Error(
|
|
3019
|
-
|
|
3018
|
+
`KEEL_PRIVATE_KEY is not set; cannot sign the ${audience} service token`
|
|
3020
3019
|
);
|
|
3021
3020
|
}
|
|
3022
3021
|
const privateKey = Buffer.from(base64pk, "base64").toString("utf8");
|
|
3023
|
-
const
|
|
3024
|
-
headers["Authorization"] = "Bearer " + import_jsonwebtoken3.default.sign({}, privateKey, {
|
|
3022
|
+
const token = import_jsonwebtoken3.default.sign({}, privateKey, {
|
|
3025
3023
|
algorithm: "RS256",
|
|
3026
3024
|
expiresIn: 60 * 60 * 24,
|
|
3027
|
-
|
|
3028
|
-
// Scope the token to the integration proxy so it can't be mistaken for an ordinary user
|
|
3029
|
-
// access token; the runtime proxy verifies this audience before injecting credentials.
|
|
3030
|
-
audience: "integration-proxy",
|
|
3025
|
+
audience,
|
|
3031
3026
|
issuer: "https://keel.so"
|
|
3032
3027
|
});
|
|
3033
|
-
return
|
|
3028
|
+
return {
|
|
3029
|
+
"Content-Type": "application/json",
|
|
3030
|
+
Authorization: `Bearer ${token}`
|
|
3031
|
+
};
|
|
3034
3032
|
}
|
|
3035
|
-
__name(
|
|
3033
|
+
__name(buildServiceAuthHeaders, "buildServiceAuthHeaders");
|
|
3034
|
+
|
|
3035
|
+
// src/integrationServer.js
|
|
3036
3036
|
function getApiUrl3() {
|
|
3037
3037
|
const apiUrl = process.env.KEEL_API_URL;
|
|
3038
3038
|
if (!apiUrl) {
|
|
@@ -3049,7 +3049,7 @@ function createIntegrationServer(name, identity) {
|
|
|
3049
3049
|
)}/proxy`;
|
|
3050
3050
|
const response = await fetch(url, {
|
|
3051
3051
|
method: "POST",
|
|
3052
|
-
headers:
|
|
3052
|
+
headers: buildServiceAuthHeaders("integration-proxy"),
|
|
3053
3053
|
body: JSON.stringify(request ?? {})
|
|
3054
3054
|
});
|
|
3055
3055
|
if (!response.ok) {
|
|
@@ -4775,6 +4775,19 @@ var defaultOpts = {
|
|
|
4775
4775
|
retries: 4,
|
|
4776
4776
|
timeout: 6e4
|
|
4777
4777
|
};
|
|
4778
|
+
var STEP_VALUE_WARN_BYTES = 1024 * 1024;
|
|
4779
|
+
function serializeStepValue(span, name, value) {
|
|
4780
|
+
const serialized = JSON.stringify(value);
|
|
4781
|
+
const bytes = serialized == null ? 0 : Buffer.byteLength(serialized, "utf8");
|
|
4782
|
+
span.setAttribute("step.value.bytes", bytes);
|
|
4783
|
+
if (bytes > STEP_VALUE_WARN_BYTES) {
|
|
4784
|
+
console.warn(
|
|
4785
|
+
`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.`
|
|
4786
|
+
);
|
|
4787
|
+
}
|
|
4788
|
+
return serialized;
|
|
4789
|
+
}
|
|
4790
|
+
__name(serializeStepValue, "serializeStepValue");
|
|
4778
4791
|
async function insertNewStep(db, runId, name, stage) {
|
|
4779
4792
|
await db.transaction().execute(async (trx) => {
|
|
4780
4793
|
await trx.selectFrom("keel.flow_run").select("id").where("id", "=", runId).forUpdate().executeTakeFirst();
|
|
@@ -4795,6 +4808,30 @@ async function insertNewStep(db, runId, name, stage) {
|
|
|
4795
4808
|
__name(insertNewStep, "insertNewStep");
|
|
4796
4809
|
function createFlowContext(runId, data, action, callback, element, spanId, ctx) {
|
|
4797
4810
|
const usedNames = /* @__PURE__ */ new Set();
|
|
4811
|
+
let stepsSnapshot = null;
|
|
4812
|
+
let uiBoundaryCrossed = false;
|
|
4813
|
+
async function loadStepsSnapshot(db) {
|
|
4814
|
+
if (stepsSnapshot) {
|
|
4815
|
+
return stepsSnapshot;
|
|
4816
|
+
}
|
|
4817
|
+
const rows = await db.selectFrom("keel.flow_step").where("run_id", "=", runId).select(["id", "name", "status", "type", "action"]).select(import_kysely6.sql`value::text`.as("valueRaw")).execute();
|
|
4818
|
+
const map = /* @__PURE__ */ new Map();
|
|
4819
|
+
for (const row of rows) {
|
|
4820
|
+
const existing = map.get(row.name);
|
|
4821
|
+
if (existing) {
|
|
4822
|
+
existing.push(row);
|
|
4823
|
+
} else {
|
|
4824
|
+
map.set(row.name, [row]);
|
|
4825
|
+
}
|
|
4826
|
+
}
|
|
4827
|
+
stepsSnapshot = map;
|
|
4828
|
+
return map;
|
|
4829
|
+
}
|
|
4830
|
+
__name(loadStepsSnapshot, "loadStepsSnapshot");
|
|
4831
|
+
async function readStepRows(db, name) {
|
|
4832
|
+
return await db.selectFrom("keel.flow_step").where("run_id", "=", runId).where("name", "=", name).select(["id", "name", "status", "type", "action"]).select(import_kysely6.sql`value::text`.as("valueRaw")).execute();
|
|
4833
|
+
}
|
|
4834
|
+
__name(readStepRows, "readStepRows");
|
|
4798
4835
|
const context7 = {
|
|
4799
4836
|
identity: ctx.identity,
|
|
4800
4837
|
env: ctx.env,
|
|
@@ -4834,7 +4871,15 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
4834
4871
|
throw new Error(`Duplicate step name: ${name}`);
|
|
4835
4872
|
}
|
|
4836
4873
|
usedNames.add(name);
|
|
4837
|
-
|
|
4874
|
+
let past;
|
|
4875
|
+
if (uiBoundaryCrossed) {
|
|
4876
|
+
past = await readStepRows(db, name);
|
|
4877
|
+
} else {
|
|
4878
|
+
past = (await loadStepsSnapshot(db)).get(name) ?? [];
|
|
4879
|
+
if (!past.some((step) => step.status === "COMPLETED" /* COMPLETED */)) {
|
|
4880
|
+
past = await readStepRows(db, name);
|
|
4881
|
+
}
|
|
4882
|
+
}
|
|
4838
4883
|
const newSteps = past.filter(
|
|
4839
4884
|
(step) => step.status === "NEW" /* NEW */
|
|
4840
4885
|
);
|
|
@@ -4917,7 +4962,7 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
4917
4962
|
}
|
|
4918
4963
|
await db.updateTable("keel.flow_step").set({
|
|
4919
4964
|
status: "COMPLETED" /* COMPLETED */,
|
|
4920
|
-
value:
|
|
4965
|
+
value: serializeStepValue(span, name, result),
|
|
4921
4966
|
spanId,
|
|
4922
4967
|
endTime: /* @__PURE__ */ new Date()
|
|
4923
4968
|
}).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
|
|
@@ -4955,6 +5000,20 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
4955
5000
|
throw new Error(`Duplicate step name: ${name}`);
|
|
4956
5001
|
}
|
|
4957
5002
|
usedNames.add(name);
|
|
5003
|
+
const replayCompletedUiStep = /* @__PURE__ */ __name(async (completed) => {
|
|
5004
|
+
span.setAttribute(KEEL_INTERNAL_ATTR, KEEL_INTERNAL_CHILDREN);
|
|
5005
|
+
span.setAttribute("step.status", "COMPLETED" /* COMPLETED */);
|
|
5006
|
+
const rawValue = completed.valueRaw;
|
|
5007
|
+
const storedData = rawValue == null ? null : JSON.parse(rawValue);
|
|
5008
|
+
const parsedData2 = await applyElementGetData(
|
|
5009
|
+
options.content,
|
|
5010
|
+
transformRichDataTypes(storedData)
|
|
5011
|
+
);
|
|
5012
|
+
if (completed.action) {
|
|
5013
|
+
return { data: parsedData2, action: completed.action };
|
|
5014
|
+
}
|
|
5015
|
+
return parsedData2;
|
|
5016
|
+
}, "replayCompletedUiStep");
|
|
4958
5017
|
const { step, inserted } = await db.transaction().execute(async (trx) => {
|
|
4959
5018
|
await trx.selectFrom("keel.flow_run").select("id").where("id", "=", runId).forUpdate().executeTakeFirst();
|
|
4960
5019
|
const existing = await trx.selectFrom("keel.flow_step").where("run_id", "=", runId).where("name", "=", name).selectAll().select(import_kysely6.sql`value::text`.as("valueRaw")).executeTakeFirst();
|
|
@@ -4973,18 +5032,8 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
4973
5032
|
return { step: created, inserted: true };
|
|
4974
5033
|
});
|
|
4975
5034
|
if (step && step.status === "COMPLETED" /* COMPLETED */) {
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
const rawValue = step.valueRaw;
|
|
4979
|
-
const storedData = rawValue == null ? null : JSON.parse(rawValue);
|
|
4980
|
-
const parsedData2 = await applyElementGetData(
|
|
4981
|
-
options.content,
|
|
4982
|
-
transformRichDataTypes(storedData)
|
|
4983
|
-
);
|
|
4984
|
-
if (step.action) {
|
|
4985
|
-
return { data: parsedData2, action: step.action };
|
|
4986
|
-
}
|
|
4987
|
-
return parsedData2;
|
|
5035
|
+
uiBoundaryCrossed = true;
|
|
5036
|
+
return replayCompletedUiStep(step);
|
|
4988
5037
|
}
|
|
4989
5038
|
if (inserted) {
|
|
4990
5039
|
span.setAttribute("rendered", true);
|
|
@@ -5043,12 +5092,13 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
5043
5092
|
}
|
|
5044
5093
|
await db.updateTable("keel.flow_step").set({
|
|
5045
5094
|
status: "COMPLETED" /* COMPLETED */,
|
|
5046
|
-
value:
|
|
5095
|
+
value: serializeStepValue(span, name, data),
|
|
5047
5096
|
action,
|
|
5048
5097
|
spanId,
|
|
5049
5098
|
endTime: /* @__PURE__ */ new Date()
|
|
5050
5099
|
}).where("id", "=", step.id).returningAll().executeTakeFirst();
|
|
5051
5100
|
span.setAttribute("step.status", "COMPLETED" /* COMPLETED */);
|
|
5101
|
+
uiBoundaryCrossed = true;
|
|
5052
5102
|
const parsedData = await applyElementGetData(
|
|
5053
5103
|
options.content,
|
|
5054
5104
|
transformRichDataTypes(data)
|
|
@@ -5453,7 +5503,7 @@ async function notifyEmail(input) {
|
|
|
5453
5503
|
};
|
|
5454
5504
|
const response = await fetch(`${getApiUrl4()}/notifications/json/email`, {
|
|
5455
5505
|
method: "POST",
|
|
5456
|
-
headers:
|
|
5506
|
+
headers: buildServiceAuthHeaders("notifications"),
|
|
5457
5507
|
body: JSON.stringify(body)
|
|
5458
5508
|
});
|
|
5459
5509
|
if (!response.ok) {
|