@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.cjs
CHANGED
|
@@ -47,6 +47,7 @@ __export(index_exports, {
|
|
|
47
47
|
RetryConstant: () => RetryConstant,
|
|
48
48
|
STEP_STATUS: () => STEP_STATUS,
|
|
49
49
|
STEP_TYPE: () => STEP_TYPE,
|
|
50
|
+
Signature: () => Signature,
|
|
50
51
|
TaskAPI: () => TaskAPI,
|
|
51
52
|
checkBuiltInPermissions: () => checkBuiltInPermissions,
|
|
52
53
|
createFlowContext: () => createFlowContext,
|
|
@@ -587,9 +588,9 @@ var InstrumentedClient = class extends import_pg.Client {
|
|
|
587
588
|
}
|
|
588
589
|
async query(...args) {
|
|
589
590
|
const _super = super.query.bind(this);
|
|
590
|
-
const
|
|
591
|
+
const sql5 = args[0];
|
|
591
592
|
let sqlAttribute = false;
|
|
592
|
-
let spanName = txStatements[
|
|
593
|
+
let spanName = txStatements[sql5.toLowerCase()];
|
|
593
594
|
if (!spanName) {
|
|
594
595
|
spanName = "Database Query";
|
|
595
596
|
sqlAttribute = true;
|
|
@@ -657,9 +658,9 @@ function getDialect(connString) {
|
|
|
657
658
|
pool.on("connect", (client) => {
|
|
658
659
|
const originalQuery = client.query;
|
|
659
660
|
client.query = function(...args) {
|
|
660
|
-
const
|
|
661
|
+
const sql5 = args[0];
|
|
661
662
|
let sqlAttribute = false;
|
|
662
|
-
let spanName = txStatements[
|
|
663
|
+
let spanName = txStatements[sql5.toLowerCase()];
|
|
663
664
|
if (!spanName) {
|
|
664
665
|
spanName = "Database Query";
|
|
665
666
|
sqlAttribute = true;
|
|
@@ -1029,7 +1030,7 @@ function transformRichDataTypes(data) {
|
|
|
1029
1030
|
} else if (value.key && value.size && value.filename && value.contentType) {
|
|
1030
1031
|
row[key] = File.fromDbRecord(value);
|
|
1031
1032
|
} else {
|
|
1032
|
-
row[key] = value;
|
|
1033
|
+
row[key] = transformRichDataTypes(value);
|
|
1033
1034
|
}
|
|
1034
1035
|
} else {
|
|
1035
1036
|
row[key] = value;
|
|
@@ -1150,23 +1151,23 @@ var TimePeriod = class _TimePeriod {
|
|
|
1150
1151
|
return new _TimePeriod(period, value, offset, complete2);
|
|
1151
1152
|
}
|
|
1152
1153
|
periodStartSQL() {
|
|
1153
|
-
let
|
|
1154
|
+
let sql5 = "NOW()";
|
|
1154
1155
|
if (this.offset !== 0) {
|
|
1155
|
-
|
|
1156
|
+
sql5 = `${sql5} + INTERVAL '${this.offset} ${this.period}'`;
|
|
1156
1157
|
}
|
|
1157
1158
|
if (this.complete) {
|
|
1158
|
-
|
|
1159
|
+
sql5 = `DATE_TRUNC('${this.period}', ${sql5})`;
|
|
1159
1160
|
} else {
|
|
1160
|
-
|
|
1161
|
+
sql5 = `(${sql5})`;
|
|
1161
1162
|
}
|
|
1162
|
-
return
|
|
1163
|
+
return sql5;
|
|
1163
1164
|
}
|
|
1164
1165
|
periodEndSQL() {
|
|
1165
|
-
let
|
|
1166
|
+
let sql5 = this.periodStartSQL();
|
|
1166
1167
|
if (this.value != 0) {
|
|
1167
|
-
|
|
1168
|
+
sql5 = `(${sql5} + INTERVAL '${this.value} ${this.period}')`;
|
|
1168
1169
|
}
|
|
1169
|
-
return
|
|
1170
|
+
return sql5;
|
|
1170
1171
|
}
|
|
1171
1172
|
};
|
|
1172
1173
|
|
|
@@ -2570,7 +2571,9 @@ var FlowRun = class _FlowRun {
|
|
|
2570
2571
|
const name = spanNameForModelAPI(this._flowName, "refresh");
|
|
2571
2572
|
return withSpan(name, async () => {
|
|
2572
2573
|
const apiUrl = getApiUrl2();
|
|
2573
|
-
const url = `${apiUrl}/flows/json/${
|
|
2574
|
+
const url = `${apiUrl}/flows/json/${encodeURIComponent(
|
|
2575
|
+
this._flowName
|
|
2576
|
+
)}/${encodeURIComponent(this.id)}`;
|
|
2574
2577
|
const response = await fetch(url, {
|
|
2575
2578
|
method: "GET",
|
|
2576
2579
|
headers: buildHeaders2(this._identity, this._authToken)
|
|
@@ -2598,7 +2601,9 @@ var FlowRun = class _FlowRun {
|
|
|
2598
2601
|
const name = spanNameForModelAPI(this._flowName, "cancel");
|
|
2599
2602
|
return withSpan(name, async () => {
|
|
2600
2603
|
const apiUrl = getApiUrl2();
|
|
2601
|
-
const url = `${apiUrl}/flows/json/${
|
|
2604
|
+
const url = `${apiUrl}/flows/json/${encodeURIComponent(
|
|
2605
|
+
this._flowName
|
|
2606
|
+
)}/${encodeURIComponent(this.id)}/cancel`;
|
|
2602
2607
|
const response = await fetch(url, {
|
|
2603
2608
|
method: "POST",
|
|
2604
2609
|
headers: buildHeaders2(this._identity, this._authToken)
|
|
@@ -2658,7 +2663,7 @@ var FlowsAPI = class _FlowsAPI {
|
|
|
2658
2663
|
const name = spanNameForModelAPI(this._flowName, "start");
|
|
2659
2664
|
return withSpan(name, async () => {
|
|
2660
2665
|
const apiUrl = getApiUrl2();
|
|
2661
|
-
const url = `${apiUrl}/flows/json/${this._flowName}`;
|
|
2666
|
+
const url = `${apiUrl}/flows/json/${encodeURIComponent(this._flowName)}`;
|
|
2662
2667
|
const response = await fetch(url, {
|
|
2663
2668
|
method: "POST",
|
|
2664
2669
|
headers: buildHeaders2(this._identity, this._authToken),
|
|
@@ -2688,7 +2693,9 @@ var FlowsAPI = class _FlowsAPI {
|
|
|
2688
2693
|
const name = spanNameForModelAPI(this._flowName, "get");
|
|
2689
2694
|
return withSpan(name, async () => {
|
|
2690
2695
|
const apiUrl = getApiUrl2();
|
|
2691
|
-
const url = `${apiUrl}/flows/json/${
|
|
2696
|
+
const url = `${apiUrl}/flows/json/${encodeURIComponent(
|
|
2697
|
+
this._flowName
|
|
2698
|
+
)}/${encodeURIComponent(runId)}`;
|
|
2692
2699
|
const response = await fetch(url, {
|
|
2693
2700
|
method: "GET",
|
|
2694
2701
|
headers: buildHeaders2(this._identity, this._authToken)
|
|
@@ -2722,7 +2729,7 @@ var FlowsAPI = class _FlowsAPI {
|
|
|
2722
2729
|
const params = new URLSearchParams();
|
|
2723
2730
|
if (options.limit) params.set("limit", options.limit.toString());
|
|
2724
2731
|
if (options.offset) params.set("offset", options.offset.toString());
|
|
2725
|
-
const url = `${apiUrl}/flows/json/${this._flowName}${params.toString() ? "?" + params.toString() : ""}`;
|
|
2732
|
+
const url = `${apiUrl}/flows/json/${encodeURIComponent(this._flowName)}${params.toString() ? "?" + params.toString() : ""}`;
|
|
2726
2733
|
const response = await fetch(url, {
|
|
2727
2734
|
method: "GET",
|
|
2728
2735
|
headers: buildHeaders2(this._identity, this._authToken)
|
|
@@ -3313,15 +3320,59 @@ var import_json_rpc_26 = require("json-rpc-2.0");
|
|
|
3313
3320
|
var opentelemetry6 = __toESM(require("@opentelemetry/api"), 1);
|
|
3314
3321
|
|
|
3315
3322
|
// src/tryExecuteFlow.js
|
|
3323
|
+
var import_kysely6 = require("kysely");
|
|
3316
3324
|
function tryExecuteFlow(db, request, cb) {
|
|
3317
|
-
return withDatabase(db, false, async () => {
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3325
|
+
return withDatabase(db, false, async ({ sDb }) => {
|
|
3326
|
+
const runId = request?.meta?.runId;
|
|
3327
|
+
if (runId && sDb) {
|
|
3328
|
+
await import_kysely6.sql`SELECT pg_advisory_lock(hashtextextended(${runId}, 0))`.execute(
|
|
3329
|
+
sDb
|
|
3330
|
+
);
|
|
3331
|
+
}
|
|
3332
|
+
try {
|
|
3333
|
+
return await withAuditContext(request, async () => {
|
|
3334
|
+
return cb();
|
|
3335
|
+
});
|
|
3336
|
+
} finally {
|
|
3337
|
+
if (runId && sDb) {
|
|
3338
|
+
await import_kysely6.sql`SELECT pg_advisory_unlock(hashtextextended(${runId}, 0))`.execute(sDb).catch(() => void 0);
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3321
3341
|
});
|
|
3322
3342
|
}
|
|
3323
3343
|
__name(tryExecuteFlow, "tryExecuteFlow");
|
|
3324
3344
|
|
|
3345
|
+
// src/flows/ui/elements/input/signature.ts
|
|
3346
|
+
var Signature = class {
|
|
3347
|
+
static {
|
|
3348
|
+
__name(this, "Signature");
|
|
3349
|
+
}
|
|
3350
|
+
constructor(data) {
|
|
3351
|
+
this.svg = data.svg;
|
|
3352
|
+
this.signedAt = data.signedAt;
|
|
3353
|
+
}
|
|
3354
|
+
async toPngDataURL() {
|
|
3355
|
+
const sharp = (await import("sharp")).default;
|
|
3356
|
+
const png = await sharp(Buffer.from(this.svg), { density: 300 }).png().toBuffer();
|
|
3357
|
+
return `data:image/png;base64,${png.toString("base64")}`;
|
|
3358
|
+
}
|
|
3359
|
+
};
|
|
3360
|
+
var signatureInput = /* @__PURE__ */ __name((name, options) => {
|
|
3361
|
+
return {
|
|
3362
|
+
__type: "input",
|
|
3363
|
+
uiConfig: {
|
|
3364
|
+
__type: "ui.input.signature",
|
|
3365
|
+
name,
|
|
3366
|
+
label: options?.label || name,
|
|
3367
|
+
optional: options?.optional || false,
|
|
3368
|
+
disabled: options?.disabled || false,
|
|
3369
|
+
helpText: options?.helpText
|
|
3370
|
+
},
|
|
3371
|
+
validate: options?.validate,
|
|
3372
|
+
getData: /* @__PURE__ */ __name((x) => new Signature(x), "getData")
|
|
3373
|
+
};
|
|
3374
|
+
}, "signatureInput");
|
|
3375
|
+
|
|
3325
3376
|
// src/flows/ui/elements/input/text.ts
|
|
3326
3377
|
var textInput = /* @__PURE__ */ __name((name, options) => {
|
|
3327
3378
|
return {
|
|
@@ -3453,6 +3504,28 @@ var selectOne = /* @__PURE__ */ __name((name, options) => {
|
|
|
3453
3504
|
}, "selectOne");
|
|
3454
3505
|
|
|
3455
3506
|
// src/flows/ui/page.ts
|
|
3507
|
+
async function applyElementGetData(content, data) {
|
|
3508
|
+
if (!data || typeof data !== "object" || !Array.isArray(content)) return data;
|
|
3509
|
+
for (const c of content) {
|
|
3510
|
+
const resolved = await c;
|
|
3511
|
+
if (!resolved || !("__type" in resolved)) continue;
|
|
3512
|
+
const name = resolved.uiConfig?.name;
|
|
3513
|
+
if (!name || !(name in data)) continue;
|
|
3514
|
+
if (resolved.__type === "input" && typeof resolved.getData === "function") {
|
|
3515
|
+
data[name] = resolved.getData(data[name]);
|
|
3516
|
+
} else if (resolved.__type === "iterator") {
|
|
3517
|
+
const rows = data[name];
|
|
3518
|
+
const inner = resolved.uiConfig?.content;
|
|
3519
|
+
if (Array.isArray(rows) && Array.isArray(inner)) {
|
|
3520
|
+
for (let i = 0; i < rows.length; i++) {
|
|
3521
|
+
rows[i] = await applyElementGetData(inner, rows[i]);
|
|
3522
|
+
}
|
|
3523
|
+
}
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
return data;
|
|
3527
|
+
}
|
|
3528
|
+
__name(applyElementGetData, "applyElementGetData");
|
|
3456
3529
|
async function callbackFn(elements, elementName, callbackName, data) {
|
|
3457
3530
|
const element = elements.find(
|
|
3458
3531
|
(el) => el.uiConfig && el.uiConfig.name === elementName
|
|
@@ -3909,6 +3982,87 @@ var fileInput = /* @__PURE__ */ __name((name, options) => {
|
|
|
3909
3982
|
};
|
|
3910
3983
|
}, "fileInput");
|
|
3911
3984
|
|
|
3985
|
+
// src/flows/ui/elements/input/imageCapture.ts
|
|
3986
|
+
var isMultiOptions = /* @__PURE__ */ __name((opts) => opts && opts.mode === "multi", "isMultiOptions");
|
|
3987
|
+
function validateEntry(entry, requireCaption, context7) {
|
|
3988
|
+
if (!entry?.file?.key) {
|
|
3989
|
+
return `${context7}: an image is required`;
|
|
3990
|
+
}
|
|
3991
|
+
if (requireCaption && !entry.caption?.trim()) {
|
|
3992
|
+
return `${context7}: a caption is required`;
|
|
3993
|
+
}
|
|
3994
|
+
return true;
|
|
3995
|
+
}
|
|
3996
|
+
__name(validateEntry, "validateEntry");
|
|
3997
|
+
var imageCapture = /* @__PURE__ */ __name((name, options) => {
|
|
3998
|
+
const requireCaption = options?.requireCaption ?? false;
|
|
3999
|
+
const mode = options?.mode ?? "single";
|
|
4000
|
+
const multi = isMultiOptions(options);
|
|
4001
|
+
const max = multi ? options?.max : void 0;
|
|
4002
|
+
const min = multi ? options?.min : void 0;
|
|
4003
|
+
return {
|
|
4004
|
+
__type: "input",
|
|
4005
|
+
uiConfig: {
|
|
4006
|
+
__type: "ui.input.imageCapture",
|
|
4007
|
+
name,
|
|
4008
|
+
label: options?.label || name,
|
|
4009
|
+
optional: options?.optional || false,
|
|
4010
|
+
disabled: options?.disabled || false,
|
|
4011
|
+
helpText: options?.helpText,
|
|
4012
|
+
mode,
|
|
4013
|
+
requireCaption,
|
|
4014
|
+
...multi ? { max, min } : {}
|
|
4015
|
+
},
|
|
4016
|
+
validate: /* @__PURE__ */ __name(async (data, action) => {
|
|
4017
|
+
const optional = options?.optional ?? false;
|
|
4018
|
+
if (mode === "multi") {
|
|
4019
|
+
const list2 = data ?? [];
|
|
4020
|
+
if (list2.length === 0) {
|
|
4021
|
+
if (!optional) return "At least one image is required";
|
|
4022
|
+
} else {
|
|
4023
|
+
if (min !== void 0 && list2.length < min) {
|
|
4024
|
+
return `At least ${min} image${min === 1 ? "" : "s"} required`;
|
|
4025
|
+
}
|
|
4026
|
+
if (max !== void 0 && list2.length > max) {
|
|
4027
|
+
return `At most ${max} image${max === 1 ? "" : "s"} allowed`;
|
|
4028
|
+
}
|
|
4029
|
+
for (let i = 0; i < list2.length; i++) {
|
|
4030
|
+
const result = validateEntry(
|
|
4031
|
+
list2[i],
|
|
4032
|
+
requireCaption,
|
|
4033
|
+
`Image ${i + 1}`
|
|
4034
|
+
);
|
|
4035
|
+
if (result !== true) return result;
|
|
4036
|
+
}
|
|
4037
|
+
}
|
|
4038
|
+
} else {
|
|
4039
|
+
const entry = data;
|
|
4040
|
+
const hasFile = !!entry?.file?.key;
|
|
4041
|
+
if (!optional && !hasFile) {
|
|
4042
|
+
return "An image is required";
|
|
4043
|
+
}
|
|
4044
|
+
if (hasFile) {
|
|
4045
|
+
const result = validateEntry(entry, requireCaption, "Image");
|
|
4046
|
+
if (result !== true) return result;
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
4049
|
+
return options?.validate?.(
|
|
4050
|
+
data,
|
|
4051
|
+
action
|
|
4052
|
+
) ?? true;
|
|
4053
|
+
}, "validate"),
|
|
4054
|
+
getData: /* @__PURE__ */ __name((x) => x, "getData"),
|
|
4055
|
+
getPresignedUploadURL: /* @__PURE__ */ __name((async (input) => {
|
|
4056
|
+
const file2 = new File(input);
|
|
4057
|
+
const url = await file2.getPresignedUploadUrl();
|
|
4058
|
+
return {
|
|
4059
|
+
url: url.toString(),
|
|
4060
|
+
key: file2.key
|
|
4061
|
+
};
|
|
4062
|
+
}), "getPresignedUploadURL")
|
|
4063
|
+
};
|
|
4064
|
+
}, "imageCapture");
|
|
4065
|
+
|
|
3912
4066
|
// src/flows/ui/elements/iterator.ts
|
|
3913
4067
|
var iterator = /* @__PURE__ */ __name((name, options) => {
|
|
3914
4068
|
return {
|
|
@@ -4251,7 +4405,10 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
4251
4405
|
if (step && step.status === "COMPLETED" /* COMPLETED */) {
|
|
4252
4406
|
span.setAttribute(KEEL_INTERNAL_ATTR, KEEL_INTERNAL_CHILDREN);
|
|
4253
4407
|
span.setAttribute("step.status", "COMPLETED" /* COMPLETED */);
|
|
4254
|
-
const parsedData2 =
|
|
4408
|
+
const parsedData2 = await applyElementGetData(
|
|
4409
|
+
options.content,
|
|
4410
|
+
transformRichDataTypes(step.value)
|
|
4411
|
+
);
|
|
4255
4412
|
if (step.action) {
|
|
4256
4413
|
return { data: parsedData2, action: step.action };
|
|
4257
4414
|
}
|
|
@@ -4328,7 +4485,10 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
4328
4485
|
endTime: /* @__PURE__ */ new Date()
|
|
4329
4486
|
}).where("id", "=", step.id).returningAll().executeTakeFirst();
|
|
4330
4487
|
span.setAttribute("step.status", "COMPLETED" /* COMPLETED */);
|
|
4331
|
-
const parsedData =
|
|
4488
|
+
const parsedData = await applyElementGetData(
|
|
4489
|
+
options.content,
|
|
4490
|
+
transformRichDataTypes(data)
|
|
4491
|
+
);
|
|
4332
4492
|
if (action) {
|
|
4333
4493
|
return { data: parsedData, action };
|
|
4334
4494
|
}
|
|
@@ -4343,7 +4503,9 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
4343
4503
|
dataGrid: dataGridInput,
|
|
4344
4504
|
datePicker: datePickerInput,
|
|
4345
4505
|
scan,
|
|
4346
|
-
file: fileInput
|
|
4506
|
+
file: fileInput,
|
|
4507
|
+
imageCapture,
|
|
4508
|
+
signature: signatureInput
|
|
4347
4509
|
},
|
|
4348
4510
|
display: {
|
|
4349
4511
|
divider,
|
|
@@ -4599,6 +4761,7 @@ __name(ksuid, "ksuid");
|
|
|
4599
4761
|
RetryConstant,
|
|
4600
4762
|
STEP_STATUS,
|
|
4601
4763
|
STEP_TYPE,
|
|
4764
|
+
Signature,
|
|
4602
4765
|
TaskAPI,
|
|
4603
4766
|
checkBuiltInPermissions,
|
|
4604
4767
|
createFlowContext,
|