@teamkeel/functions-runtime 0.450.0 → 0.451.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 +324 -229
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -2
- package/dist/index.d.ts +24 -2
- package/dist/index.js +323 -229
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -195,17 +195,20 @@ var tracing_exports = {};
|
|
|
195
195
|
__export(tracing_exports, {
|
|
196
196
|
KEEL_INTERNAL_ATTR: () => KEEL_INTERNAL_ATTR,
|
|
197
197
|
KEEL_INTERNAL_CHILDREN: () => KEEL_INTERNAL_CHILDREN,
|
|
198
|
+
createTraceAPI: () => createTraceAPI,
|
|
198
199
|
forceFlush: () => forceFlush,
|
|
199
200
|
getTracer: () => getTracer,
|
|
200
201
|
init: () => init,
|
|
201
202
|
spanNameForModelAPI: () => spanNameForModelAPI,
|
|
202
|
-
withSpan: () => withSpan
|
|
203
|
+
withSpan: () => withSpan,
|
|
204
|
+
withUserSpan: () => withUserSpan
|
|
203
205
|
});
|
|
204
206
|
import * as opentelemetry from "@opentelemetry/api";
|
|
205
207
|
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
206
208
|
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
|
|
207
209
|
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
208
210
|
import { envDetectorSync } from "@opentelemetry/resources";
|
|
211
|
+
var userSpanContextKey = opentelemetry.createContextKey("keel.userSpan");
|
|
209
212
|
async function withSpan(name, fn) {
|
|
210
213
|
return getTracer().startActiveSpan(name, async (span) => {
|
|
211
214
|
try {
|
|
@@ -225,6 +228,73 @@ async function withSpan(name, fn) {
|
|
|
225
228
|
});
|
|
226
229
|
}
|
|
227
230
|
__name(withSpan, "withSpan");
|
|
231
|
+
function withUserSpan(span, fn) {
|
|
232
|
+
const ctx = opentelemetry.context.active().setValue(userSpanContextKey, span);
|
|
233
|
+
return opentelemetry.context.with(ctx, fn);
|
|
234
|
+
}
|
|
235
|
+
__name(withUserSpan, "withUserSpan");
|
|
236
|
+
function getUserSpan() {
|
|
237
|
+
return opentelemetry.context.active().getValue(userSpanContextKey);
|
|
238
|
+
}
|
|
239
|
+
__name(getUserSpan, "getUserSpan");
|
|
240
|
+
function resolveTraceSpan(defaultSpan) {
|
|
241
|
+
const span = getUserSpan() ?? defaultSpan;
|
|
242
|
+
if (!span) {
|
|
243
|
+
throw new Error("no user span available for ctx.trace");
|
|
244
|
+
}
|
|
245
|
+
return span;
|
|
246
|
+
}
|
|
247
|
+
__name(resolveTraceSpan, "resolveTraceSpan");
|
|
248
|
+
function normalizeTraceAttributeValue(value) {
|
|
249
|
+
if (value === void 0) {
|
|
250
|
+
return void 0;
|
|
251
|
+
}
|
|
252
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
253
|
+
return value;
|
|
254
|
+
}
|
|
255
|
+
if (Array.isArray(value)) {
|
|
256
|
+
if (value.length === 0) {
|
|
257
|
+
return value;
|
|
258
|
+
}
|
|
259
|
+
const firstType = typeof value[0];
|
|
260
|
+
const validArrayType = firstType === "string" || firstType === "number" || firstType === "boolean";
|
|
261
|
+
if (validArrayType && value.every((item) => typeof item === firstType)) {
|
|
262
|
+
return value;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
throw new TypeError(
|
|
266
|
+
"trace attribute values must be strings, numbers, booleans, or arrays of a single primitive type"
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
__name(normalizeTraceAttributeValue, "normalizeTraceAttributeValue");
|
|
270
|
+
function createTraceAPI(defaultSpan) {
|
|
271
|
+
return {
|
|
272
|
+
get traceId() {
|
|
273
|
+
return resolveTraceSpan(defaultSpan).spanContext().traceId;
|
|
274
|
+
},
|
|
275
|
+
get spanId() {
|
|
276
|
+
return resolveTraceSpan(defaultSpan).spanContext().spanId;
|
|
277
|
+
},
|
|
278
|
+
setAttribute(key, value) {
|
|
279
|
+
const normalized = normalizeTraceAttributeValue(value);
|
|
280
|
+
if (normalized === void 0) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
resolveTraceSpan(defaultSpan).setAttribute(key, normalized);
|
|
284
|
+
},
|
|
285
|
+
setAttributes(attributes) {
|
|
286
|
+
const normalized = {};
|
|
287
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
288
|
+
const normalizedValue = normalizeTraceAttributeValue(value);
|
|
289
|
+
if (normalizedValue !== void 0) {
|
|
290
|
+
normalized[key] = normalizedValue;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
resolveTraceSpan(defaultSpan).setAttributes(normalized);
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
__name(createTraceAPI, "createTraceAPI");
|
|
228
298
|
function patchFetch() {
|
|
229
299
|
if (!globalThis.fetch.patched) {
|
|
230
300
|
const originalFetch = globalThis.fetch;
|
|
@@ -1004,7 +1074,11 @@ var TimePeriod = class _TimePeriod {
|
|
|
1004
1074
|
let value = rawValue ? parseInt(rawValue, 10) : 1;
|
|
1005
1075
|
let complete2 = Boolean(isComplete);
|
|
1006
1076
|
let offset = 0;
|
|
1007
|
-
|
|
1077
|
+
const dir = direction?.toLowerCase();
|
|
1078
|
+
if (!complete2 && !rawValue && (dir === "last" || dir === "next") && ["day", "week", "month", "year"].includes(period)) {
|
|
1079
|
+
complete2 = true;
|
|
1080
|
+
}
|
|
1081
|
+
switch (dir) {
|
|
1008
1082
|
case "this":
|
|
1009
1083
|
offset = 0;
|
|
1010
1084
|
complete2 = true;
|
|
@@ -1062,10 +1136,14 @@ var opMapping = {
|
|
|
1062
1136
|
},
|
|
1063
1137
|
notEquals: { op: sql2`is distinct from` },
|
|
1064
1138
|
equalsRelative: {
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1139
|
+
custom: /* @__PURE__ */ __name((qb, fieldName, v) => {
|
|
1140
|
+
const tp = TimePeriod.fromExpression(v);
|
|
1141
|
+
return qb.where(
|
|
1142
|
+
sql2`${sql2.raw(fieldName)} >= ${sql2.raw(
|
|
1143
|
+
tp.periodStartSQL()
|
|
1144
|
+
)} AND ${sql2.raw(fieldName)} < ${sql2.raw(tp.periodEndSQL())}`
|
|
1145
|
+
);
|
|
1146
|
+
}, "custom")
|
|
1069
1147
|
},
|
|
1070
1148
|
beforeRelative: {
|
|
1071
1149
|
op: "<",
|
|
@@ -1102,18 +1180,18 @@ var opMapping = {
|
|
|
1102
1180
|
notEquals: { op: "=", value: /* @__PURE__ */ __name((v) => sql2`NOT ${v}`, "value") }
|
|
1103
1181
|
}
|
|
1104
1182
|
};
|
|
1105
|
-
function applyWhereConditions(
|
|
1106
|
-
const conf =
|
|
1183
|
+
function applyWhereConditions(context7, qb, where = {}) {
|
|
1184
|
+
const conf = context7.tableConfig();
|
|
1107
1185
|
for (const key of Object.keys(where)) {
|
|
1108
1186
|
const v = where[key];
|
|
1109
1187
|
if (conf && conf[snakeCase(key)]) {
|
|
1110
1188
|
const rel = conf[snakeCase(key)];
|
|
1111
|
-
|
|
1112
|
-
qb = applyWhereConditions(
|
|
1189
|
+
context7.withJoin(rel.referencesTable, () => {
|
|
1190
|
+
qb = applyWhereConditions(context7, qb, v);
|
|
1113
1191
|
});
|
|
1114
1192
|
continue;
|
|
1115
1193
|
}
|
|
1116
|
-
const fieldName = `${
|
|
1194
|
+
const fieldName = `${context7.tableAlias()}.${snakeCase(key)}`;
|
|
1117
1195
|
if (Object.prototype.toString.call(v) !== "[object Object]") {
|
|
1118
1196
|
const operator = v === null || Array.isArray(v) ? sql2`is not distinct from` : "=";
|
|
1119
1197
|
qb = qb.where(fieldName, operator, sql2`${v}`);
|
|
@@ -1124,7 +1202,9 @@ function applyWhereConditions(context6, qb, where = {}) {
|
|
|
1124
1202
|
if (!mapping) {
|
|
1125
1203
|
throw new Error(`invalid where condition: ${op}`);
|
|
1126
1204
|
}
|
|
1127
|
-
if (mapping.
|
|
1205
|
+
if (mapping.custom) {
|
|
1206
|
+
qb = mapping.custom(qb, fieldName, v[op]);
|
|
1207
|
+
} else if (mapping.isArrayQuery) {
|
|
1128
1208
|
for (const arrayOp of Object.keys(v[op])) {
|
|
1129
1209
|
qb = qb.where(
|
|
1130
1210
|
mapping[arrayOp].value ? mapping[arrayOp].value(v[op][arrayOp]) : sql2`${v[op][arrayOp]}`,
|
|
@@ -1147,15 +1227,15 @@ function applyWhereConditions(context6, qb, where = {}) {
|
|
|
1147
1227
|
__name(applyWhereConditions, "applyWhereConditions");
|
|
1148
1228
|
|
|
1149
1229
|
// src/applyAdditionalQueryConstraints.js
|
|
1150
|
-
function applyLimit(
|
|
1230
|
+
function applyLimit(context7, qb, limit) {
|
|
1151
1231
|
return qb.limit(limit);
|
|
1152
1232
|
}
|
|
1153
1233
|
__name(applyLimit, "applyLimit");
|
|
1154
|
-
function applyOffset(
|
|
1234
|
+
function applyOffset(context7, qb, offset) {
|
|
1155
1235
|
return qb.offset(offset);
|
|
1156
1236
|
}
|
|
1157
1237
|
__name(applyOffset, "applyOffset");
|
|
1158
|
-
function applyOrderBy(
|
|
1238
|
+
function applyOrderBy(context7, qb, tableName, orderBy = {}) {
|
|
1159
1239
|
Object.entries(orderBy).forEach(([key, sortOrder]) => {
|
|
1160
1240
|
qb = qb.orderBy(`${tableName}.${snakeCase(key)}`, sortOrder.toLowerCase());
|
|
1161
1241
|
});
|
|
@@ -1164,41 +1244,41 @@ function applyOrderBy(context6, qb, tableName, orderBy = {}) {
|
|
|
1164
1244
|
__name(applyOrderBy, "applyOrderBy");
|
|
1165
1245
|
|
|
1166
1246
|
// src/applyJoins.js
|
|
1167
|
-
function applyJoins(
|
|
1168
|
-
const conf =
|
|
1247
|
+
function applyJoins(context7, qb, where) {
|
|
1248
|
+
const conf = context7.tableConfig();
|
|
1169
1249
|
if (!conf) {
|
|
1170
1250
|
return qb;
|
|
1171
1251
|
}
|
|
1172
|
-
const srcTable =
|
|
1252
|
+
const srcTable = context7.tableAlias();
|
|
1173
1253
|
for (const key of Object.keys(where)) {
|
|
1174
1254
|
const rel = conf[snakeCase(key)];
|
|
1175
1255
|
if (!rel) {
|
|
1176
1256
|
continue;
|
|
1177
1257
|
}
|
|
1178
1258
|
const targetTable = rel.referencesTable;
|
|
1179
|
-
if (
|
|
1259
|
+
if (context7.hasJoin(targetTable)) {
|
|
1180
1260
|
continue;
|
|
1181
1261
|
}
|
|
1182
|
-
|
|
1262
|
+
context7.withJoin(targetTable, () => {
|
|
1183
1263
|
switch (rel.relationshipType) {
|
|
1184
1264
|
case "hasMany":
|
|
1185
1265
|
qb = qb.innerJoin(
|
|
1186
|
-
`${targetTable} as ${
|
|
1266
|
+
`${targetTable} as ${context7.tableAlias()}`,
|
|
1187
1267
|
`${srcTable}.id`,
|
|
1188
|
-
`${
|
|
1268
|
+
`${context7.tableAlias()}.${rel.foreignKey}`
|
|
1189
1269
|
);
|
|
1190
1270
|
break;
|
|
1191
1271
|
case "belongsTo":
|
|
1192
1272
|
qb = qb.innerJoin(
|
|
1193
|
-
`${targetTable} as ${
|
|
1273
|
+
`${targetTable} as ${context7.tableAlias()}`,
|
|
1194
1274
|
`${srcTable}.${rel.foreignKey}`,
|
|
1195
|
-
`${
|
|
1275
|
+
`${context7.tableAlias()}.id`
|
|
1196
1276
|
);
|
|
1197
1277
|
break;
|
|
1198
1278
|
default:
|
|
1199
1279
|
throw new Error(`unknown relationshipType: ${rel.relationshipType}`);
|
|
1200
1280
|
}
|
|
1201
|
-
qb = applyJoins(
|
|
1281
|
+
qb = applyJoins(context7, qb, where[key]);
|
|
1202
1282
|
});
|
|
1203
1283
|
}
|
|
1204
1284
|
return qb;
|
|
@@ -1428,17 +1508,17 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
1428
1508
|
* @param {import("./QueryContext").QueryContext} context
|
|
1429
1509
|
* @param {import("kysely").Kysely} db
|
|
1430
1510
|
*/
|
|
1431
|
-
constructor(tableName,
|
|
1511
|
+
constructor(tableName, context7, db) {
|
|
1432
1512
|
this._tableName = tableName;
|
|
1433
|
-
this._context =
|
|
1513
|
+
this._context = context7;
|
|
1434
1514
|
this._db = db;
|
|
1435
1515
|
this._modelName = upperCamelCase(this._tableName);
|
|
1436
1516
|
}
|
|
1437
1517
|
where(where) {
|
|
1438
|
-
const
|
|
1439
|
-
let builder = applyJoins(
|
|
1440
|
-
builder = applyWhereConditions(
|
|
1441
|
-
return new _QueryBuilder(this._tableName,
|
|
1518
|
+
const context7 = this._context.clone();
|
|
1519
|
+
let builder = applyJoins(context7, this._db, where);
|
|
1520
|
+
builder = applyWhereConditions(context7, builder, where);
|
|
1521
|
+
return new _QueryBuilder(this._tableName, context7, builder);
|
|
1442
1522
|
}
|
|
1443
1523
|
sql() {
|
|
1444
1524
|
return this._db.compile().sql;
|
|
@@ -1503,19 +1583,19 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
1503
1583
|
const name = spanNameForModelAPI(this._modelName, "findMany");
|
|
1504
1584
|
const db = useDatabase();
|
|
1505
1585
|
return withSpan(name, async (span) => {
|
|
1506
|
-
const
|
|
1586
|
+
const context7 = new QueryContext([this._tableName], this._tableConfigMap);
|
|
1507
1587
|
let builder = db.selectFrom((qb) => {
|
|
1508
1588
|
return this._db.as(this._tableName);
|
|
1509
1589
|
}).selectAll();
|
|
1510
1590
|
if (params?.limit) {
|
|
1511
|
-
builder = applyLimit(
|
|
1591
|
+
builder = applyLimit(context7, builder, params.limit);
|
|
1512
1592
|
}
|
|
1513
1593
|
if (params?.offset) {
|
|
1514
|
-
builder = applyOffset(
|
|
1594
|
+
builder = applyOffset(context7, builder, params.offset);
|
|
1515
1595
|
}
|
|
1516
1596
|
if (params?.orderBy !== void 0 && Object.keys(params?.orderBy).length > 0) {
|
|
1517
1597
|
builder = applyOrderBy(
|
|
1518
|
-
|
|
1598
|
+
context7,
|
|
1519
1599
|
builder,
|
|
1520
1600
|
this._tableName,
|
|
1521
1601
|
params.orderBy
|
|
@@ -1549,7 +1629,7 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
1549
1629
|
);
|
|
1550
1630
|
const db = useDatabase();
|
|
1551
1631
|
return withSpan(name, async (span) => {
|
|
1552
|
-
const
|
|
1632
|
+
const context7 = new QueryContext([this._tableName], this._tableConfigMap);
|
|
1553
1633
|
const isOffsetPagination = params.limit != null && params.limit > 0;
|
|
1554
1634
|
const isBackward = params.last != null && params.last > 0;
|
|
1555
1635
|
const DEFAULT_PAGE_SIZE = 50;
|
|
@@ -1597,7 +1677,7 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
1597
1677
|
])
|
|
1598
1678
|
) : normalizedOrderBy;
|
|
1599
1679
|
builder = applyOrderBy(
|
|
1600
|
-
|
|
1680
|
+
context7,
|
|
1601
1681
|
builder,
|
|
1602
1682
|
this._tableName,
|
|
1603
1683
|
effectiveOrderBy
|
|
@@ -1670,10 +1750,10 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
1670
1750
|
}
|
|
1671
1751
|
}
|
|
1672
1752
|
if (limit != null) {
|
|
1673
|
-
builder = applyLimit(
|
|
1753
|
+
builder = applyLimit(context7, builder, limit);
|
|
1674
1754
|
}
|
|
1675
1755
|
if (isOffsetPagination && params.offset) {
|
|
1676
|
-
builder = applyOffset(
|
|
1756
|
+
builder = applyOffset(context7, builder, params.offset);
|
|
1677
1757
|
}
|
|
1678
1758
|
span.setAttribute("sql", builder.compile().sql);
|
|
1679
1759
|
let rows = await builder.execute();
|
|
@@ -1778,9 +1858,9 @@ var ModelAPI = class {
|
|
|
1778
1858
|
const db = useDatabase();
|
|
1779
1859
|
return withSpan(name, async (span) => {
|
|
1780
1860
|
let builder = db.selectFrom(this._tableName).distinctOn(`${this._tableName}.id`).selectAll(this._tableName);
|
|
1781
|
-
const
|
|
1782
|
-
builder = applyJoins(
|
|
1783
|
-
builder = applyWhereConditions(
|
|
1861
|
+
const context7 = new QueryContext([this._tableName], this._tableConfigMap);
|
|
1862
|
+
builder = applyJoins(context7, builder, where);
|
|
1863
|
+
builder = applyWhereConditions(context7, builder, where);
|
|
1784
1864
|
span.setAttribute("sql", builder.compile().sql);
|
|
1785
1865
|
const row = await builder.executeTakeFirst();
|
|
1786
1866
|
if (!row) {
|
|
@@ -1794,23 +1874,23 @@ var ModelAPI = class {
|
|
|
1794
1874
|
const db = useDatabase();
|
|
1795
1875
|
const where = params?.where || {};
|
|
1796
1876
|
return withSpan(name, async (span) => {
|
|
1797
|
-
const
|
|
1877
|
+
const context7 = new QueryContext([this._tableName], this._tableConfigMap);
|
|
1798
1878
|
let builder = db.selectFrom((qb) => {
|
|
1799
1879
|
let builder2 = qb.selectFrom(this._tableName).distinctOn(`${this._tableName}.id`).selectAll(this._tableName);
|
|
1800
|
-
builder2 = applyJoins(
|
|
1801
|
-
builder2 = applyWhereConditions(
|
|
1880
|
+
builder2 = applyJoins(context7, builder2, where);
|
|
1881
|
+
builder2 = applyWhereConditions(context7, builder2, where);
|
|
1802
1882
|
builder2 = builder2.as(this._tableName);
|
|
1803
1883
|
return builder2;
|
|
1804
1884
|
}).selectAll();
|
|
1805
1885
|
if (params?.limit) {
|
|
1806
|
-
builder = applyLimit(
|
|
1886
|
+
builder = applyLimit(context7, builder, params.limit);
|
|
1807
1887
|
}
|
|
1808
1888
|
if (params?.offset) {
|
|
1809
|
-
builder = applyOffset(
|
|
1889
|
+
builder = applyOffset(context7, builder, params.offset);
|
|
1810
1890
|
}
|
|
1811
1891
|
if (params?.orderBy !== void 0 && Object.keys(params?.orderBy).length > 0) {
|
|
1812
1892
|
builder = applyOrderBy(
|
|
1813
|
-
|
|
1893
|
+
context7,
|
|
1814
1894
|
builder,
|
|
1815
1895
|
this._tableName,
|
|
1816
1896
|
params.orderBy
|
|
@@ -1861,8 +1941,8 @@ var ModelAPI = class {
|
|
|
1861
1941
|
}
|
|
1862
1942
|
}
|
|
1863
1943
|
builder = builder.set(snakeCaseObject(row));
|
|
1864
|
-
const
|
|
1865
|
-
builder = applyWhereConditions(
|
|
1944
|
+
const context7 = new QueryContext([this._tableName], this._tableConfigMap);
|
|
1945
|
+
builder = applyWhereConditions(context7, builder, where);
|
|
1866
1946
|
span.setAttribute("sql", builder.compile().sql);
|
|
1867
1947
|
try {
|
|
1868
1948
|
const row2 = await builder.executeTakeFirstOrThrow();
|
|
@@ -1877,8 +1957,8 @@ var ModelAPI = class {
|
|
|
1877
1957
|
const db = useDatabase();
|
|
1878
1958
|
return withSpan(name, async (span) => {
|
|
1879
1959
|
let builder = db.deleteFrom(this._tableName).returning(["id"]);
|
|
1880
|
-
const
|
|
1881
|
-
builder = applyWhereConditions(
|
|
1960
|
+
const context7 = new QueryContext([this._tableName], this._tableConfigMap);
|
|
1961
|
+
builder = applyWhereConditions(context7, builder, where);
|
|
1882
1962
|
span.setAttribute("sql", builder.compile().sql);
|
|
1883
1963
|
try {
|
|
1884
1964
|
const row = await builder.executeTakeFirstOrThrow();
|
|
@@ -1891,10 +1971,10 @@ var ModelAPI = class {
|
|
|
1891
1971
|
where(where) {
|
|
1892
1972
|
const db = useDatabase();
|
|
1893
1973
|
let builder = db.selectFrom(this._tableName).distinctOn(`${this._tableName}.id`).selectAll(this._tableName);
|
|
1894
|
-
const
|
|
1895
|
-
builder = applyJoins(
|
|
1896
|
-
builder = applyWhereConditions(
|
|
1897
|
-
return new QueryBuilder(this._tableName,
|
|
1974
|
+
const context7 = new QueryContext([this._tableName], this._tableConfigMap);
|
|
1975
|
+
builder = applyJoins(context7, builder, where);
|
|
1976
|
+
builder = applyWhereConditions(context7, builder, where);
|
|
1977
|
+
return new QueryBuilder(this._tableName, context7, builder);
|
|
1898
1978
|
}
|
|
1899
1979
|
};
|
|
1900
1980
|
async function create(conn, tableName, tableConfigs, values) {
|
|
@@ -2841,7 +2921,8 @@ async function handleRequest(request, config) {
|
|
|
2841
2921
|
const headers = new Headers();
|
|
2842
2922
|
const ctx = createContextAPI({
|
|
2843
2923
|
responseHeaders: headers,
|
|
2844
|
-
meta: request.meta
|
|
2924
|
+
meta: request.meta,
|
|
2925
|
+
span
|
|
2845
2926
|
});
|
|
2846
2927
|
const permitted = request.meta && request.meta.permissionState.status === "granted" ? true : null;
|
|
2847
2928
|
db = createDatabaseClient({
|
|
@@ -2964,7 +3045,8 @@ async function handleJob(request, config) {
|
|
|
2964
3045
|
);
|
|
2965
3046
|
}
|
|
2966
3047
|
const ctx = createJobContextAPI({
|
|
2967
|
-
meta: request.meta
|
|
3048
|
+
meta: request.meta,
|
|
3049
|
+
span
|
|
2968
3050
|
});
|
|
2969
3051
|
const permitted = request.meta && request.meta.permissionState.status === "granted" ? true : null;
|
|
2970
3052
|
db = createDatabaseClient({
|
|
@@ -3056,7 +3138,8 @@ async function handleSubscriber(request, config) {
|
|
|
3056
3138
|
);
|
|
3057
3139
|
}
|
|
3058
3140
|
const ctx = createSubscriberContextAPI({
|
|
3059
|
-
meta: request.meta
|
|
3141
|
+
meta: request.meta,
|
|
3142
|
+
span
|
|
3060
3143
|
});
|
|
3061
3144
|
db = createDatabaseClient({
|
|
3062
3145
|
connString: request.meta?.secrets?.KEEL_DB_CONN
|
|
@@ -3136,7 +3219,8 @@ async function handleRoute(request, config) {
|
|
|
3136
3219
|
...ctx
|
|
3137
3220
|
} = createContextAPI({
|
|
3138
3221
|
responseHeaders: new Headers(),
|
|
3139
|
-
meta: request.meta
|
|
3222
|
+
meta: request.meta,
|
|
3223
|
+
span
|
|
3140
3224
|
});
|
|
3141
3225
|
request.params.headers = headers;
|
|
3142
3226
|
db = createDatabaseClient({
|
|
@@ -3983,6 +4067,7 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
3983
4067
|
env: ctx.env,
|
|
3984
4068
|
now: ctx.now,
|
|
3985
4069
|
secrets: ctx.secrets,
|
|
4070
|
+
trace: ctx.trace,
|
|
3986
4071
|
complete: /* @__PURE__ */ __name((options) => {
|
|
3987
4072
|
return {
|
|
3988
4073
|
__type: "ui.complete",
|
|
@@ -3991,116 +4076,19 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
3991
4076
|
}, "complete"),
|
|
3992
4077
|
step: /* @__PURE__ */ __name(async (name, optionsOrFn, fn) => {
|
|
3993
4078
|
return withSpan(`Step - ${name}`, async (span) => {
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
if (usedNames.has(name)) {
|
|
4000
|
-
await db.insertInto("keel.flow_step").values({
|
|
4001
|
-
run_id: runId,
|
|
4002
|
-
name,
|
|
4003
|
-
stage: options.stage,
|
|
4004
|
-
status: "FAILED" /* FAILED */,
|
|
4005
|
-
type: "FUNCTION" /* FUNCTION */,
|
|
4006
|
-
error: `Duplicate step name: ${name}`,
|
|
4007
|
-
startTime: /* @__PURE__ */ new Date(),
|
|
4008
|
-
endTime: /* @__PURE__ */ new Date()
|
|
4009
|
-
}).returningAll().executeTakeFirst();
|
|
4010
|
-
throw new Error(`Duplicate step name: ${name}`);
|
|
4011
|
-
}
|
|
4012
|
-
usedNames.add(name);
|
|
4013
|
-
const past = await db.selectFrom("keel.flow_step").where("run_id", "=", runId).where("name", "=", name).selectAll().execute();
|
|
4014
|
-
const newSteps = past.filter((step) => step.status === "NEW" /* NEW */);
|
|
4015
|
-
const completedSteps = past.filter(
|
|
4016
|
-
(step) => step.status === "COMPLETED" /* COMPLETED */
|
|
4017
|
-
);
|
|
4018
|
-
const failedSteps = past.filter(
|
|
4019
|
-
(step) => step.status === "FAILED" /* FAILED */
|
|
4020
|
-
);
|
|
4021
|
-
if (newSteps.length > 1) {
|
|
4022
|
-
throw new Error("Multiple NEW steps found for the same step");
|
|
4023
|
-
}
|
|
4024
|
-
if (completedSteps.length > 1) {
|
|
4025
|
-
throw new Error("Multiple completed steps found for the same step");
|
|
4026
|
-
}
|
|
4027
|
-
if (completedSteps.length > 1 && newSteps.length > 1) {
|
|
4028
|
-
throw new Error(
|
|
4029
|
-
"Multiple completed and new steps found for the same step"
|
|
4030
|
-
);
|
|
4031
|
-
}
|
|
4032
|
-
if (completedSteps.length === 1) {
|
|
4033
|
-
span.setAttribute(KEEL_INTERNAL_ATTR, KEEL_INTERNAL_CHILDREN);
|
|
4034
|
-
return completedSteps[0].value;
|
|
4035
|
-
}
|
|
4036
|
-
if (newSteps.length === 1) {
|
|
4037
|
-
let result = null;
|
|
4038
|
-
await db.updateTable("keel.flow_step").set({
|
|
4039
|
-
startTime: /* @__PURE__ */ new Date()
|
|
4040
|
-
}).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
|
|
4041
|
-
try {
|
|
4042
|
-
const stepArgs = {
|
|
4043
|
-
attempt: failedSteps.length + 1,
|
|
4044
|
-
stepOptions: options
|
|
4045
|
-
};
|
|
4046
|
-
result = await withTimeout(actualFn(stepArgs), options.timeout);
|
|
4047
|
-
} catch (e) {
|
|
4048
|
-
await db.updateTable("keel.flow_step").set({
|
|
4049
|
-
status: "FAILED" /* FAILED */,
|
|
4050
|
-
spanId,
|
|
4051
|
-
endTime: /* @__PURE__ */ new Date(),
|
|
4052
|
-
error: e instanceof Error ? e.message : "An error occurred"
|
|
4053
|
-
}).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
|
|
4054
|
-
if (failedSteps.length >= options.retries || e instanceof NonRetriableError) {
|
|
4055
|
-
if (options.onFailure) {
|
|
4056
|
-
await options.onFailure();
|
|
4057
|
-
}
|
|
4058
|
-
throw new ExhuastedRetriesDisrupt();
|
|
4059
|
-
}
|
|
4060
|
-
await db.insertInto("keel.flow_step").values({
|
|
4061
|
-
run_id: runId,
|
|
4062
|
-
name,
|
|
4063
|
-
stage: options.stage,
|
|
4064
|
-
status: "NEW" /* NEW */,
|
|
4065
|
-
type: "FUNCTION" /* FUNCTION */
|
|
4066
|
-
}).returningAll().executeTakeFirst();
|
|
4067
|
-
throw new StepCreatedDisrupt(
|
|
4068
|
-
options.retryPolicy ? new Date(
|
|
4069
|
-
Date.now() + options.retryPolicy(failedSteps.length + 1)
|
|
4070
|
-
) : void 0
|
|
4071
|
-
);
|
|
4072
|
-
}
|
|
4073
|
-
await db.updateTable("keel.flow_step").set({
|
|
4074
|
-
status: "COMPLETED" /* COMPLETED */,
|
|
4075
|
-
value: JSON.stringify(result),
|
|
4076
|
-
spanId,
|
|
4077
|
-
endTime: /* @__PURE__ */ new Date()
|
|
4078
|
-
}).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
|
|
4079
|
-
return result;
|
|
4080
|
-
}
|
|
4081
|
-
await db.insertInto("keel.flow_step").values({
|
|
4082
|
-
run_id: runId,
|
|
4083
|
-
name,
|
|
4084
|
-
stage: options.stage,
|
|
4085
|
-
status: "NEW" /* NEW */,
|
|
4086
|
-
type: "FUNCTION" /* FUNCTION */
|
|
4087
|
-
}).returningAll().executeTakeFirst();
|
|
4088
|
-
span.setAttribute(KEEL_INTERNAL_ATTR, KEEL_INTERNAL_CHILDREN);
|
|
4089
|
-
throw new StepCreatedDisrupt();
|
|
4090
|
-
});
|
|
4091
|
-
}, "step"),
|
|
4092
|
-
ui: {
|
|
4093
|
-
page: /* @__PURE__ */ __name((async (name, options) => {
|
|
4094
|
-
return withSpan(`Page - ${name}`, async (span) => {
|
|
4079
|
+
return withUserSpan(span, async () => {
|
|
4080
|
+
const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
|
|
4081
|
+
const actualFn = typeof optionsOrFn === "function" ? optionsOrFn : fn;
|
|
4082
|
+
options.retries = options.retries ?? defaultOpts.retries;
|
|
4083
|
+
options.timeout = options.timeout ?? defaultOpts.timeout;
|
|
4095
4084
|
const db = useDatabase();
|
|
4096
|
-
const isCallback = element && callback;
|
|
4097
4085
|
if (usedNames.has(name)) {
|
|
4098
4086
|
await db.insertInto("keel.flow_step").values({
|
|
4099
4087
|
run_id: runId,
|
|
4100
4088
|
name,
|
|
4101
4089
|
stage: options.stage,
|
|
4102
4090
|
status: "FAILED" /* FAILED */,
|
|
4103
|
-
type: "
|
|
4091
|
+
type: "FUNCTION" /* FUNCTION */,
|
|
4104
4092
|
error: `Duplicate step name: ${name}`,
|
|
4105
4093
|
startTime: /* @__PURE__ */ new Date(),
|
|
4106
4094
|
endTime: /* @__PURE__ */ new Date()
|
|
@@ -4108,85 +4096,188 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
|
|
|
4108
4096
|
throw new Error(`Duplicate step name: ${name}`);
|
|
4109
4097
|
}
|
|
4110
4098
|
usedNames.add(name);
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4099
|
+
const past = await db.selectFrom("keel.flow_step").where("run_id", "=", runId).where("name", "=", name).selectAll().execute();
|
|
4100
|
+
const newSteps = past.filter(
|
|
4101
|
+
(step) => step.status === "NEW" /* NEW */
|
|
4102
|
+
);
|
|
4103
|
+
const completedSteps = past.filter(
|
|
4104
|
+
(step) => step.status === "COMPLETED" /* COMPLETED */
|
|
4105
|
+
);
|
|
4106
|
+
const failedSteps = past.filter(
|
|
4107
|
+
(step) => step.status === "FAILED" /* FAILED */
|
|
4108
|
+
);
|
|
4109
|
+
if (newSteps.length > 1) {
|
|
4110
|
+
throw new Error("Multiple NEW steps found for the same step");
|
|
4119
4111
|
}
|
|
4120
|
-
if (
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
type: "UI" /* UI */,
|
|
4127
|
-
startTime: /* @__PURE__ */ new Date()
|
|
4128
|
-
}).returningAll().executeTakeFirst();
|
|
4129
|
-
span.setAttribute("rendered", true);
|
|
4130
|
-
throw new UIRenderDisrupt(
|
|
4131
|
-
step?.id,
|
|
4132
|
-
(await page(options, null, null)).page
|
|
4112
|
+
if (completedSteps.length > 1) {
|
|
4113
|
+
throw new Error("Multiple completed steps found for the same step");
|
|
4114
|
+
}
|
|
4115
|
+
if (completedSteps.length > 1 && newSteps.length > 1) {
|
|
4116
|
+
throw new Error(
|
|
4117
|
+
"Multiple completed and new steps found for the same step"
|
|
4133
4118
|
);
|
|
4134
4119
|
}
|
|
4135
|
-
if (
|
|
4136
|
-
span.setAttribute(
|
|
4120
|
+
if (completedSteps.length === 1) {
|
|
4121
|
+
span.setAttribute(KEEL_INTERNAL_ATTR, KEEL_INTERNAL_CHILDREN);
|
|
4122
|
+
return completedSteps[0].value;
|
|
4123
|
+
}
|
|
4124
|
+
if (newSteps.length === 1) {
|
|
4125
|
+
let result = null;
|
|
4126
|
+
await db.updateTable("keel.flow_step").set({
|
|
4127
|
+
startTime: /* @__PURE__ */ new Date()
|
|
4128
|
+
}).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
|
|
4137
4129
|
try {
|
|
4138
|
-
const
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
);
|
|
4144
|
-
throw new CallbackDisrupt(response, false);
|
|
4130
|
+
const stepArgs = {
|
|
4131
|
+
attempt: failedSteps.length + 1,
|
|
4132
|
+
stepOptions: options
|
|
4133
|
+
};
|
|
4134
|
+
result = await withTimeout(actualFn(stepArgs), options.timeout);
|
|
4145
4135
|
} catch (e) {
|
|
4146
|
-
|
|
4147
|
-
|
|
4136
|
+
await db.updateTable("keel.flow_step").set({
|
|
4137
|
+
status: "FAILED" /* FAILED */,
|
|
4138
|
+
spanId,
|
|
4139
|
+
endTime: /* @__PURE__ */ new Date(),
|
|
4140
|
+
error: e instanceof Error ? e.message : "An error occurred"
|
|
4141
|
+
}).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
|
|
4142
|
+
if (failedSteps.length >= options.retries || e instanceof NonRetriableError) {
|
|
4143
|
+
if (options.onFailure) {
|
|
4144
|
+
await options.onFailure();
|
|
4145
|
+
}
|
|
4146
|
+
throw new ExhuastedRetriesDisrupt();
|
|
4148
4147
|
}
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4148
|
+
await db.insertInto("keel.flow_step").values({
|
|
4149
|
+
run_id: runId,
|
|
4150
|
+
name,
|
|
4151
|
+
stage: options.stage,
|
|
4152
|
+
status: "NEW" /* NEW */,
|
|
4153
|
+
type: "FUNCTION" /* FUNCTION */
|
|
4154
|
+
}).returningAll().executeTakeFirst();
|
|
4155
|
+
throw new StepCreatedDisrupt(
|
|
4156
|
+
options.retryPolicy ? new Date(
|
|
4157
|
+
Date.now() + options.retryPolicy(failedSteps.length + 1)
|
|
4158
|
+
) : void 0
|
|
4152
4159
|
);
|
|
4153
4160
|
}
|
|
4161
|
+
await db.updateTable("keel.flow_step").set({
|
|
4162
|
+
status: "COMPLETED" /* COMPLETED */,
|
|
4163
|
+
value: JSON.stringify(result),
|
|
4164
|
+
spanId,
|
|
4165
|
+
endTime: /* @__PURE__ */ new Date()
|
|
4166
|
+
}).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
|
|
4167
|
+
return result;
|
|
4154
4168
|
}
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4169
|
+
await db.insertInto("keel.flow_step").values({
|
|
4170
|
+
run_id: runId,
|
|
4171
|
+
name,
|
|
4172
|
+
stage: options.stage,
|
|
4173
|
+
status: "NEW" /* NEW */,
|
|
4174
|
+
type: "FUNCTION" /* FUNCTION */
|
|
4175
|
+
}).returningAll().executeTakeFirst();
|
|
4176
|
+
span.setAttribute(KEEL_INTERNAL_ATTR, KEEL_INTERNAL_CHILDREN);
|
|
4177
|
+
throw new StepCreatedDisrupt();
|
|
4178
|
+
});
|
|
4179
|
+
});
|
|
4180
|
+
}, "step"),
|
|
4181
|
+
ui: {
|
|
4182
|
+
page: /* @__PURE__ */ __name((async (name, options) => {
|
|
4183
|
+
return withSpan(`Page - ${name}`, async (span) => {
|
|
4184
|
+
return withUserSpan(span, async () => {
|
|
4185
|
+
const db = useDatabase();
|
|
4186
|
+
const isCallback = element && callback;
|
|
4187
|
+
if (usedNames.has(name)) {
|
|
4188
|
+
await db.insertInto("keel.flow_step").values({
|
|
4189
|
+
run_id: runId,
|
|
4190
|
+
name,
|
|
4191
|
+
stage: options.stage,
|
|
4192
|
+
status: "FAILED" /* FAILED */,
|
|
4193
|
+
type: "UI" /* UI */,
|
|
4194
|
+
error: `Duplicate step name: ${name}`,
|
|
4195
|
+
startTime: /* @__PURE__ */ new Date(),
|
|
4196
|
+
endTime: /* @__PURE__ */ new Date()
|
|
4197
|
+
}).returningAll().executeTakeFirst();
|
|
4198
|
+
throw new Error(`Duplicate step name: ${name}`);
|
|
4199
|
+
}
|
|
4200
|
+
usedNames.add(name);
|
|
4201
|
+
let step = await db.selectFrom("keel.flow_step").where("run_id", "=", runId).where("name", "=", name).selectAll().executeTakeFirst();
|
|
4202
|
+
if (step && step.status === "COMPLETED" /* COMPLETED */) {
|
|
4203
|
+
span.setAttribute(KEEL_INTERNAL_ATTR, KEEL_INTERNAL_CHILDREN);
|
|
4204
|
+
const parsedData2 = transformRichDataTypes(step.value);
|
|
4205
|
+
if (step.action) {
|
|
4206
|
+
return { data: parsedData2, action: step.action };
|
|
4207
|
+
}
|
|
4208
|
+
return parsedData2;
|
|
4209
|
+
}
|
|
4210
|
+
if (!step) {
|
|
4211
|
+
step = await db.insertInto("keel.flow_step").values({
|
|
4212
|
+
run_id: runId,
|
|
4213
|
+
name,
|
|
4214
|
+
stage: options.stage,
|
|
4215
|
+
status: "PENDING" /* PENDING */,
|
|
4216
|
+
type: "UI" /* UI */,
|
|
4217
|
+
startTime: /* @__PURE__ */ new Date()
|
|
4218
|
+
}).returningAll().executeTakeFirst();
|
|
4219
|
+
span.setAttribute("rendered", true);
|
|
4220
|
+
throw new UIRenderDisrupt(
|
|
4221
|
+
step?.id,
|
|
4222
|
+
(await page(options, null, null)).page
|
|
4223
|
+
);
|
|
4224
|
+
}
|
|
4225
|
+
if (isCallback) {
|
|
4226
|
+
span.setAttribute("callback", callback);
|
|
4227
|
+
try {
|
|
4228
|
+
const response = await callbackFn(
|
|
4229
|
+
options.content,
|
|
4230
|
+
element,
|
|
4231
|
+
callback,
|
|
4232
|
+
data
|
|
4233
|
+
);
|
|
4234
|
+
throw new CallbackDisrupt(response, false);
|
|
4235
|
+
} catch (e) {
|
|
4236
|
+
if (e instanceof CallbackDisrupt) {
|
|
4237
|
+
throw e;
|
|
4238
|
+
}
|
|
4239
|
+
throw new CallbackDisrupt(
|
|
4240
|
+
e instanceof Error ? e.message : `An error occurred`,
|
|
4241
|
+
true
|
|
4242
|
+
);
|
|
4243
|
+
}
|
|
4165
4244
|
}
|
|
4166
|
-
|
|
4167
|
-
|
|
4245
|
+
if (!data) {
|
|
4246
|
+
throw new UIRenderDisrupt(
|
|
4247
|
+
step?.id,
|
|
4248
|
+
(await page(options, null, null)).page
|
|
4249
|
+
);
|
|
4250
|
+
}
|
|
4251
|
+
try {
|
|
4252
|
+
const p = await page(options, data, action);
|
|
4253
|
+
if (p.hasValidationErrors) {
|
|
4254
|
+
throw new UIRenderDisrupt(step?.id, p.page);
|
|
4255
|
+
}
|
|
4256
|
+
} catch (e) {
|
|
4257
|
+
if (e instanceof UIRenderDisrupt) {
|
|
4258
|
+
throw e;
|
|
4259
|
+
}
|
|
4260
|
+
await db.updateTable("keel.flow_step").set({
|
|
4261
|
+
status: "FAILED" /* FAILED */,
|
|
4262
|
+
spanId,
|
|
4263
|
+
endTime: /* @__PURE__ */ new Date(),
|
|
4264
|
+
error: e instanceof Error ? e.message : "An error occurred"
|
|
4265
|
+
}).where("id", "=", step?.id).returningAll().executeTakeFirst();
|
|
4168
4266
|
throw e;
|
|
4169
4267
|
}
|
|
4170
4268
|
await db.updateTable("keel.flow_step").set({
|
|
4171
|
-
status: "
|
|
4269
|
+
status: "COMPLETED" /* COMPLETED */,
|
|
4270
|
+
value: JSON.stringify(data),
|
|
4271
|
+
action,
|
|
4172
4272
|
spanId,
|
|
4173
|
-
endTime: /* @__PURE__ */ new Date()
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
action,
|
|
4182
|
-
spanId,
|
|
4183
|
-
endTime: /* @__PURE__ */ new Date()
|
|
4184
|
-
}).where("id", "=", step.id).returningAll().executeTakeFirst();
|
|
4185
|
-
const parsedData = transformRichDataTypes(data);
|
|
4186
|
-
if (action) {
|
|
4187
|
-
return { data: parsedData, action };
|
|
4188
|
-
}
|
|
4189
|
-
return parsedData;
|
|
4273
|
+
endTime: /* @__PURE__ */ new Date()
|
|
4274
|
+
}).where("id", "=", step.id).returningAll().executeTakeFirst();
|
|
4275
|
+
const parsedData = transformRichDataTypes(data);
|
|
4276
|
+
if (action) {
|
|
4277
|
+
return { data: parsedData, action };
|
|
4278
|
+
}
|
|
4279
|
+
return parsedData;
|
|
4280
|
+
});
|
|
4190
4281
|
});
|
|
4191
4282
|
}), "page"),
|
|
4192
4283
|
inputs: {
|
|
@@ -4300,7 +4391,8 @@ async function handleFlow(request, config) {
|
|
|
4300
4391
|
request.meta.element,
|
|
4301
4392
|
span.spanContext().spanId,
|
|
4302
4393
|
createFlowContextAPI({
|
|
4303
|
-
meta: request.meta
|
|
4394
|
+
meta: request.meta,
|
|
4395
|
+
span
|
|
4304
4396
|
})
|
|
4305
4397
|
);
|
|
4306
4398
|
const flowFunction = flows[request.method].fn;
|
|
@@ -4428,6 +4520,7 @@ __name(handleFlow, "handleFlow");
|
|
|
4428
4520
|
|
|
4429
4521
|
// src/index.ts
|
|
4430
4522
|
import KSUID2 from "ksuid";
|
|
4523
|
+
var createTraceAPI2 = createTraceAPI;
|
|
4431
4524
|
function ksuid() {
|
|
4432
4525
|
return KSUID2.randomSync().string;
|
|
4433
4526
|
}
|
|
@@ -4452,6 +4545,7 @@ export {
|
|
|
4452
4545
|
TaskAPI,
|
|
4453
4546
|
checkBuiltInPermissions,
|
|
4454
4547
|
createFlowContext,
|
|
4548
|
+
createTraceAPI2 as createTraceAPI,
|
|
4455
4549
|
handleFlow,
|
|
4456
4550
|
handleJob,
|
|
4457
4551
|
handleRequest,
|