@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.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 sql4 = args[0];
533
+ const sql5 = args[0];
534
534
  let sqlAttribute = false;
535
- let spanName = txStatements[sql4.toLowerCase()];
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 sql4 = args[0];
603
+ const sql5 = args[0];
604
604
  let sqlAttribute = false;
605
- let spanName = txStatements[sql4.toLowerCase()];
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 sql4 = "NOW()";
1100
+ let sql5 = "NOW()";
1101
1101
  if (this.offset !== 0) {
1102
- sql4 = `${sql4} + INTERVAL '${this.offset} ${this.period}'`;
1102
+ sql5 = `${sql5} + INTERVAL '${this.offset} ${this.period}'`;
1103
1103
  }
1104
1104
  if (this.complete) {
1105
- sql4 = `DATE_TRUNC('${this.period}', ${sql4})`;
1105
+ sql5 = `DATE_TRUNC('${this.period}', ${sql5})`;
1106
1106
  } else {
1107
- sql4 = `(${sql4})`;
1107
+ sql5 = `(${sql5})`;
1108
1108
  }
1109
- return sql4;
1109
+ return sql5;
1110
1110
  }
1111
1111
  periodEndSQL() {
1112
- let sql4 = this.periodStartSQL();
1112
+ let sql5 = this.periodStartSQL();
1113
1113
  if (this.value != 0) {
1114
- sql4 = `(${sql4} + INTERVAL '${this.value} ${this.period}')`;
1114
+ sql5 = `(${sql5} + INTERVAL '${this.value} ${this.period}')`;
1115
1115
  }
1116
- return sql4;
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/${this._flowName}/${this.id}`;
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/${this._flowName}/${this.id}/cancel`;
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/${this._flowName}/${runId}`;
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
- return withAuditContext(request, async () => {
3286
- return cb();
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 = transformRichDataTypes(step.value);
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 = transformRichDataTypes(data);
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,