@teamkeel/functions-runtime 0.452.1 → 0.454.2
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 +188 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +82 -22
- package/dist/index.d.ts +82 -22
- package/dist/index.js +187 -25
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -530,9 +530,9 @@ var InstrumentedClient = class extends Client {
|
|
|
530
530
|
}
|
|
531
531
|
async query(...args) {
|
|
532
532
|
const _super = super.query.bind(this);
|
|
533
|
-
const
|
|
533
|
+
const sql5 = args[0];
|
|
534
534
|
let sqlAttribute = false;
|
|
535
|
-
let spanName = txStatements[
|
|
535
|
+
let spanName = txStatements[sql5.toLowerCase()];
|
|
536
536
|
if (!spanName) {
|
|
537
537
|
spanName = "Database Query";
|
|
538
538
|
sqlAttribute = true;
|
|
@@ -600,9 +600,9 @@ function getDialect(connString) {
|
|
|
600
600
|
pool.on("connect", (client) => {
|
|
601
601
|
const originalQuery = client.query;
|
|
602
602
|
client.query = function(...args) {
|
|
603
|
-
const
|
|
603
|
+
const sql5 = args[0];
|
|
604
604
|
let sqlAttribute = false;
|
|
605
|
-
let spanName = txStatements[
|
|
605
|
+
let spanName = txStatements[sql5.toLowerCase()];
|
|
606
606
|
if (!spanName) {
|
|
607
607
|
spanName = "Database Query";
|
|
608
608
|
sqlAttribute = true;
|
|
@@ -976,7 +976,7 @@ function transformRichDataTypes(data) {
|
|
|
976
976
|
} else if (value.key && value.size && value.filename && value.contentType) {
|
|
977
977
|
row[key] = File.fromDbRecord(value);
|
|
978
978
|
} else {
|
|
979
|
-
row[key] = value;
|
|
979
|
+
row[key] = transformRichDataTypes(value);
|
|
980
980
|
}
|
|
981
981
|
} else {
|
|
982
982
|
row[key] = value;
|
|
@@ -1097,23 +1097,23 @@ var TimePeriod = class _TimePeriod {
|
|
|
1097
1097
|
return new _TimePeriod(period, value, offset, complete2);
|
|
1098
1098
|
}
|
|
1099
1099
|
periodStartSQL() {
|
|
1100
|
-
let
|
|
1100
|
+
let sql5 = "NOW()";
|
|
1101
1101
|
if (this.offset !== 0) {
|
|
1102
|
-
|
|
1102
|
+
sql5 = `${sql5} + INTERVAL '${this.offset} ${this.period}'`;
|
|
1103
1103
|
}
|
|
1104
1104
|
if (this.complete) {
|
|
1105
|
-
|
|
1105
|
+
sql5 = `DATE_TRUNC('${this.period}', ${sql5})`;
|
|
1106
1106
|
} else {
|
|
1107
|
-
|
|
1107
|
+
sql5 = `(${sql5})`;
|
|
1108
1108
|
}
|
|
1109
|
-
return
|
|
1109
|
+
return sql5;
|
|
1110
1110
|
}
|
|
1111
1111
|
periodEndSQL() {
|
|
1112
|
-
let
|
|
1112
|
+
let sql5 = this.periodStartSQL();
|
|
1113
1113
|
if (this.value != 0) {
|
|
1114
|
-
|
|
1114
|
+
sql5 = `(${sql5} + INTERVAL '${this.value} ${this.period}')`;
|
|
1115
1115
|
}
|
|
1116
|
-
return
|
|
1116
|
+
return sql5;
|
|
1117
1117
|
}
|
|
1118
1118
|
};
|
|
1119
1119
|
|
|
@@ -2517,7 +2517,9 @@ var FlowRun = class _FlowRun {
|
|
|
2517
2517
|
const name = spanNameForModelAPI(this._flowName, "refresh");
|
|
2518
2518
|
return withSpan(name, async () => {
|
|
2519
2519
|
const apiUrl = getApiUrl2();
|
|
2520
|
-
const url = `${apiUrl}/flows/json/${
|
|
2520
|
+
const url = `${apiUrl}/flows/json/${encodeURIComponent(
|
|
2521
|
+
this._flowName
|
|
2522
|
+
)}/${encodeURIComponent(this.id)}`;
|
|
2521
2523
|
const response = await fetch(url, {
|
|
2522
2524
|
method: "GET",
|
|
2523
2525
|
headers: buildHeaders2(this._identity, this._authToken)
|
|
@@ -2545,7 +2547,9 @@ var FlowRun = class _FlowRun {
|
|
|
2545
2547
|
const name = spanNameForModelAPI(this._flowName, "cancel");
|
|
2546
2548
|
return withSpan(name, async () => {
|
|
2547
2549
|
const apiUrl = getApiUrl2();
|
|
2548
|
-
const url = `${apiUrl}/flows/json/${
|
|
2550
|
+
const url = `${apiUrl}/flows/json/${encodeURIComponent(
|
|
2551
|
+
this._flowName
|
|
2552
|
+
)}/${encodeURIComponent(this.id)}/cancel`;
|
|
2549
2553
|
const response = await fetch(url, {
|
|
2550
2554
|
method: "POST",
|
|
2551
2555
|
headers: buildHeaders2(this._identity, this._authToken)
|
|
@@ -2605,7 +2609,7 @@ var FlowsAPI = class _FlowsAPI {
|
|
|
2605
2609
|
const name = spanNameForModelAPI(this._flowName, "start");
|
|
2606
2610
|
return withSpan(name, async () => {
|
|
2607
2611
|
const apiUrl = getApiUrl2();
|
|
2608
|
-
const url = `${apiUrl}/flows/json/${this._flowName}`;
|
|
2612
|
+
const url = `${apiUrl}/flows/json/${encodeURIComponent(this._flowName)}`;
|
|
2609
2613
|
const response = await fetch(url, {
|
|
2610
2614
|
method: "POST",
|
|
2611
2615
|
headers: buildHeaders2(this._identity, this._authToken),
|
|
@@ -2635,7 +2639,9 @@ var FlowsAPI = class _FlowsAPI {
|
|
|
2635
2639
|
const name = spanNameForModelAPI(this._flowName, "get");
|
|
2636
2640
|
return withSpan(name, async () => {
|
|
2637
2641
|
const apiUrl = getApiUrl2();
|
|
2638
|
-
const url = `${apiUrl}/flows/json/${
|
|
2642
|
+
const url = `${apiUrl}/flows/json/${encodeURIComponent(
|
|
2643
|
+
this._flowName
|
|
2644
|
+
)}/${encodeURIComponent(runId)}`;
|
|
2639
2645
|
const response = await fetch(url, {
|
|
2640
2646
|
method: "GET",
|
|
2641
2647
|
headers: buildHeaders2(this._identity, this._authToken)
|
|
@@ -2669,7 +2675,7 @@ var FlowsAPI = class _FlowsAPI {
|
|
|
2669
2675
|
const params = new URLSearchParams();
|
|
2670
2676
|
if (options.limit) params.set("limit", options.limit.toString());
|
|
2671
2677
|
if (options.offset) params.set("offset", options.offset.toString());
|
|
2672
|
-
const url = `${apiUrl}/flows/json/${this._flowName}${params.toString() ? "?" + params.toString() : ""}`;
|
|
2678
|
+
const url = `${apiUrl}/flows/json/${encodeURIComponent(this._flowName)}${params.toString() ? "?" + params.toString() : ""}`;
|
|
2673
2679
|
const response = await fetch(url, {
|
|
2674
2680
|
method: "GET",
|
|
2675
2681
|
headers: buildHeaders2(this._identity, this._authToken)
|
|
@@ -3280,15 +3286,59 @@ import {
|
|
|
3280
3286
|
import * as opentelemetry6 from "@opentelemetry/api";
|
|
3281
3287
|
|
|
3282
3288
|
// src/tryExecuteFlow.js
|
|
3289
|
+
import { sql as sql4 } from "kysely";
|
|
3283
3290
|
function tryExecuteFlow(db, request, cb) {
|
|
3284
|
-
return withDatabase(db, false, async () => {
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3291
|
+
return withDatabase(db, false, async ({ sDb }) => {
|
|
3292
|
+
const runId = request?.meta?.runId;
|
|
3293
|
+
if (runId && sDb) {
|
|
3294
|
+
await sql4`SELECT pg_advisory_lock(hashtextextended(${runId}, 0))`.execute(
|
|
3295
|
+
sDb
|
|
3296
|
+
);
|
|
3297
|
+
}
|
|
3298
|
+
try {
|
|
3299
|
+
return await withAuditContext(request, async () => {
|
|
3300
|
+
return cb();
|
|
3301
|
+
});
|
|
3302
|
+
} finally {
|
|
3303
|
+
if (runId && sDb) {
|
|
3304
|
+
await sql4`SELECT pg_advisory_unlock(hashtextextended(${runId}, 0))`.execute(sDb).catch(() => void 0);
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3288
3307
|
});
|
|
3289
3308
|
}
|
|
3290
3309
|
__name(tryExecuteFlow, "tryExecuteFlow");
|
|
3291
3310
|
|
|
3311
|
+
// src/flows/ui/elements/input/signature.ts
|
|
3312
|
+
var Signature = class {
|
|
3313
|
+
static {
|
|
3314
|
+
__name(this, "Signature");
|
|
3315
|
+
}
|
|
3316
|
+
constructor(data) {
|
|
3317
|
+
this.svg = data.svg;
|
|
3318
|
+
this.signedAt = data.signedAt;
|
|
3319
|
+
}
|
|
3320
|
+
async toPngDataURL() {
|
|
3321
|
+
const sharp = (await import("sharp")).default;
|
|
3322
|
+
const png = await sharp(Buffer.from(this.svg), { density: 300 }).png().toBuffer();
|
|
3323
|
+
return `data:image/png;base64,${png.toString("base64")}`;
|
|
3324
|
+
}
|
|
3325
|
+
};
|
|
3326
|
+
var signatureInput = /* @__PURE__ */ __name((name, options) => {
|
|
3327
|
+
return {
|
|
3328
|
+
__type: "input",
|
|
3329
|
+
uiConfig: {
|
|
3330
|
+
__type: "ui.input.signature",
|
|
3331
|
+
name,
|
|
3332
|
+
label: options?.label || name,
|
|
3333
|
+
optional: options?.optional || false,
|
|
3334
|
+
disabled: options?.disabled || false,
|
|
3335
|
+
helpText: options?.helpText
|
|
3336
|
+
},
|
|
3337
|
+
validate: options?.validate,
|
|
3338
|
+
getData: /* @__PURE__ */ __name((x) => new Signature(x), "getData")
|
|
3339
|
+
};
|
|
3340
|
+
}, "signatureInput");
|
|
3341
|
+
|
|
3292
3342
|
// src/flows/ui/elements/input/text.ts
|
|
3293
3343
|
var textInput = /* @__PURE__ */ __name((name, options) => {
|
|
3294
3344
|
return {
|
|
@@ -3420,6 +3470,28 @@ var selectOne = /* @__PURE__ */ __name((name, options) => {
|
|
|
3420
3470
|
}, "selectOne");
|
|
3421
3471
|
|
|
3422
3472
|
// src/flows/ui/page.ts
|
|
3473
|
+
async function applyElementGetData(content, data) {
|
|
3474
|
+
if (!data || typeof data !== "object" || !Array.isArray(content)) return data;
|
|
3475
|
+
for (const c of content) {
|
|
3476
|
+
const resolved = await c;
|
|
3477
|
+
if (!resolved || !("__type" in resolved)) continue;
|
|
3478
|
+
const name = resolved.uiConfig?.name;
|
|
3479
|
+
if (!name || !(name in data)) continue;
|
|
3480
|
+
if (resolved.__type === "input" && typeof resolved.getData === "function") {
|
|
3481
|
+
data[name] = resolved.getData(data[name]);
|
|
3482
|
+
} else if (resolved.__type === "iterator") {
|
|
3483
|
+
const rows = data[name];
|
|
3484
|
+
const inner = resolved.uiConfig?.content;
|
|
3485
|
+
if (Array.isArray(rows) && Array.isArray(inner)) {
|
|
3486
|
+
for (let i = 0; i < rows.length; i++) {
|
|
3487
|
+
rows[i] = await applyElementGetData(inner, rows[i]);
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3490
|
+
}
|
|
3491
|
+
}
|
|
3492
|
+
return data;
|
|
3493
|
+
}
|
|
3494
|
+
__name(applyElementGetData, "applyElementGetData");
|
|
3423
3495
|
async function callbackFn(elements, elementName, callbackName, data) {
|
|
3424
3496
|
const element = elements.find(
|
|
3425
3497
|
(el) => el.uiConfig && el.uiConfig.name === elementName
|
|
@@ -3876,6 +3948,87 @@ var fileInput = /* @__PURE__ */ __name((name, options) => {
|
|
|
3876
3948
|
};
|
|
3877
3949
|
}, "fileInput");
|
|
3878
3950
|
|
|
3951
|
+
// src/flows/ui/elements/input/imageCapture.ts
|
|
3952
|
+
var isMultiOptions = /* @__PURE__ */ __name((opts) => opts && opts.mode === "multi", "isMultiOptions");
|
|
3953
|
+
function validateEntry(entry, requireCaption, context7) {
|
|
3954
|
+
if (!entry?.file?.key) {
|
|
3955
|
+
return `${context7}: an image is required`;
|
|
3956
|
+
}
|
|
3957
|
+
if (requireCaption && !entry.caption?.trim()) {
|
|
3958
|
+
return `${context7}: a caption is required`;
|
|
3959
|
+
}
|
|
3960
|
+
return true;
|
|
3961
|
+
}
|
|
3962
|
+
__name(validateEntry, "validateEntry");
|
|
3963
|
+
var imageCapture = /* @__PURE__ */ __name((name, options) => {
|
|
3964
|
+
const requireCaption = options?.requireCaption ?? false;
|
|
3965
|
+
const mode = options?.mode ?? "single";
|
|
3966
|
+
const multi = isMultiOptions(options);
|
|
3967
|
+
const max = multi ? options?.max : void 0;
|
|
3968
|
+
const min = multi ? options?.min : void 0;
|
|
3969
|
+
return {
|
|
3970
|
+
__type: "input",
|
|
3971
|
+
uiConfig: {
|
|
3972
|
+
__type: "ui.input.imageCapture",
|
|
3973
|
+
name,
|
|
3974
|
+
label: options?.label || name,
|
|
3975
|
+
optional: options?.optional || false,
|
|
3976
|
+
disabled: options?.disabled || false,
|
|
3977
|
+
helpText: options?.helpText,
|
|
3978
|
+
mode,
|
|
3979
|
+
requireCaption,
|
|
3980
|
+
...multi ? { max, min } : {}
|
|
3981
|
+
},
|
|
3982
|
+
validate: /* @__PURE__ */ __name(async (data, action) => {
|
|
3983
|
+
const optional = options?.optional ?? false;
|
|
3984
|
+
if (mode === "multi") {
|
|
3985
|
+
const list2 = data ?? [];
|
|
3986
|
+
if (list2.length === 0) {
|
|
3987
|
+
if (!optional) return "At least one image is required";
|
|
3988
|
+
} else {
|
|
3989
|
+
if (min !== void 0 && list2.length < min) {
|
|
3990
|
+
return `At least ${min} image${min === 1 ? "" : "s"} required`;
|
|
3991
|
+
}
|
|
3992
|
+
if (max !== void 0 && list2.length > max) {
|
|
3993
|
+
return `At most ${max} image${max === 1 ? "" : "s"} allowed`;
|
|
3994
|
+
}
|
|
3995
|
+
for (let i = 0; i < list2.length; i++) {
|
|
3996
|
+
const result = validateEntry(
|
|
3997
|
+
list2[i],
|
|
3998
|
+
requireCaption,
|
|
3999
|
+
`Image ${i + 1}`
|
|
4000
|
+
);
|
|
4001
|
+
if (result !== true) return result;
|
|
4002
|
+
}
|
|
4003
|
+
}
|
|
4004
|
+
} else {
|
|
4005
|
+
const entry = data;
|
|
4006
|
+
const hasFile = !!entry?.file?.key;
|
|
4007
|
+
if (!optional && !hasFile) {
|
|
4008
|
+
return "An image is required";
|
|
4009
|
+
}
|
|
4010
|
+
if (hasFile) {
|
|
4011
|
+
const result = validateEntry(entry, requireCaption, "Image");
|
|
4012
|
+
if (result !== true) return result;
|
|
4013
|
+
}
|
|
4014
|
+
}
|
|
4015
|
+
return options?.validate?.(
|
|
4016
|
+
data,
|
|
4017
|
+
action
|
|
4018
|
+
) ?? true;
|
|
4019
|
+
}, "validate"),
|
|
4020
|
+
getData: /* @__PURE__ */ __name((x) => x, "getData"),
|
|
4021
|
+
getPresignedUploadURL: /* @__PURE__ */ __name((async (input) => {
|
|
4022
|
+
const file2 = new File(input);
|
|
4023
|
+
const url = await file2.getPresignedUploadUrl();
|
|
4024
|
+
return {
|
|
4025
|
+
url: url.toString(),
|
|
4026
|
+
key: file2.key
|
|
4027
|
+
};
|
|
4028
|
+
}), "getPresignedUploadURL")
|
|
4029
|
+
};
|
|
4030
|
+
}, "imageCapture");
|
|
4031
|
+
|
|
3879
4032
|
// src/flows/ui/elements/iterator.ts
|
|
3880
4033
|
var iterator = /* @__PURE__ */ __name((name, options) => {
|
|
3881
4034
|
return {
|
|
@@ -4218,7 +4371,10 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
4218
4371
|
if (step && step.status === "COMPLETED" /* COMPLETED */) {
|
|
4219
4372
|
span.setAttribute(KEEL_INTERNAL_ATTR, KEEL_INTERNAL_CHILDREN);
|
|
4220
4373
|
span.setAttribute("step.status", "COMPLETED" /* COMPLETED */);
|
|
4221
|
-
const parsedData2 =
|
|
4374
|
+
const parsedData2 = await applyElementGetData(
|
|
4375
|
+
options.content,
|
|
4376
|
+
transformRichDataTypes(step.value)
|
|
4377
|
+
);
|
|
4222
4378
|
if (step.action) {
|
|
4223
4379
|
return { data: parsedData2, action: step.action };
|
|
4224
4380
|
}
|
|
@@ -4295,7 +4451,10 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
4295
4451
|
endTime: /* @__PURE__ */ new Date()
|
|
4296
4452
|
}).where("id", "=", step.id).returningAll().executeTakeFirst();
|
|
4297
4453
|
span.setAttribute("step.status", "COMPLETED" /* COMPLETED */);
|
|
4298
|
-
const parsedData =
|
|
4454
|
+
const parsedData = await applyElementGetData(
|
|
4455
|
+
options.content,
|
|
4456
|
+
transformRichDataTypes(data)
|
|
4457
|
+
);
|
|
4299
4458
|
if (action) {
|
|
4300
4459
|
return { data: parsedData, action };
|
|
4301
4460
|
}
|
|
@@ -4310,7 +4469,9 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
4310
4469
|
dataGrid: dataGridInput,
|
|
4311
4470
|
datePicker: datePickerInput,
|
|
4312
4471
|
scan,
|
|
4313
|
-
file: fileInput
|
|
4472
|
+
file: fileInput,
|
|
4473
|
+
imageCapture,
|
|
4474
|
+
signature: signatureInput
|
|
4314
4475
|
},
|
|
4315
4476
|
display: {
|
|
4316
4477
|
divider,
|
|
@@ -4565,6 +4726,7 @@ export {
|
|
|
4565
4726
|
RetryConstant,
|
|
4566
4727
|
STEP_STATUS,
|
|
4567
4728
|
STEP_TYPE,
|
|
4729
|
+
Signature,
|
|
4568
4730
|
TaskAPI,
|
|
4569
4731
|
checkBuiltInPermissions,
|
|
4570
4732
|
createFlowContext,
|