@lotics/app-sdk 0.121.0 → 0.122.1

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
@@ -1848,13 +1848,16 @@ async function callEach(arr, cb) {
1848
1848
  let next = 0;
1849
1849
  let failed = false;
1850
1850
  const work = async () => {
1851
- while (!failed && next < arr.length) {
1851
+ while (next < arr.length && !failed) {
1852
1852
  const i = next;
1853
1853
  next += 1;
1854
- results[i] = await Promise.resolve().then(() => cb(arr[i], i)).catch((error51) => {
1854
+ try {
1855
+ const result = cb(arr[i], i);
1856
+ results[i] = result instanceof Promise ? await result : result;
1857
+ } catch (error51) {
1855
1858
  failed = true;
1856
1859
  throw error51;
1857
- });
1860
+ }
1858
1861
  }
1859
1862
  };
1860
1863
  const extra = arr.length > 1 ? cb.workers?.claim(arr.length - 1) ?? 0 : 0;
@@ -2047,7 +2050,8 @@ function find(arr, fieldOrCb, value) {
2047
2050
  }
2048
2051
  async function findByCallback(arr, cb) {
2049
2052
  for (let i = 0; i < arr.length; i++) {
2050
- if (await cb(arr[i], i)) return arr[i];
2053
+ const hit = cb(arr[i], i);
2054
+ if (hit instanceof Promise ? await hit : hit) return arr[i];
2051
2055
  }
2052
2056
  return void 0;
2053
2057
  }
@@ -2283,7 +2287,8 @@ function some(arr, fieldOrCb, value) {
2283
2287
  assertCallbackInput("some", arr);
2284
2288
  return (async () => {
2285
2289
  for (let i = 0; i < arr.length; i++) {
2286
- if (await fieldOrCb(arr[i], i)) return true;
2290
+ const hit = fieldOrCb(arr[i], i);
2291
+ if (hit instanceof Promise ? await hit : hit) return true;
2287
2292
  }
2288
2293
  return false;
2289
2294
  })();
@@ -2303,7 +2308,8 @@ function every(arr, fieldOrCb, value) {
2303
2308
  assertCallbackInput("every", arr);
2304
2309
  return (async () => {
2305
2310
  for (let i = 0; i < arr.length; i++) {
2306
- if (!await fieldOrCb(arr[i], i)) return false;
2311
+ const hit = fieldOrCb(arr[i], i);
2312
+ if (!(hit instanceof Promise ? await hit : hit)) return false;
2307
2313
  }
2308
2314
  return true;
2309
2315
  })();
@@ -2398,7 +2404,8 @@ async function reduce(arr, callback, initial) {
2398
2404
  assertCallbackInput("reduce", arr);
2399
2405
  let acc = initial;
2400
2406
  for (let i = 0; i < arr.length; i++) {
2401
- acc = await callback(acc, arr[i], i);
2407
+ const next = callback(acc, arr[i], i);
2408
+ acc = next instanceof Promise ? await next : next;
2402
2409
  }
2403
2410
  return acc;
2404
2411
  }
@@ -6121,11 +6128,9 @@ var HELPER_COST = {
6121
6128
  typeOf: "reads"
6122
6129
  };
6123
6130
  function helperCost(name) {
6124
- return isHelperName(name) ? HELPER_COST[name] : "builds";
6125
- }
6126
- function isHelperName(name) {
6127
- return Object.prototype.hasOwnProperty.call(HELPER_COST, name);
6131
+ return HELPER_COST_BY_NAME.get(name) ?? "builds";
6128
6132
  }
6133
+ var HELPER_COST_BY_NAME = new Map(Object.entries(HELPER_COST));
6129
6134
  function createTimezoneAwareFunctions(defaultTimezone) {
6130
6135
  return {
6131
6136
  // Number functions
@@ -27376,7 +27381,11 @@ function resolveLambdaItemFrame(frames, name) {
27376
27381
  }
27377
27382
  return void 0;
27378
27383
  }
27384
+ function lambdaItemAnchor(ctx, name) {
27385
+ return resolveLambdaItemFrame(ctx.lambda_items, name)?.anchor ?? null;
27386
+ }
27379
27387
  function readRecordAnchor(source, path, ctx) {
27388
+ if (source.from === "lambda_param") return lambdaItemAnchor(ctx, source.name);
27380
27389
  return anchorForRead(source, path, ctx, /* @__PURE__ */ new Set());
27381
27390
  }
27382
27391
  function anchorForRead(source, path, ctx, seen) {
@@ -27386,7 +27395,7 @@ function anchorForRead(source, path, ctx, seen) {
27386
27395
  case "foreach_item":
27387
27396
  return resolveNamedForeachFrame(ctx.foreach_items, source.name)?.anchor ?? null;
27388
27397
  case "lambda_param":
27389
- return resolveLambdaItemFrame(ctx.lambda_items, source.name)?.anchor ?? null;
27398
+ return lambdaItemAnchor(ctx, source.name);
27390
27399
  case "trigger_record":
27391
27400
  return rootAnchor(ctx.trigger_record);
27392
27401
  case "trigger_record_prev":
@@ -27697,7 +27706,7 @@ function assertCheap(budget, ...values2) {
27697
27706
  function charge(ctx, bytes) {
27698
27707
  const budget = ctx.evaluation_budget;
27699
27708
  assertUnsettled(budget);
27700
- if (Date.now() > ctx.run_budget.deadline_ms) throw new WorkflowTimeBudgetError(ctx.run_budget.subject, ctx.run_budget.budget_ms);
27709
+ if (readsClock(ctx) && Date.now() > ctx.run_budget.deadline_ms) throw new WorkflowTimeBudgetError(ctx.run_budget.subject, ctx.run_budget.budget_ms);
27701
27710
  if (budget.bounded && budget.built + bytes > MAX_IN_PLACE_BYTES) throw new ExpressionNotCheapError();
27702
27711
  budget.built += bytes;
27703
27712
  chargeBuilt(ctx.run_budget, bytes);
@@ -27716,8 +27725,8 @@ function callbackWorkers() {
27716
27725
  };
27717
27726
  }
27718
27727
  function evaluateWorkflowExpression(expr2, ctx, options = {}) {
27719
- const budget = { workers: callbackWorkers(), bounded: options.bounded === true, built: 0, settled: false };
27720
- return evaluateExpression(expr2, { ...ctx, evaluation_budget: budget }).finally(() => {
27728
+ const budget = { workers: callbackWorkers(), bounded: options.bounded === true, built: 0, clock_checks: 0, helpers: /* @__PURE__ */ new Map(), settled: false };
27729
+ return evaluateRoot(expr2, { ...ctx, evaluation_budget: budget, anchor_context: evalAnchorContext(ctx) }).finally(() => {
27721
27730
  budget.settled = true;
27722
27731
  }).then((answer) => {
27723
27732
  if (budget.bounded && expandedSize(answer, MAX_IN_PLACE_BYTES) > MAX_IN_PLACE_BYTES) throw new ExpressionNotCheapError();
@@ -27727,8 +27736,19 @@ function evaluateWorkflowExpression(expr2, ctx, options = {}) {
27727
27736
  throw error51;
27728
27737
  });
27729
27738
  }
27730
- async function evaluateExpression(expr2, ctx) {
27739
+ async function evaluateRoot(expr2, ctx) {
27731
27740
  for (let pause = checkClock(ctx); pause !== null; pause = checkClock(ctx)) await pause;
27741
+ return evaluateExpression(expr2, ctx);
27742
+ }
27743
+ function failBeside(error51, started) {
27744
+ void Promise.allSettled(started);
27745
+ throw error51;
27746
+ }
27747
+ async function startBeside(expr2, ctx) {
27748
+ return evaluateExpression(expr2, ctx);
27749
+ }
27750
+ function evaluateExpression(expr2, ctx) {
27751
+ assertUnsettled(ctx.evaluation_budget);
27732
27752
  switch (expr2.kind) {
27733
27753
  case "lit":
27734
27754
  return expr2.value;
@@ -27741,31 +27761,75 @@ async function evaluateExpression(expr2, ctx) {
27741
27761
  case "unary":
27742
27762
  return evaluateUnary(expr2.op, expr2.arg, ctx);
27743
27763
  case "ternary": {
27744
- const cond = await evaluateExpression(expr2.cond, ctx);
27745
- return cond ? evaluateExpression(expr2.then, ctx) : evaluateExpression(expr2.else, ctx);
27764
+ const cond = evaluateExpression(expr2.cond, ctx);
27765
+ return cond instanceof Promise ? branchAfter(cond, expr2.then, expr2.else, ctx) : evaluateExpression(cond ? expr2.then : expr2.else, ctx);
27746
27766
  }
27747
27767
  case "template":
27748
27768
  return evaluateTemplate(expr2.parts, ctx);
27749
27769
  case "lambda":
27750
27770
  return evaluateLambda(expr2.params, expr2.body, ctx, []);
27751
- case "array_literal": {
27752
- const elements = await Promise.all(expr2.elements.map((el) => evaluateExpression(el, ctx)));
27753
- charge(ctx, builtSize(elements));
27754
- return elements;
27755
- }
27756
- case "object_literal": {
27757
- const out = {};
27758
- for (const entry of expr2.entries) defineOwn(out, entry.key, await evaluateExpression(entry.value, ctx));
27759
- charge(ctx, builtSize(out));
27760
- return out;
27761
- }
27771
+ case "array_literal":
27772
+ return evaluateArrayLiteral(expr2.elements, ctx);
27773
+ case "object_literal":
27774
+ return fillObjectLiteral({}, expr2.entries, 0, ctx);
27762
27775
  default:
27763
27776
  return assertNever(expr2);
27764
27777
  }
27765
27778
  }
27779
+ async function branchAfter(cond, then, otherwise, ctx) {
27780
+ return evaluateExpression(await cond ? then : otherwise, ctx);
27781
+ }
27782
+ function evaluateArrayLiteral(elements, ctx) {
27783
+ const values2 = [];
27784
+ let pending = false;
27785
+ try {
27786
+ for (const element of elements) {
27787
+ const value = evaluateExpression(element, ctx);
27788
+ if (value instanceof Promise) pending = true;
27789
+ values2.push(value);
27790
+ }
27791
+ } catch (error51) {
27792
+ return failBeside(error51, values2);
27793
+ }
27794
+ return pending ? chargeAfter(values2, ctx) : chargedArray(values2, ctx);
27795
+ }
27796
+ async function chargeAfter(values2, ctx) {
27797
+ return chargedArray(await Promise.all(values2), ctx);
27798
+ }
27799
+ function chargedArray(elements, ctx) {
27800
+ charge(ctx, builtSize(elements));
27801
+ return elements;
27802
+ }
27803
+ function fillObjectLiteral(out, entries3, from, ctx) {
27804
+ for (let at2 = from; at2 < entries3.length; at2++) {
27805
+ const entry = entries3[at2];
27806
+ const value = evaluateExpression(entry.value, ctx);
27807
+ if (value instanceof Promise) return fillObjectAfter(out, entries3, at2, value, ctx);
27808
+ defineOwn(out, entry.key, value);
27809
+ }
27810
+ charge(ctx, builtSize(out));
27811
+ return out;
27812
+ }
27813
+ async function fillObjectAfter(out, entries3, at2, value, ctx) {
27814
+ defineOwn(out, entries3[at2].key, await value);
27815
+ return fillObjectLiteral(out, entries3, at2 + 1, ctx);
27816
+ }
27766
27817
  function checkClock(ctx) {
27767
27818
  assertUnsettled(ctx.evaluation_budget);
27768
- return runClock(ctx.run_budget);
27819
+ return readsClock(ctx) ? runClock(ctx.run_budget) : null;
27820
+ }
27821
+ var ISOLATED_CLOCK_STRIDE = 16;
27822
+ function readsClock(ctx) {
27823
+ if (ctx.run_budget.host === "shared") return true;
27824
+ const budget = ctx.evaluation_budget;
27825
+ budget.clock_checks += 1;
27826
+ if (budget.clock_checks % ISOLATED_CLOCK_STRIDE !== 1) return false;
27827
+ if (budget.clock_checks === 1) {
27828
+ queueMicrotask(() => {
27829
+ budget.clock_checks = 0;
27830
+ });
27831
+ }
27832
+ return true;
27769
27833
  }
27770
27834
  function assertUnsettled(budget) {
27771
27835
  if (budget.settled) {
@@ -27775,21 +27839,19 @@ function assertUnsettled(budget) {
27775
27839
  }
27776
27840
  }
27777
27841
  function evaluateLambda(params, body, ctx, items) {
27778
- const call = async (...args) => {
27779
- const frame2 = {};
27780
- for (let i = 0; i < params.length; i++) defineOwn(frame2, params[i], args[i]);
27781
- const stack = ctx.lambda_params ?? [];
27782
- const newStack = [...stack, frame2];
27783
- const innerCtx = {
27784
- ...ctx,
27785
- lambda_params: newStack,
27786
- // The VALUE frame and the ANCHOR frames are pushed together: a body that
27787
- // can read the item must read it through the same table the save layer
27788
- // typed it with, and a parameter that is not the item must shadow an
27789
- // outer one of the same name in both stacks alike.
27790
- lambda_items: items.length === 0 ? ctx.lambda_items : [...ctx.lambda_items ?? [], ...items]
27791
- };
27792
- return evaluateExpression(body, innerCtx);
27842
+ const lambdaItems = items.length === 0 ? ctx.lambda_items : [...ctx.lambda_items ?? [], ...items];
27843
+ const bodyCtx = {
27844
+ ...ctx,
27845
+ lambda_items: lambdaItems,
27846
+ anchor_context: { ...ctx.anchor_context, lambda_items: lambdaItems ?? [] }
27847
+ };
27848
+ const stack = ctx.lambda_params ?? [];
27849
+ const call = (...args) => {
27850
+ const pause = checkClock(bodyCtx);
27851
+ if (pause !== null) return pause.then(() => call(...args));
27852
+ const frame2 = /* @__PURE__ */ Object.create(null);
27853
+ for (let i = 0; i < params.length; i++) frame2[params[i]] = args[i];
27854
+ return evaluateExpression(body, { ...bodyCtx, lambda_params: [...stack, frame2] });
27793
27855
  };
27794
27856
  return Object.assign(call, { workers: ctx.evaluation_budget.workers });
27795
27857
  }
@@ -27809,9 +27871,6 @@ function evalAnchorContext(ctx) {
27809
27871
  trigger_changes: ctx.trigger_table
27810
27872
  };
27811
27873
  }
27812
- function resolveReadAnchor(source, path, ctx) {
27813
- return readRecordAnchor(source, path, evalAnchorContext(ctx));
27814
- }
27815
27874
  function resolveReadRoot(source, ctx) {
27816
27875
  switch (source.from) {
27817
27876
  case "trigger":
@@ -27921,29 +27980,37 @@ function resolveForeachFrame(ctx, name, at2) {
27921
27980
  { kind: "read", at: at2, extra: { name } }
27922
27981
  );
27923
27982
  }
27924
- async function evaluateRead(source, path, coerce, ctx) {
27925
- let current = source.from === "value" ? await evaluateExpression(source.expr, ctx) : resolveReadRoot(source, ctx);
27926
- const anchor = resolveReadAnchor(source, path, ctx);
27927
- let currentTable = null;
27928
- let prevFieldForSegment;
27929
- let terminalField;
27930
- for (let i = 0; i < path.length; i++) {
27983
+ function evaluateRead(source, path, coerce, ctx) {
27984
+ const root = source.from === "value" ? evaluateExpression(source.expr, ctx) : resolveReadRoot(source, ctx);
27985
+ return root instanceof Promise ? readAfter(root, source, path, coerce, ctx) : walkPath(path, coerce, ctx, readRecordAnchor(source, path, ctx.anchor_context), 0, root, null, void 0, void 0);
27986
+ }
27987
+ async function readAfter(root, source, path, coerce, ctx) {
27988
+ const value = await root;
27989
+ return walkPath(path, coerce, ctx, readRecordAnchor(source, path, ctx.anchor_context), 0, value, null, void 0, void 0);
27990
+ }
27991
+ function walkPath(path, coerce, ctx, anchor, from, start, startTable, startField, startTerminal) {
27992
+ let current = start;
27993
+ let table = startTable;
27994
+ let prevField = startField;
27995
+ let terminalField = startTerminal;
27996
+ for (let i = from; i < path.length; i++) {
27931
27997
  const segment = path[i];
27932
27998
  const isLast = i === path.length - 1;
27933
- if (anchor && i === anchor.envelopeLen) currentTable ??= anchor.table;
27999
+ if (anchor && i === anchor.envelopeLen) table ??= anchor.table;
27934
28000
  const carried = carriedTable(current, ctx);
27935
- if (carried?.at === "self") currentTable = carried.table;
27936
- const fieldForSegment = (segment.at === "field" || segment.at === "key") && currentTable ? findField(currentTable, segment.key) : void 0;
28001
+ if (carried?.at === "self") table = carried.table;
28002
+ const field = (segment.at === "field" || segment.at === "key") && table ? findField(table, segment.key) : void 0;
27937
28003
  if (isLast) {
27938
- terminalField = fieldForSegment ?? (segment.at === "key" && (segment.key === "next_value" || segment.key === "prev_value") ? prevFieldForSegment : void 0);
28004
+ terminalField = field ?? (segment.at === "key" && (segment.key === "next_value" || segment.key === "prev_value") ? prevField : void 0);
27939
28005
  }
27940
- current = await walkSegment(current, segment, ctx);
27941
- currentTable = advanceTable(segment, currentTable, ctx);
27942
- if (carried?.at === "data" && isKeyNamed(segment, "data")) currentTable = carried.table;
27943
- prevFieldForSegment = fieldForSegment;
27944
- if (current === void 0 || current === null) {
27945
- return current;
28006
+ const walked = walkSegment(current, segment, ctx);
28007
+ if (walked instanceof Promise) {
28008
+ return walkPending({ path, coerce, ctx, anchor, table, carried, field, terminal_field: terminalField }, i, walked);
27946
28009
  }
28010
+ table = tableAfter(segment, table, carried, ctx);
28011
+ prevField = field;
28012
+ current = walked;
28013
+ if (current === void 0 || current === null) return current;
27947
28014
  }
27948
28015
  if (terminalField && isScalarWrappedField(terminalField)) {
27949
28016
  current = unwrapScalarField(current);
@@ -27953,6 +28020,17 @@ async function evaluateRead(source, path, coerce, ctx) {
27953
28020
  }
27954
28021
  return current;
27955
28022
  }
28023
+ async function walkPending(read2, at2, walked) {
28024
+ const { path, coerce, ctx, anchor, carried, field, terminal_field: terminalField } = read2;
28025
+ const current = await walked;
28026
+ if (current === void 0 || current === null) return current;
28027
+ const table = tableAfter(path[at2], read2.table, carried, ctx);
28028
+ return walkPath(path, coerce, ctx, anchor, at2 + 1, current, table, field, terminalField);
28029
+ }
28030
+ function tableAfter(segment, table, carried, ctx) {
28031
+ const advanced = advanceTable(segment, table, ctx);
28032
+ return carried?.at === "data" && isKeyNamed(segment, "data") ? carried.table : advanced;
28033
+ }
27956
28034
  function isScalarWrappedField(field) {
27957
28035
  if (field.type === "formula") return field.formula.options !== void 0;
27958
28036
  return (field.type === "select" || field.type === "select_member") && field.multi !== true;
@@ -28058,7 +28136,7 @@ function advanceTable(segment, currentTable, ctx) {
28058
28136
  function findField(table, fieldKey) {
28059
28137
  return table.fields.find((f) => f.key === fieldKey);
28060
28138
  }
28061
- async function walkSegment(value, segment, ctx) {
28139
+ function walkSegment(value, segment, ctx) {
28062
28140
  switch (segment.at) {
28063
28141
  case "key":
28064
28142
  case "field": {
@@ -28079,12 +28157,14 @@ async function walkSegment(value, segment, ctx) {
28079
28157
  case "index": {
28080
28158
  if (value === null || value === void 0) return void 0;
28081
28159
  if (Array.isArray(value) || typeof value === "string") {
28082
- const idx = typeof segment.index === "number" ? segment.index : await resolveIndexExpression(segment.index, ctx, "array index");
28083
- return value[idx];
28160
+ if (typeof segment.index === "number") return value[segment.index];
28161
+ const idx = resolveIndexExpression(segment.index, ctx, "array index");
28162
+ return idx instanceof Promise ? idx.then((at2) => value[at2]) : value[idx];
28084
28163
  }
28085
28164
  if (typeof value === "object") {
28086
- const key = typeof segment.index === "number" ? String(segment.index) : await resolveObjectKeyExpression(segment.index, ctx);
28087
- return ownMember(value, key);
28165
+ if (typeof segment.index === "number") return ownMember(value, String(segment.index));
28166
+ const key = resolveObjectKeyExpression(segment.index, ctx);
28167
+ return key instanceof Promise ? key.then((named) => ownMember(value, named)) : ownMember(value, key);
28088
28168
  }
28089
28169
  throw new WorkflowEvalError(
28090
28170
  `Cannot index ${typeof value} \u2014 only an array or an object can be read by index.`,
@@ -28095,8 +28175,11 @@ async function walkSegment(value, segment, ctx) {
28095
28175
  return walkLinked(value, segment, ctx);
28096
28176
  }
28097
28177
  }
28098
- async function resolveObjectKeyExpression(expr2, ctx) {
28099
- const value = await evaluateExpression(expr2, ctx);
28178
+ function resolveObjectKeyExpression(expr2, ctx) {
28179
+ const value = evaluateExpression(expr2, ctx);
28180
+ return value instanceof Promise ? value.then(objectKey) : objectKey(value);
28181
+ }
28182
+ function objectKey(value) {
28100
28183
  if (typeof value === "string") return value;
28101
28184
  if (typeof value === "number" && Number.isFinite(value)) return String(value);
28102
28185
  throw new WorkflowEvalError(
@@ -28108,8 +28191,11 @@ async function resolveObjectKeyExpression(expr2, ctx) {
28108
28191
  );
28109
28192
  }
28110
28193
  var VALUE_PREVIEW_LENGTH = 120;
28111
- async function resolveIndexExpression(expr2, ctx, context) {
28112
- const value = await evaluateExpression(expr2, ctx);
28194
+ function resolveIndexExpression(expr2, ctx, context) {
28195
+ const value = evaluateExpression(expr2, ctx);
28196
+ return value instanceof Promise ? value.then((settled) => arrayIndex(settled, context)) : arrayIndex(value, context);
28197
+ }
28198
+ function arrayIndex(value, context) {
28113
28199
  if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
28114
28200
  throw new WorkflowEvalError(
28115
28201
  `Computed ${context} must evaluate to a non-negative integer, got ${describeValue(value)}`,
@@ -28181,46 +28267,77 @@ async function fetchRecordsBounded(ids, reading, ctx) {
28181
28267
  }
28182
28268
  return results;
28183
28269
  }
28184
- async function evaluateCall(fn, args, ctx) {
28270
+ function evaluateCall(fn, args, ctx) {
28271
+ const pause = checkClock(ctx);
28272
+ if (pause !== null) return pause.then(() => evaluateCall(fn, args, ctx));
28273
+ const helper = resolveHelper(fn, ctx);
28274
+ const values2 = [];
28275
+ let pending = false;
28276
+ try {
28277
+ for (const arg of args) {
28278
+ const value = arg.kind === "lambda" ? evaluateLambda(arg.params, arg.body, ctx, callbackItemFrames(fn, args, arg.params, ctx.anchor_context)) : evaluateExpression(arg, ctx);
28279
+ if (value instanceof Promise) pending = true;
28280
+ values2.push(value);
28281
+ }
28282
+ } catch (error51) {
28283
+ return failBeside(error51, values2);
28284
+ }
28285
+ return pending ? callAfter(helper, values2, ctx) : callHelper(helper, values2, ctx);
28286
+ }
28287
+ function resolveHelper(fn, ctx) {
28288
+ const known = ctx.evaluation_budget.helpers.get(fn);
28289
+ if (known !== void 0) return known;
28185
28290
  if (!Object.prototype.hasOwnProperty.call(ctx.helpers, fn)) {
28186
28291
  throw new WorkflowEvalError(`Unknown helper function "${fn}"`, {
28187
28292
  kind: "call",
28188
28293
  extra: { fn }
28189
28294
  });
28190
28295
  }
28191
- const helper = ctx.helpers[fn];
28192
- const anchors = args.some((arg) => arg.kind === "lambda") ? evalAnchorContext(ctx) : null;
28193
- const evaluatedArgs = await Promise.all(
28194
- args.map(
28195
- (arg) => arg.kind === "lambda" && anchors !== null ? evaluateLambda(arg.params, arg.body, ctx, callbackItemFrames(fn, args, arg.params, anchors)) : evaluateExpression(arg, ctx)
28196
- )
28197
- );
28296
+ const resolved = { call: ctx.helpers[fn], cost: helperCost(fn) };
28297
+ ctx.evaluation_budget.helpers.set(fn, resolved);
28298
+ return resolved;
28299
+ }
28300
+ async function callAfter(helper, pending, ctx) {
28301
+ const values2 = await Promise.all(pending);
28198
28302
  for (let pause = checkClock(ctx); pause !== null; pause = checkClock(ctx)) await pause;
28199
- const cost = helperCost(fn);
28200
- if (cost === "parses") charge(ctx, parsedSize(evaluatedArgs[0]));
28201
- const answer = await helper(...evaluatedArgs);
28303
+ return callHelper(helper, values2, ctx);
28304
+ }
28305
+ function callHelper({ call, cost }, values2, ctx) {
28306
+ if (cost === "parses") charge(ctx, parsedSize(values2[0]));
28307
+ const answer = Reflect.apply(call, void 0, values2);
28308
+ return answer instanceof Promise ? chargeAnswerAfter(cost, answer, values2, ctx) : chargeAnswer(cost, answer, values2, ctx);
28309
+ }
28310
+ async function chargeAnswerAfter(cost, answer, values2, ctx) {
28311
+ return chargeAnswer(cost, await answer, values2, ctx);
28312
+ }
28313
+ function chargeAnswer(cost, answer, values2, ctx) {
28202
28314
  if (cost !== "builds" && cost !== "nested") return answer;
28203
- const handedBack = evaluatedArgs.indexOf(answer);
28204
- if (handedBack !== -1) return evaluatedArgs[handedBack];
28205
- charge(ctx, builtSize(answer) + (cost === "nested" ? builtSize(evaluatedArgs[0]) : 0));
28315
+ const handedBack = values2.indexOf(answer);
28316
+ if (handedBack !== -1) return values2[handedBack];
28317
+ charge(ctx, builtSize(answer) + (cost === "nested" ? builtSize(values2[0]) : 0));
28206
28318
  return answer;
28207
28319
  }
28208
- async function evaluateBinary(op, leftExpr, rightExpr, ctx) {
28209
- if (op === "and") {
28210
- const left2 = await evaluateExpression(leftExpr, ctx);
28211
- if (!left2) return left2;
28212
- return evaluateExpression(rightExpr, ctx);
28213
- }
28214
- if (op === "or") {
28215
- const left2 = await evaluateExpression(leftExpr, ctx);
28216
- if (left2) return left2;
28217
- return evaluateExpression(rightExpr, ctx);
28218
- }
28219
- const [left, right] = await Promise.all([
28220
- evaluateExpression(leftExpr, ctx),
28221
- evaluateExpression(rightExpr, ctx)
28222
- ]);
28320
+ function evaluateBinary(op, leftExpr, rightExpr, ctx) {
28321
+ if (op === "and" || op === "or") {
28322
+ const first2 = evaluateExpression(leftExpr, ctx);
28323
+ return first2 instanceof Promise ? shortCircuitAfter(first2, op, rightExpr, ctx) : shortCircuit(op, first2, rightExpr, ctx);
28324
+ }
28325
+ const left = evaluateExpression(leftExpr, ctx);
28326
+ const right = left instanceof Promise ? startBeside(rightExpr, ctx) : evaluateExpression(rightExpr, ctx);
28327
+ return left instanceof Promise || right instanceof Promise ? binaryAfter(op, left, right, ctx) : applyBinary(op, left, right, ctx);
28328
+ }
28329
+ function shortCircuit(op, left, rightExpr, ctx) {
28330
+ return (op === "and" ? !left : left) ? left : evaluateExpression(rightExpr, ctx);
28331
+ }
28332
+ async function shortCircuitAfter(left, op, rightExpr, ctx) {
28333
+ return shortCircuit(op, await left, rightExpr, ctx);
28334
+ }
28335
+ async function binaryAfter(op, left, right, ctx) {
28336
+ const [leftValue, rightValue] = await Promise.all([left, right]);
28223
28337
  for (let pause = checkClock(ctx); pause !== null; pause = checkClock(ctx)) await pause;
28338
+ return applyBinary(op, leftValue, rightValue, ctx);
28339
+ }
28340
+ function applyBinary(op, left, right, ctx) {
28224
28341
  switch (op) {
28225
28342
  case "eq":
28226
28343
  case "neq":
@@ -28327,8 +28444,14 @@ function describeValue(value) {
28327
28444
  }
28328
28445
  return value.length > 0 && length2 <= VALUE_PREVIEW_LENGTH ? `array ${value.join(",")}` : "array";
28329
28446
  }
28330
- async function evaluateUnary(op, argExpr, ctx) {
28331
- const value = await evaluateExpression(argExpr, ctx);
28447
+ function evaluateUnary(op, argExpr, ctx) {
28448
+ const value = evaluateExpression(argExpr, ctx);
28449
+ return value instanceof Promise ? unaryAfter(op, value) : applyUnary(op, value);
28450
+ }
28451
+ async function unaryAfter(op, value) {
28452
+ return applyUnary(op, await value);
28453
+ }
28454
+ function applyUnary(op, value) {
28332
28455
  switch (op) {
28333
28456
  case "not":
28334
28457
  return !value;
@@ -28342,11 +28465,26 @@ async function evaluateUnary(op, argExpr, ctx) {
28342
28465
  return -value;
28343
28466
  }
28344
28467
  }
28345
- async function evaluateTemplate(parts, ctx) {
28346
- const evaluated2 = await Promise.all(
28347
- parts.map((part) => part.t === "text" ? part.s : evaluateExpression(part.e, ctx))
28348
- );
28468
+ function evaluateTemplate(parts, ctx) {
28469
+ const evaluated2 = [];
28470
+ let pending = false;
28471
+ try {
28472
+ for (const part of parts) {
28473
+ const value = part.t === "text" ? part.s : evaluateExpression(part.e, ctx);
28474
+ if (value instanceof Promise) pending = true;
28475
+ evaluated2.push(value);
28476
+ }
28477
+ } catch (error51) {
28478
+ return failBeside(error51, evaluated2);
28479
+ }
28480
+ return pending ? templateAfter(evaluated2, ctx) : writeTemplate(evaluated2, ctx);
28481
+ }
28482
+ async function templateAfter(pending, ctx) {
28483
+ const evaluated2 = await Promise.all(pending);
28349
28484
  for (let pause = checkClock(ctx); pause !== null; pause = checkClock(ctx)) await pause;
28485
+ return writeTemplate(evaluated2, ctx);
28486
+ }
28487
+ function writeTemplate(evaluated2, ctx) {
28350
28488
  assertCheap(ctx.evaluation_budget, ...evaluated2);
28351
28489
  assertTextWithin("template", ...evaluated2);
28352
28490
  const text2 = evaluated2.map(stringifyForTemplate).join("");
package/docs/queries.md CHANGED
@@ -142,7 +142,7 @@ Delivery-layer enrichment (applied to the response, per request):
142
142
  (`readSelect(cell).map((o) => o.key)`) against any alias that projects the underlying field
143
143
  DIRECTLY.
144
144
  - **`number` columns** arrive as JS numbers (Postgres `numeric` strings are coerced; a
145
- high-precision decimal that would lose digits stays a string). **`date`/`datetime`** columns
145
+ decimal with more digits than a double holds rounds to the double). **`date`/`datetime`** columns
146
146
  arrive as canonical wall-clock strings (`YYYY-MM-DD` / `YYYY-MM-DDTHH:mm`).
147
147
 
148
148
  ### System columns
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/app-sdk",
3
- "version": "0.121.0",
3
+ "version": "0.122.1",
4
4
  "description": "The SDK a Lotics custom-code app reads and writes through — typed hooks over the host bridge, cell readers, mount() and AppRouter",
5
5
  "type": "module",
6
6
  "exports": {