@nodegx/preview 0.2.7 → 0.2.9

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.
@@ -4936,7 +4936,7 @@ var require_lib3 = __commonJS({
4936
4936
  return this.resolve([]);
4937
4937
  }
4938
4938
  var values2 = new Array(len);
4939
- var resolved2 = 0;
4939
+ var resolved3 = 0;
4940
4940
  var i2 = -1;
4941
4941
  var promise = new this(INTERNAL);
4942
4942
  while (++i2 < len) {
@@ -4952,7 +4952,7 @@ var require_lib3 = __commonJS({
4952
4952
  });
4953
4953
  function resolveFromAll(outValue) {
4954
4954
  values2[i3] = outValue;
4955
- if (++resolved2 === len && !called) {
4955
+ if (++resolved3 === len && !called) {
4956
4956
  called = true;
4957
4957
  handlers.resolve(promise, values2);
4958
4958
  }
@@ -6222,15 +6222,15 @@ var require_crc32 = __commonJS({
6222
6222
  "use strict";
6223
6223
  var utils = require_utils3();
6224
6224
  function makeTable() {
6225
- var c, table = [];
6225
+ var c, table2 = [];
6226
6226
  for (var n = 0; n < 256; n++) {
6227
6227
  c = n;
6228
6228
  for (var k = 0; k < 8; k++) {
6229
6229
  c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
6230
6230
  }
6231
- table[n] = c;
6231
+ table2[n] = c;
6232
6232
  }
6233
- return table;
6233
+ return table2;
6234
6234
  }
6235
6235
  var crcTable = makeTable();
6236
6236
  function crc32(crc, buf, len, pos) {
@@ -7228,15 +7228,15 @@ var require_crc322 = __commonJS({
7228
7228
  "../../node_modules/pako/lib/zlib/crc32.js"(exports2, module2) {
7229
7229
  "use strict";
7230
7230
  function makeTable() {
7231
- var c, table = [];
7231
+ var c, table2 = [];
7232
7232
  for (var n = 0; n < 256; n++) {
7233
7233
  c = n;
7234
7234
  for (var k = 0; k < 8; k++) {
7235
7235
  c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
7236
7236
  }
7237
- table[n] = c;
7237
+ table2[n] = c;
7238
7238
  }
7239
- return table;
7239
+ return table2;
7240
7240
  }
7241
7241
  var crcTable = makeTable();
7242
7242
  function crc32(crc, buf, len, pos) {
@@ -9030,7 +9030,7 @@ var require_inftrees = __commonJS({
9030
9030
  64,
9031
9031
  64
9032
9032
  ];
9033
- module2.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) {
9033
+ module2.exports = function inflate_table(type, lens, lens_index, codes, table2, table_index, work, opts) {
9034
9034
  var bits = opts.bits;
9035
9035
  var len = 0;
9036
9036
  var sym = 0;
@@ -9070,8 +9070,8 @@ var require_inftrees = __commonJS({
9070
9070
  root2 = max2;
9071
9071
  }
9072
9072
  if (max2 === 0) {
9073
- table[table_index++] = 1 << 24 | 64 << 16 | 0;
9074
- table[table_index++] = 1 << 24 | 64 << 16 | 0;
9073
+ table2[table_index++] = 1 << 24 | 64 << 16 | 0;
9074
+ table2[table_index++] = 1 << 24 | 64 << 16 | 0;
9075
9075
  opts.bits = 1;
9076
9076
  return 0;
9077
9077
  }
@@ -9146,7 +9146,7 @@ var require_inftrees = __commonJS({
9146
9146
  min2 = fill;
9147
9147
  do {
9148
9148
  fill -= incr;
9149
- table[next + (huff >> drop2) + fill] = here_bits << 24 | here_op << 16 | here_val | 0;
9149
+ table2[next + (huff >> drop2) + fill] = here_bits << 24 | here_op << 16 | here_val | 0;
9150
9150
  } while (fill !== 0);
9151
9151
  incr = 1 << len - 1;
9152
9152
  while (huff & incr) {
@@ -9185,11 +9185,11 @@ var require_inftrees = __commonJS({
9185
9185
  return 1;
9186
9186
  }
9187
9187
  low = huff & mask;
9188
- table[low] = root2 << 24 | curr << 16 | next - table_index | 0;
9188
+ table2[low] = root2 << 24 | curr << 16 | next - table_index | 0;
9189
9189
  }
9190
9190
  }
9191
9191
  if (huff !== 0) {
9192
- table[next + huff] = len - drop2 << 24 | 64 << 16 | 0;
9192
+ table2[next + huff] = len - drop2 << 24 | 64 << 16 | 0;
9193
9193
  }
9194
9194
  opts.bits = root2;
9195
9195
  return 0;
@@ -9236,7 +9236,7 @@ var require_inflate = __commonJS({
9236
9236
  var STORED = 14;
9237
9237
  var COPY_ = 15;
9238
9238
  var COPY = 16;
9239
- var TABLE2 = 17;
9239
+ var TABLE3 = 17;
9240
9240
  var LENLENS = 18;
9241
9241
  var CODELENS = 19;
9242
9242
  var LEN_ = 20;
@@ -9824,7 +9824,7 @@ var require_inflate = __commonJS({
9824
9824
  }
9825
9825
  break;
9826
9826
  case 2:
9827
- state2.mode = TABLE2;
9827
+ state2.mode = TABLE3;
9828
9828
  break;
9829
9829
  case 3:
9830
9830
  strm.msg = "invalid block type";
@@ -9882,7 +9882,7 @@ var require_inflate = __commonJS({
9882
9882
  }
9883
9883
  state2.mode = TYPE;
9884
9884
  break;
9885
- case TABLE2:
9885
+ case TABLE3:
9886
9886
  while (bits < 14) {
9887
9887
  if (have === 0) {
9888
9888
  break inf_leave;
@@ -13786,7 +13786,7 @@ var require_common2 = __commonJS({
13786
13786
  exports2.ownProp = ownProp;
13787
13787
  exports2.makeAbs = makeAbs;
13788
13788
  exports2.finish = finish2;
13789
- exports2.mark = mark;
13789
+ exports2.mark = mark2;
13790
13790
  exports2.isIgnored = isIgnored;
13791
13791
  exports2.childrenIgnored = childrenIgnored;
13792
13792
  function ownProp(obj, field) {
@@ -13922,7 +13922,7 @@ var require_common2 = __commonJS({
13922
13922
  });
13923
13923
  self2.found = all;
13924
13924
  }
13925
- function mark(self2, p) {
13925
+ function mark2(self2, p) {
13926
13926
  var abs = makeAbs(self2, p);
13927
13927
  var c = self2.cache[abs];
13928
13928
  var m = p;
@@ -18973,8 +18973,21 @@ var require_node2 = __commonJS({
18973
18973
  const scope = this.nodeScope;
18974
18974
  const runContext = scope && scope.runContext;
18975
18975
  if (!runContext || !runContext.beginStep || !runContext.endStep) return;
18976
- const step = runContext.beginStep({ nodeId: this.id, nodeType: this.name });
18977
- if (step !== void 0 && step !== null) runContext.endStep(step, { status: "failure", code, message, detail });
18976
+ const recordValues = !!runContext.recordValues;
18977
+ const step = runContext.beginStep({
18978
+ nodeId: this.id,
18979
+ nodeType: this.name,
18980
+ ...recordValues ? { inputs: snapshotInputValues(this) } : {}
18981
+ });
18982
+ if (step !== void 0 && step !== null) {
18983
+ runContext.endStep(step, {
18984
+ status: "failure",
18985
+ code,
18986
+ message,
18987
+ detail,
18988
+ ...recordValues ? { outputs: snapshotOutputValues(this) } : {}
18989
+ });
18990
+ }
18978
18991
  };
18979
18992
  Node17.prototype.setDiagnostic = function(key, message) {
18980
18993
  setDiagnostic(this, key, message);
@@ -18984,6 +18997,47 @@ var require_node2 = __commonJS({
18984
18997
  return diagnosticsEnabled(this);
18985
18998
  }
18986
18999
  });
19000
+ function isSignalPortType(type) {
19001
+ if (type === "signal") return true;
19002
+ return !!type && typeof type === "object" && type.name === "signal";
19003
+ }
19004
+ function snapshotInputValues(node) {
19005
+ const out = {};
19006
+ const values2 = node._inputValues || {};
19007
+ const inputs = node._inputs || {};
19008
+ let declared2 = {};
19009
+ try {
19010
+ const register = node.context && node.context.nodeRegister;
19011
+ if (register && register.hasNode(node.name)) declared2 = register.getNodeMetadata(node.name).inputs || {};
19012
+ } catch (e) {
19013
+ }
19014
+ for (const name2 of Object.keys(values2)) {
19015
+ const value2 = values2[name2];
19016
+ if (value2 === void 0 || typeof value2 === "function") continue;
19017
+ const port = inputs[name2];
19018
+ if (port && isSignalPortType(port.type)) continue;
19019
+ const meta = declared2[name2];
19020
+ if (meta && isSignalPortType(meta.type)) continue;
19021
+ out[name2] = value2;
19022
+ }
19023
+ return out;
19024
+ }
19025
+ function snapshotOutputValues(node) {
19026
+ const out = {};
19027
+ const list = node._outputList || [];
19028
+ for (const port of list) {
19029
+ if (!port || isSignalPortType(port.type)) continue;
19030
+ let value2;
19031
+ try {
19032
+ value2 = port.value;
19033
+ } catch (e) {
19034
+ continue;
19035
+ }
19036
+ if (value2 === void 0 || typeof value2 === "function") continue;
19037
+ out[port.name] = value2;
19038
+ }
19039
+ return out;
19040
+ }
18987
19041
  Node17.prototype.beginOutcome = function(inputData) {
18988
19042
  const token = { reported: void 0 };
18989
19043
  const cause = currentTraceCause(this.context);
@@ -18991,7 +19045,13 @@ var require_node2 = __commonJS({
18991
19045
  const scope = this.nodeScope;
18992
19046
  const runContext = scope && scope.runContext;
18993
19047
  if (runContext && runContext.beginStep) {
18994
- token.step = runContext.beginStep({ nodeId: this.id, nodeType: this.name, inputData });
19048
+ token.step = runContext.beginStep({
19049
+ nodeId: this.id,
19050
+ nodeType: this.name,
19051
+ inputData,
19052
+ // P123-STU-FNRUNVALUES — opt-in; absent, the step object is exactly what it always was.
19053
+ ...runContext.recordValues ? { inputs: snapshotInputValues(this) } : {}
19054
+ });
18995
19055
  }
18996
19056
  return token;
18997
19057
  };
@@ -19070,7 +19130,10 @@ var require_node2 = __commonJS({
19070
19130
  message: options && options.message,
19071
19131
  // The subject of the failure, for a record whose steps are all called `http`. See
19072
19132
  // `RuntimeStepEnd.detail` — the node already composes this for the error bus.
19073
- detail: options && options.detail
19133
+ detail: options && options.detail,
19134
+ // P123-STU-FNRUNVALUES — read now, after the signals: "the outcome is the last thing an
19135
+ // action does", so every value it produced is already on its ports.
19136
+ ...runContext.recordValues ? { outputs: snapshotOutputValues(this) } : {}
19074
19137
  });
19075
19138
  }
19076
19139
  }
@@ -19380,10 +19443,10 @@ var require_nodescope = __commonJS({
19380
19443
  } else {
19381
19444
  const parameters = nodeModel.parameters;
19382
19445
  var inputNames = Object.keys(parameters);
19383
- const RUN_ON_CHANGE_PREFIX4 = "runOnChange-";
19446
+ const RUN_ON_CHANGE_PREFIX5 = "runOnChange-";
19384
19447
  const metadata = this.context.nodeRegister.hasNode(node.name) ? this.context.nodeRegister.getNodeMetadata(node.name) : void 0;
19385
19448
  const priorityOf = function(name2) {
19386
- if (name2.indexOf(RUN_ON_CHANGE_PREFIX4) === 0) return Number.MAX_SAFE_INTEGER;
19449
+ if (name2.indexOf(RUN_ON_CHANGE_PREFIX5) === 0) return Number.MAX_SAFE_INTEGER;
19387
19450
  const input2 = metadata ? metadata.inputs[name2] : void 0;
19388
19451
  return input2 ? input2.inputPriority : 0;
19389
19452
  };
@@ -21345,11 +21408,11 @@ var require_editorconnection = __commonJS({
21345
21408
  });
21346
21409
  };
21347
21410
  var serviceRequests = {};
21348
- EditorConnection.prototype.sendServiceRequest = function(request, callback) {
21349
- request.token = guid4();
21350
- request.clientId = this.clientId;
21351
- serviceRequests[request.token] = callback;
21352
- this.send(request);
21411
+ EditorConnection.prototype.sendServiceRequest = function(request2, callback) {
21412
+ request2.token = guid4();
21413
+ request2.clientId = this.clientId;
21414
+ serviceRequests[request2.token] = callback;
21415
+ this.send(request2);
21353
21416
  };
21354
21417
  EditorConnection.prototype.close = function() {
21355
21418
  this.reconnectOnClose = false;
@@ -23328,7 +23391,10 @@ var require_nodedefinition = __commonJS({
23328
23391
  node.registerOutput(name2, {
23329
23392
  getter: function() {
23330
23393
  return void 0;
23331
- }
23394
+ },
23395
+ onFirstConnectionAdded: output.onFirstConnectionAdded,
23396
+ onLastConnectionRemoved: output.onLastConnectionRemoved
23397
+ // a signal keeps its wire hooks (P121-TWO003)
23332
23398
  });
23333
23399
  } else {
23334
23400
  node.registerOutput(name2, output);
@@ -24601,9 +24667,704 @@ var require_runtasks = __commonJS({
24601
24667
  }
24602
24668
  });
24603
24669
 
24670
+ // ../noodl-runtime/src/utils.ts
24671
+ var utils_exports = {};
24672
+ __export(utils_exports, {
24673
+ getAbsoluteUrl: () => getAbsoluteUrl,
24674
+ logJavaScriptNodeError: () => logJavaScriptNodeError,
24675
+ thrownMessage: () => thrownMessage
24676
+ });
24677
+ function getAbsoluteUrl(_url) {
24678
+ const url = String(_url);
24679
+ if (!url || url[0] === "/" || url.includes("://") || url.startsWith("data:")) {
24680
+ return url;
24681
+ }
24682
+ return (Noodl.baseUrl || "/") + url;
24683
+ }
24684
+ function thrownMessage(error) {
24685
+ if (error && error.message) return String(error.message);
24686
+ try {
24687
+ return String(error);
24688
+ } catch {
24689
+ return typeof error;
24690
+ }
24691
+ }
24692
+ function logJavaScriptNodeError(error) {
24693
+ const prefix = "Error in JS node run code.";
24694
+ if (error === null || typeof error !== "object" && typeof error !== "function") {
24695
+ console.log(prefix, thrownMessage(error));
24696
+ return;
24697
+ }
24698
+ const proto = Object.getPrototypeOf(error);
24699
+ const kind = proto && proto.constructor && proto.constructor.name ? proto.constructor.name : "Error";
24700
+ console.log(prefix, kind + ": " + thrownMessage(error), error.stack);
24701
+ }
24702
+ var init_utils = __esm({
24703
+ "../noodl-runtime/src/utils.ts"() {
24704
+ }
24705
+ });
24706
+
24707
+ // ../noodl-runtime/src/componentwalk.ts
24708
+ var componentwalk_exports = {};
24709
+ __export(componentwalk_exports, {
24710
+ COMPONENT_OBJECT_TYPES: () => COMPONENT_OBJECT_TYPES,
24711
+ componentAncestorNames: () => componentAncestorNames,
24712
+ componentAncestors: () => componentAncestors,
24713
+ findAncestorWithComponentObject: () => findAncestorWithComponentObject,
24714
+ findAncestorWithName: () => findAncestorWithName,
24715
+ findAncestorWithNodeType: () => findAncestorWithNodeType,
24716
+ findAncestorWithProperty: () => findAncestorWithProperty,
24717
+ findComponentAncestor: () => findComponentAncestor,
24718
+ parentComponentOf: () => parentComponentOf,
24719
+ scopeChain: () => scopeChain,
24720
+ scopeChainNames: () => scopeChainNames
24721
+ });
24722
+ function parentComponentOf(component) {
24723
+ if (!component) return void 0;
24724
+ let parent;
24725
+ if (component.getRoots().length > 0) {
24726
+ const root2 = component.getRoots()[0];
24727
+ if (root2.getVisualParentNode) {
24728
+ const visualParent = root2.getVisualParentNode();
24729
+ if (visualParent) {
24730
+ parent = visualParent.nodeScope.componentOwner;
24731
+ }
24732
+ } else if (root2.parentNodeScope) {
24733
+ parent = component.parentNodeScope.componentOwner;
24734
+ }
24735
+ } else if (component.parentNodeScope) {
24736
+ parent = component.parentNodeScope.componentOwner;
24737
+ }
24738
+ if (parent && parent.nodeScope && parent.nodeScope.componentOwner !== component) {
24739
+ return parent;
24740
+ }
24741
+ return void 0;
24742
+ }
24743
+ function componentAncestors(component) {
24744
+ const ancestors = [];
24745
+ let current = component;
24746
+ for (let depth = 0; depth < MAX_WALK_DEPTH; depth++) {
24747
+ const parent = parentComponentOf(current);
24748
+ if (!parent) break;
24749
+ ancestors.push(parent);
24750
+ current = parent;
24751
+ }
24752
+ return ancestors;
24753
+ }
24754
+ function findComponentAncestor(component, predicate) {
24755
+ let current = component;
24756
+ for (let depth = 0; depth < MAX_WALK_DEPTH; depth++) {
24757
+ const parent = parentComponentOf(current);
24758
+ if (!parent) return void 0;
24759
+ if (predicate(parent)) return parent;
24760
+ current = parent;
24761
+ }
24762
+ return void 0;
24763
+ }
24764
+ function findAncestorWithNodeType(component, types) {
24765
+ return findComponentAncestor(
24766
+ component,
24767
+ (candidate) => types.some((type) => candidate.nodeScope.getNodesWithType(type).length > 0)
24768
+ );
24769
+ }
24770
+ function findAncestorWithComponentObject(component) {
24771
+ return findAncestorWithNodeType(component, COMPONENT_OBJECT_TYPES);
24772
+ }
24773
+ function findAncestorWithName(component, name2) {
24774
+ return findComponentAncestor(component, (candidate) => candidate.name === name2);
24775
+ }
24776
+ function scopeChain(component) {
24777
+ const chain2 = [];
24778
+ let current = component;
24779
+ for (let depth = 0; depth < MAX_WALK_DEPTH; depth++) {
24780
+ if (!current) break;
24781
+ chain2.push(current);
24782
+ if (!current.parentNodeScope) break;
24783
+ current = current.parentNodeScope.componentOwner;
24784
+ }
24785
+ return chain2;
24786
+ }
24787
+ function scopeChainNames(component) {
24788
+ return scopeChain(component).map((entry) => entry.name);
24789
+ }
24790
+ function findAncestorWithProperty(component, property2) {
24791
+ const chain2 = scopeChain(component);
24792
+ for (let i2 = 0; i2 < chain2.length; i2++) {
24793
+ if (chain2[i2][property2] !== void 0) return chain2[i2];
24794
+ }
24795
+ return void 0;
24796
+ }
24797
+ function componentAncestorNames(component) {
24798
+ return componentAncestors(component).map((ancestor) => ancestor.name);
24799
+ }
24800
+ var MAX_WALK_DEPTH, COMPONENT_OBJECT_TYPES;
24801
+ var init_componentwalk = __esm({
24802
+ "../noodl-runtime/src/componentwalk.ts"() {
24803
+ "use strict";
24804
+ MAX_WALK_DEPTH = 1e3;
24805
+ COMPONENT_OBJECT_TYPES = ["net.noodl.ComponentObject", "Component State"];
24806
+ }
24807
+ });
24808
+
24809
+ // ../noodl-runtime/src/resolvedtarget.ts
24810
+ function summariseTargets(labels) {
24811
+ const distinct = [];
24812
+ for (let i2 = 0; i2 < labels.length; i2++) {
24813
+ const label = labels[i2];
24814
+ if (label === void 0) continue;
24815
+ if (distinct.indexOf(label) === -1) distinct.push(label);
24816
+ }
24817
+ if (distinct.length === 0) return void 0;
24818
+ if (distinct.length === 1) return "\u2192 " + distinct[0];
24819
+ const listed = distinct.slice(0, MAX_NAMES_LISTED).join(", ");
24820
+ const rest2 = distinct.length - MAX_NAMES_LISTED;
24821
+ return "\u2192 " + distinct.length + " targets: " + listed + (rest2 > 0 ? ", +" + rest2 : "");
24822
+ }
24823
+ var MAX_NAMES_LISTED, ResolvedTargetReporter;
24824
+ var init_resolvedtarget = __esm({
24825
+ "../noodl-runtime/src/resolvedtarget.ts"() {
24826
+ "use strict";
24827
+ MAX_NAMES_LISTED = 3;
24828
+ ResolvedTargetReporter = class {
24829
+ constructor() {
24830
+ /** Weak, so a torn-down runtime's bookkeeping goes with it and needs no reset call. */
24831
+ this._byContext = /* @__PURE__ */ new WeakMap();
24832
+ }
24833
+ /**
24834
+ * Record what `node` bound to and push the summary to the editor.
24835
+ *
24836
+ * Safe to call every resolution; identical summaries are dropped rather than sent, so a
24837
+ * node that re-resolves each frame costs one string comparison.
24838
+ */
24839
+ report(node, target) {
24840
+ const state2 = this._stateFor(node);
24841
+ if (!state2) return;
24842
+ let instances = state2.byGraphNode.get(node.id);
24843
+ if (!instances) {
24844
+ instances = /* @__PURE__ */ new Map();
24845
+ state2.byGraphNode.set(node.id, instances);
24846
+ }
24847
+ instances.set(node, target);
24848
+ this._flush(node, state2, instances);
24849
+ }
24850
+ /** Drop an instance. Call from `_onNodeDeleted`, or this map is a leak. */
24851
+ forget(node) {
24852
+ const state2 = this._stateFor(node);
24853
+ if (!state2) return;
24854
+ const instances = state2.byGraphNode.get(node.id);
24855
+ if (!instances) return;
24856
+ instances.delete(node);
24857
+ if (instances.size === 0) {
24858
+ state2.byGraphNode.delete(node.id);
24859
+ state2.lastSent.delete(node.id);
24860
+ return;
24861
+ }
24862
+ this._flush(node, state2, instances);
24863
+ }
24864
+ _stateFor(node) {
24865
+ const context = node.context;
24866
+ if (!context) return void 0;
24867
+ let state2 = this._byContext.get(context);
24868
+ if (!state2) {
24869
+ state2 = { byGraphNode: /* @__PURE__ */ new Map(), lastSent: /* @__PURE__ */ new Map() };
24870
+ this._byContext.set(context, state2);
24871
+ }
24872
+ return state2;
24873
+ }
24874
+ _flush(node, state2, instances) {
24875
+ const labels = [];
24876
+ instances.forEach((label) => labels.push(label));
24877
+ const summary = summariseTargets(labels);
24878
+ if (state2.lastSent.has(node.id) && state2.lastSent.get(node.id) === summary) return;
24879
+ state2.lastSent.set(node.id, summary);
24880
+ const editorConnection = node.context && node.context.editorConnection;
24881
+ if (!editorConnection || !editorConnection.isRunningLocally()) return;
24882
+ if (typeof editorConnection.sendNodeSubLabel !== "function") return;
24883
+ editorConnection.sendNodeSubLabel(node.id, summary);
24884
+ }
24885
+ };
24886
+ }
24887
+ });
24888
+
24889
+ // ../noodl-runtime/src/foreachitem.ts
24890
+ var foreachitem_exports = {};
24891
+ __export(foreachitem_exports, {
24892
+ forgetForEachItem: () => forgetForEachItem,
24893
+ resolveForEachItem: () => resolveForEachItem
24894
+ });
24895
+ function resolveForEachItem(node, options = {}) {
24896
+ const chain2 = scopeChain(node.nodeScope.componentOwner);
24897
+ const wanted = options.target;
24898
+ if (wanted) {
24899
+ const named3 = firstNamed(chain2, wanted);
24900
+ if (!named3) {
24901
+ return miss(
24902
+ node,
24903
+ "repeater-item/target-not-found",
24904
+ 'No component named "' + wanted + '" contains this node',
24905
+ wanted,
24906
+ { target: wanted, scope: scopeChainNames(node.nodeScope.componentOwner) }
24907
+ );
24908
+ }
24909
+ if (named3[FOR_EACH_MODEL] === void 0) {
24910
+ return miss(
24911
+ node,
24912
+ "repeater-item/target-has-no-item",
24913
+ 'The component "' + wanted + '" has no current item \u2014 it is not used as a Repeater or Run Tasks template',
24914
+ wanted,
24915
+ { target: wanted }
24916
+ );
24917
+ }
24918
+ return hit(node, named3);
24919
+ }
24920
+ const owner = firstWithItem(chain2);
24921
+ if (!owner) {
24922
+ return miss(
24923
+ node,
24924
+ "repeater-item/no-item-in-scope",
24925
+ 'Id Source is set to "From repeater", but this node is not inside a Repeater or Run Tasks template',
24926
+ void 0,
24927
+ { scope: scopeChainNames(node.nodeScope.componentOwner) }
24928
+ );
24929
+ }
24930
+ return hit(node, owner);
24931
+ }
24932
+ function forgetForEachItem(node) {
24933
+ resolvedTargets.forget(node);
24934
+ lastMissByNode.delete(node);
24935
+ }
24936
+ function firstNamed(chain2, name2) {
24937
+ for (let i2 = 0; i2 < chain2.length; i2++) {
24938
+ if (chain2[i2].name === name2) return chain2[i2];
24939
+ }
24940
+ return void 0;
24941
+ }
24942
+ function firstWithItem(chain2) {
24943
+ for (let i2 = 0; i2 < chain2.length; i2++) {
24944
+ if (chain2[i2][FOR_EACH_MODEL] !== void 0) return chain2[i2];
24945
+ }
24946
+ return void 0;
24947
+ }
24948
+ function hit(node, owner) {
24949
+ lastMissByNode.delete(node);
24950
+ resolvedTargets.report(node, owner.name);
24951
+ return owner[FOR_EACH_MODEL];
24952
+ }
24953
+ function miss(node, code, message, target, detail) {
24954
+ resolvedTargets.report(node, void 0);
24955
+ const seen = code + "|" + (target || "");
24956
+ if (lastMissByNode.get(node) !== seen) {
24957
+ lastMissByNode.set(node, seen);
24958
+ node.raiseRuntimeError(code, message, detail);
24959
+ }
24960
+ return void 0;
24961
+ }
24962
+ var FOR_EACH_MODEL, resolvedTargets, lastMissByNode;
24963
+ var init_foreachitem = __esm({
24964
+ "../noodl-runtime/src/foreachitem.ts"() {
24965
+ "use strict";
24966
+ init_componentwalk();
24967
+ init_resolvedtarget();
24968
+ FOR_EACH_MODEL = "_forEachModel";
24969
+ resolvedTargets = new ResolvedTargetReporter();
24970
+ lastMissByNode = /* @__PURE__ */ new WeakMap();
24971
+ }
24972
+ });
24973
+
24974
+ // ../noodl-runtime/src/javascriptnodeparser.js
24975
+ var require_javascriptnodeparser = __commonJS({
24976
+ "../noodl-runtime/src/javascriptnodeparser.js"(exports2, module2) {
24977
+ "use strict";
24978
+ var Model27 = require_model2();
24979
+ var { getAbsoluteUrl: getAbsoluteUrl2 } = (init_utils(), __toCommonJS(utils_exports));
24980
+ var { findAncestorWithComponentObject: findAncestorWithComponentObject2 } = (init_componentwalk(), __toCommonJS(componentwalk_exports));
24981
+ var { resolveForEachItem: resolveForEachItem2 } = (init_foreachitem(), __toCommonJS(foreachitem_exports));
24982
+ var userFunctionsCache = {};
24983
+ function JavascriptNodeParser4(code, options) {
24984
+ this.inputs = {};
24985
+ this.outputs = {};
24986
+ this.error = void 0;
24987
+ this.code = code;
24988
+ const node = options ? options.node : void 0;
24989
+ this._initializeAPIs();
24990
+ var userCode = userFunctionsCache[code];
24991
+ if (!userCode) {
24992
+ try {
24993
+ userCode = new Function(["define", "script", "Node", "Component"], JavascriptNodeParser4.getCodePrefix() + code);
24994
+ userFunctionsCache[code] = userCode;
24995
+ } catch (e) {
24996
+ this.error = e.message;
24997
+ console.error(e);
24998
+ }
24999
+ }
25000
+ if (userCode) {
25001
+ try {
25002
+ userCode(
25003
+ this.define.bind(this),
25004
+ this.script.bind(this),
25005
+ this.apis.Node,
25006
+ node ? JavascriptNodeParser4.getComponentScopeForNode(node) : {}
25007
+ );
25008
+ this._afterSourced();
25009
+ } catch (e) {
25010
+ this.error = e.message;
25011
+ console.error(e);
25012
+ }
25013
+ }
25014
+ }
25015
+ JavascriptNodeParser4.prototype.define = function(userObject) {
25016
+ this.inputs = userObject.inputs || {};
25017
+ this.outputs = userObject.outputs || {};
25018
+ this.setup = userObject.setup;
25019
+ this.change = userObject.run || userObject.change;
25020
+ this.destroy = userObject.destroy;
25021
+ this.definedObject = userObject;
25022
+ };
25023
+ function _scriptExtend(_this) {
25024
+ var _extended = {
25025
+ inputs: _this.inputs || {},
25026
+ outputs: _this.outputs || {},
25027
+ setup: function(inputs, outputs) {
25028
+ this.inputs = inputs;
25029
+ this.outputs = outputs;
25030
+ this.setOutputs = function(states) {
25031
+ for (var key3 in states) {
25032
+ this.outputs[key3] = states[key3];
25033
+ this.flagOutputDirty(key3);
25034
+ }
25035
+ };
25036
+ if (_this.methods) {
25037
+ for (var key2 in _this.methods) {
25038
+ this[key2] = _this.methods[key2];
25039
+ }
25040
+ }
25041
+ _this.setup && _this.setup.apply(this);
25042
+ },
25043
+ destroy: function(inputs, outputs) {
25044
+ this.inputs = inputs;
25045
+ this.outputs = outputs;
25046
+ _this.destroy && _this.destroy.apply(this);
25047
+ },
25048
+ change: function(inputs, outputs) {
25049
+ this.inputs = inputs;
25050
+ this.outputs = outputs;
25051
+ var old = this._oldInputs || {};
25052
+ if (_this.changed) {
25053
+ for (var key2 in inputs) {
25054
+ if (inputs[key2] !== old[key2]) {
25055
+ var changedFunction = _this.changed[key2];
25056
+ if (typeof changedFunction === "function") changedFunction.apply(this, [inputs[key2], old[key2]]);
25057
+ }
25058
+ }
25059
+ }
25060
+ this._oldInputs = Object.assign({}, inputs);
25061
+ }
25062
+ };
25063
+ if (_this.signals) {
25064
+ for (var key in _this.signals) {
25065
+ _extended[key] = _this.signals[key];
25066
+ _extended.inputs[key] = "signal";
25067
+ }
25068
+ }
25069
+ return _extended;
25070
+ }
25071
+ JavascriptNodeParser4.prototype.script = function(userObject) {
25072
+ var _userObjectExtended = _scriptExtend(userObject);
25073
+ this.inputs = _userObjectExtended.inputs || {};
25074
+ this.outputs = _userObjectExtended.outputs || {};
25075
+ this.setup = _userObjectExtended.setup;
25076
+ this.change = _userObjectExtended.run || _userObjectExtended.change;
25077
+ this.destroy = _userObjectExtended.destroy;
25078
+ this.definedObject = _userObjectExtended;
25079
+ };
25080
+ JavascriptNodeParser4.prototype._initializeAPIs = function() {
25081
+ this.apis = {
25082
+ Node: {
25083
+ Inputs: {},
25084
+ Outputs: {},
25085
+ Signals: {},
25086
+ Setters: {}
25087
+ }
25088
+ };
25089
+ };
25090
+ JavascriptNodeParser4.prototype._afterSourced = function() {
25091
+ if (this.definedObject !== void 0) return;
25092
+ var _Node = this.apis.Node;
25093
+ this.inputs = Object.assign({}, _Node.Inputs || {});
25094
+ this.outputs = Object.assign({}, _Node.Outputs || {});
25095
+ this.setup = function(inputs, outputs) {
25096
+ const _this = this;
25097
+ _Node.setOutputs = function(_outputs) {
25098
+ for (var key2 in _outputs) {
25099
+ outputs[key2] = _outputs[key2];
25100
+ _this.flagOutputDirty(key2);
25101
+ }
25102
+ };
25103
+ _Node.OnInit && _Node.OnInit.apply(this);
25104
+ };
25105
+ this.destroy = _Node.OnDestroy || this.destory;
25106
+ this.change = (inputs, outputs, changedInputs) => {
25107
+ for (var key2 in changedInputs) {
25108
+ if (typeof _Node.Setters[key2] === "function") {
25109
+ _Node.Setters[key2](inputs[key2]);
25110
+ }
25111
+ }
25112
+ if (typeof _Node.OnInputsChanged === "function") {
25113
+ _Node.OnInputsChanged();
25114
+ }
25115
+ };
25116
+ this.definedObject = {
25117
+ inputs: this.inputs,
25118
+ outputs: this.outputs,
25119
+ setup: this.setup,
25120
+ destroy: this.destroy,
25121
+ change: this.change
25122
+ };
25123
+ if (_Node.Signals !== void 0) {
25124
+ for (var key in _Node.Signals) {
25125
+ if (typeof _Node.Signals[key] === "function") {
25126
+ this.inputs[key] = "signal";
25127
+ this.definedObject[key] = _Node.Signals[key];
25128
+ }
25129
+ }
25130
+ }
25131
+ };
25132
+ JavascriptNodeParser4.createFromCode = function(code, options) {
25133
+ return new JavascriptNodeParser4(code, options);
25134
+ };
25135
+ function failedParser(message) {
25136
+ var parser = Object.create(JavascriptNodeParser4.prototype);
25137
+ parser.inputs = {};
25138
+ parser.outputs = {};
25139
+ parser.error = message;
25140
+ parser.code = void 0;
25141
+ parser.apis = { Node: {} };
25142
+ return parser;
25143
+ }
25144
+ JavascriptNodeParser4.createFromURL = function(url, callback, options) {
25145
+ url = getAbsoluteUrl2(url);
25146
+ var settled = false;
25147
+ function settle(parser) {
25148
+ if (settled) return;
25149
+ settled = true;
25150
+ callback(parser);
25151
+ }
25152
+ var xhr = new window.XMLHttpRequest();
25153
+ xhr.open("GET", url, true);
25154
+ xhr.onreadystatechange = function() {
25155
+ if (this.readyState === 4 || this.readyState === XMLHttpRequest.DONE) {
25156
+ if (this.status !== 0 && (this.status < 200 || this.status >= 300)) {
25157
+ settle(failedParser('Could not load "' + url + '": the server answered ' + this.status));
25158
+ return;
25159
+ }
25160
+ if (this.status === 0) {
25161
+ settle(failedParser('Could not load "' + url + '": the request failed'));
25162
+ return;
25163
+ }
25164
+ settle(new JavascriptNodeParser4(this.response, options));
25165
+ }
25166
+ };
25167
+ xhr.onerror = function() {
25168
+ settle(failedParser('Could not load "' + url + '": the request failed'));
25169
+ };
25170
+ xhr.send();
25171
+ };
25172
+ JavascriptNodeParser4.parseAndAddPortsFromScript = function(script, ports, options) {
25173
+ function _exists(port) {
25174
+ if (typeof port === "string") return ports.find((p) => p.name === port) !== void 0;
25175
+ else return ports.find((p) => p.name === port.name && p.plug === port.plug) !== void 0;
25176
+ }
25177
+ function _addPortsFromMatch(match, options2) {
25178
+ if (match === void 0 || match === null) return;
25179
+ const unique = {};
25180
+ for (const _s of match) {
25181
+ let name2 = _s[1];
25182
+ if (name2 === void 0) continue;
25183
+ unique[name2] = true;
25184
+ }
25185
+ Object.keys(unique).forEach((p) => {
25186
+ if (_exists({
25187
+ name: options2.prefix + p,
25188
+ plug: options2.plug
25189
+ }))
25190
+ return;
25191
+ ports.push({
25192
+ name: options2.prefix + p,
25193
+ displayName: p,
25194
+ plug: options2.plug,
25195
+ type: options2.type,
25196
+ group: options2.group
25197
+ });
25198
+ });
25199
+ }
25200
+ if (!options.skipInputs) {
25201
+ _addPortsFromMatch(script.matchAll(/Inputs\.([A-Za-z0-9_]+)/g), {
25202
+ type: options.inputType || "*",
25203
+ plug: "input",
25204
+ group: options.inputGroup || "Inputs",
25205
+ prefix: options.inputPrefix || ""
25206
+ });
25207
+ _addPortsFromMatch(script.matchAll(/Inputs\s*\[\s*(?:'|")(.*)(?:'|")\s*\]/g), {
25208
+ type: options.inputType || "*",
25209
+ plug: "inputs",
25210
+ group: options.inputGroup || "Inputs",
25211
+ prefix: options.inputPrefix || ""
25212
+ });
25213
+ }
25214
+ if (!options.skipOutputs) {
25215
+ if (!options.skipOutputSignals) {
25216
+ _addPortsFromMatch(script.matchAll(/Outputs\.([A-Za-z0-9]+)\s*\(\s*\)/g), {
25217
+ type: "signal",
25218
+ plug: "output",
25219
+ group: "Outputs",
25220
+ prefix: options.outputPrefix || ""
25221
+ });
25222
+ _addPortsFromMatch(script.matchAll(/Outputs\s*\[\s*(?:'|")(.*)(?:'|")\s*\]\(\s*\)/g), {
25223
+ type: "signal",
25224
+ plug: "output",
25225
+ group: "Outputs",
25226
+ prefix: options.outputPrefix || ""
25227
+ });
25228
+ }
25229
+ if (!options.skipRegularOutputs) {
25230
+ _addPortsFromMatch(script.matchAll(/Outputs\.([A-Za-z0-9_]+)/g), {
25231
+ type: "*",
25232
+ plug: "output",
25233
+ group: "Outputs",
25234
+ prefix: options.outputPrefix || ""
25235
+ });
25236
+ _addPortsFromMatch(script.matchAll(/Outputs\s*\[\s*\"([^\"]*)\"\s*\]/g), {
25237
+ type: "*",
25238
+ plug: "output",
25239
+ group: "Outputs",
25240
+ prefix: options.outputPrefix || ""
25241
+ });
25242
+ }
25243
+ }
25244
+ };
25245
+ JavascriptNodeParser4.prototype.getPorts = function() {
25246
+ var ports = [];
25247
+ var self2 = this;
25248
+ Object.keys(this.inputs).forEach(function(name2) {
25249
+ var inputPort = self2.inputs[name2];
25250
+ var port = {
25251
+ name: name2,
25252
+ plug: "input"
25253
+ };
25254
+ if (typeof inputPort === "string") {
25255
+ port.type = {
25256
+ name: inputPort
25257
+ };
25258
+ port.group = "Inputs";
25259
+ } else {
25260
+ for (var p in inputPort) {
25261
+ port[p] = inputPort[p];
25262
+ }
25263
+ }
25264
+ ports.push(port);
25265
+ });
25266
+ Object.keys(this.outputs).forEach(function(name2) {
25267
+ ports.push({
25268
+ name: name2,
25269
+ type: {
25270
+ name: self2.outputs[name2]
25271
+ },
25272
+ plug: "output",
25273
+ group: "Outputs"
25274
+ });
25275
+ });
25276
+ JavascriptNodeParser4.parseAndAddPortsFromScript(this.code, ports, {});
25277
+ return ports;
25278
+ };
25279
+ var _componentScopes = {};
25280
+ function _findParentComponentStateModelId(node) {
25281
+ const parent = findAncestorWithComponentObject2(node.nodeScope.componentOwner);
25282
+ if (!parent) return;
25283
+ return "componentState" + parent.getInstanceId();
25284
+ }
25285
+ JavascriptNodeParser4.getComponentScopeForNode = function(node) {
25286
+ const componentId = node.nodeScope.componentOwner.getInstanceId();
25287
+ if (_componentScopes[componentId] === void 0) {
25288
+ _componentScopes[componentId] = {};
25289
+ const componentObject = (node.nodeScope.modelScope || Model27).get("componentState" + componentId);
25290
+ _componentScopes[componentId].Object = componentObject;
25291
+ }
25292
+ const parentComponentObjectId = _findParentComponentStateModelId(node);
25293
+ const parentComponentObject = parentComponentObjectId !== void 0 ? (node.nodeScope.modelScope || Model27).get(parentComponentObjectId) : void 0;
25294
+ _componentScopes[componentId].ParentObject = parentComponentObject;
25295
+ Object.defineProperty(_componentScopes[componentId], "RepeaterObject", {
25296
+ configurable: true,
25297
+ enumerable: true,
25298
+ get: function() {
25299
+ return resolveForEachItem2(node);
25300
+ }
25301
+ });
25302
+ return _componentScopes[componentId];
25303
+ };
25304
+ JavascriptNodeParser4.getCodePrefix = function() {
25305
+ return "const Script = (typeof Node !== 'undefined')?Node:undefined;\n";
25306
+ };
25307
+ JavascriptNodeParser4.createNoodlAPI = function() {
25308
+ return typeof window !== "undefined" && window.Noodl !== void 0 ? window.Noodl : {};
25309
+ };
25310
+ module2.exports = JavascriptNodeParser4;
25311
+ }
25312
+ });
25313
+
25314
+ // ../noodl-runtime/src/printedcode.ts
25315
+ function table() {
25316
+ return globalThis[TABLE];
25317
+ }
25318
+ function hasPrintedCode() {
25319
+ return table() !== void 0;
25320
+ }
25321
+ function sameParams(a, b) {
25322
+ return a.length === b.length && a.every((p, i2) => p === b[i2]);
25323
+ }
25324
+ function findPrintedCode(params, body, async) {
25325
+ const list = table()?.get(body);
25326
+ return list && list.find((e) => e.async === async && sameParams(e.params, params));
25327
+ }
25328
+ function findPrintedBody(body, async) {
25329
+ const list = table()?.get(body);
25330
+ return list && list.find((e) => e.async === async);
25331
+ }
25332
+ function compileCode(params, body, options) {
25333
+ const async = !!(options && options.async);
25334
+ const printed = findPrintedCode(params, body, async);
25335
+ if (printed) return printed.fn;
25336
+ if (table()?.refuseOthers) throw new Error(NOT_PRINTED_MESSAGE);
25337
+ const Ctor = async ? AsyncFunction : Function;
25338
+ return new Ctor(...params, body);
25339
+ }
25340
+ function functionNodeBody(script) {
25341
+ const JavascriptNodeParser4 = require_javascriptnodeparser();
25342
+ return JavascriptNodeParser4.getCodePrefix() + script;
25343
+ }
25344
+ function expressionNodeBody(expression) {
25345
+ return EXPRESSION_PREAMBLE + "return (" + expression + ");";
25346
+ }
25347
+ var NOT_PRINTED_MESSAGE, TABLE, AsyncFunction, FUNCTION_NODE_PARAMS, EXPRESSION_PREAMBLE, REST_REQUEST_PARAMS, REST_RESPONSE_PARAMS, MAP_COLLECTION_PARAMS;
25348
+ var init_printedcode = __esm({
25349
+ "../noodl-runtime/src/printedcode.ts"() {
25350
+ NOT_PRINTED_MESSAGE = "This code was not printed when the app was deployed, and code cannot be compiled here. Deploy the app again.";
25351
+ TABLE = Symbol.for("nodegx.printedCode");
25352
+ AsyncFunction = Object.getPrototypeOf(async function() {
25353
+ }).constructor;
25354
+ FUNCTION_NODE_PARAMS = ["Inputs", "Outputs", "Noodl", "Component", "Scripts"];
25355
+ EXPRESSION_PREAMBLE = [
25356
+ 'var min = Math.min, max = Math.max, cos = Math.cos, sin = Math.sin, tan = Math.tan, sqrt = Math.sqrt, pi = Math.PI, round = Math.round, floor = Math.floor, ceil = Math.ceil, abs = Math.abs, random = Math.random, pow = Math.pow, log = Math.log, exp = Math.exp;try { var NoodlContext = (typeof Noodl !== "undefined") ? Noodl : (typeof global !== "undefined" && global.Noodl) || {}; var Variables = NoodlContext.Variables || {}; var Objects = NoodlContext.Objects || {}; var Arrays = NoodlContext.Arrays || {};} catch (e) { var Variables = {}, Objects = {}, Arrays = {};}'
25357
+ ].join("");
25358
+ REST_REQUEST_PARAMS = ["Inputs", "Outputs", "Request"];
25359
+ REST_RESPONSE_PARAMS = ["Inputs", "Outputs", "Response"];
25360
+ MAP_COLLECTION_PARAMS = ["map", "object"];
25361
+ }
25362
+ });
25363
+
24604
25364
  // ../noodl-runtime/src/nodes/std-library/data/restnode.ts
24605
25365
  var require_restnode = __commonJS({
24606
25366
  "../noodl-runtime/src/nodes/std-library/data/restnode.ts"(exports2, module2) {
25367
+ init_printedcode();
24607
25368
  var defaultRequestScript = "//Add custom code to setup the request object before the request\n//is made.\n//\n//*Request.resource contains the resource path of the request.\n//*Request.method contains the method, GET, POST, PUT or DELETE.\n//*Request.headers is a map where you can add additional headers.\n//*Request.parameters is a map the parameters that will be appended\n// to the url.\n//*Request.content contains the content of the request as a javascript\n// object.\n//\n";
24608
25369
  var defaultResponseScript = "// Add custom code to convert the response content to outputs\n//\n//*Response.status The status code of the response\n//*Response.content The content of the response as a javascript\n// object.\n//*Response.request The request object that resulted in the response.\n//\n//*Inputs and *Outputs contain the inputs and outputs of the node.\n";
24609
25370
  var RestNode = {
@@ -24692,7 +25453,7 @@ var require_restnode = __commonJS({
24692
25453
  group: "Scripts",
24693
25454
  set: function(script) {
24694
25455
  try {
24695
- this._internal.requestFunc = new Function("Inputs", "Outputs", "Request", script);
25456
+ this._internal.requestFunc = compileCode(REST_REQUEST_PARAMS, script);
24696
25457
  } catch (e) {
24697
25458
  console.log(e);
24698
25459
  }
@@ -24709,7 +25470,7 @@ var require_restnode = __commonJS({
24709
25470
  group: "Scripts",
24710
25471
  set: function(script) {
24711
25472
  try {
24712
- this._internal.responseFunc = new Function("Inputs", "Outputs", "Response", script);
25473
+ this._internal.responseFunc = compileCode(REST_RESPONSE_PARAMS, script);
24713
25474
  } catch (e) {
24714
25475
  console.log(e);
24715
25476
  }
@@ -24781,12 +25542,12 @@ var require_restnode = __commonJS({
24781
25542
  this.scheduleAfterInputsHaveUpdated(this.doFetch.bind(this));
24782
25543
  }
24783
25544
  },
24784
- doResponse: function(status, response, request) {
25545
+ doResponse: function(status, response, request2) {
24785
25546
  if (this._internal.responseFunc) {
24786
25547
  this._internal.responseFunc.apply(this._internal.self, [
24787
25548
  this._internal.inputValues,
24788
25549
  this._internal.outputValuesProxy,
24789
- { status, content: response, request }
25550
+ { status, content: response, request: request2 }
24790
25551
  ]);
24791
25552
  }
24792
25553
  this._internal.inspectData = { status, content: response };
@@ -24796,11 +25557,11 @@ var require_restnode = __commonJS({
24796
25557
  this.sendSignalOnOutput("failure");
24797
25558
  }
24798
25559
  },
24799
- doExternalFetch: function(request) {
24800
- let url = request.resource;
24801
- if (Object.keys(request.parameters).length > 0) {
24802
- const parameters = Object.keys(request.parameters).map(function(p) {
24803
- return p + "=" + encodeURIComponent(request.parameters[p]);
25560
+ doExternalFetch: function(request2) {
25561
+ let url = request2.resource;
25562
+ if (Object.keys(request2.parameters).length > 0) {
25563
+ const parameters = Object.keys(request2.parameters).map(function(p) {
25564
+ return p + "=" + encodeURIComponent(request2.parameters[p]);
24804
25565
  });
24805
25566
  url += "?" + parameters.join("&");
24806
25567
  }
@@ -24808,9 +25569,9 @@ var require_restnode = __commonJS({
24808
25569
  const _this = this;
24809
25570
  const xhr = new window.XMLHttpRequest();
24810
25571
  this._xhr = xhr;
24811
- xhr.open(request.method, url, true);
24812
- for (const header in request.headers) {
24813
- xhr.setRequestHeader(header, request.headers[header]);
25572
+ xhr.open(request2.method, url, true);
25573
+ for (const header in request2.headers) {
25574
+ xhr.setRequestHeader(header, request2.headers[header]);
24814
25575
  }
24815
25576
  xhr.onreadystatechange = function() {
24816
25577
  let sentResponse = false;
@@ -24822,11 +25583,11 @@ var require_restnode = __commonJS({
24822
25583
  if (responseType) {
24823
25584
  responseType = responseType.toLowerCase();
24824
25585
  const responseData = responseType.indexOf("json") !== -1 ? JSON.parse(rawResponse) : rawResponse;
24825
- _this.doResponse(statusCode, responseData, request);
25586
+ _this.doResponse(statusCode, responseData, request2);
24826
25587
  sentResponse = true;
24827
25588
  }
24828
25589
  if (sentResponse === false) {
24829
- _this.doResponse(statusCode, rawResponse, request);
25590
+ _this.doResponse(statusCode, rawResponse, request2);
24830
25591
  }
24831
25592
  }
24832
25593
  };
@@ -24838,30 +25599,30 @@ var require_restnode = __commonJS({
24838
25599
  delete this._xhr;
24839
25600
  _this.sendSignalOnOutput("canceled");
24840
25601
  };
24841
- if (request.content) {
25602
+ if (request2.content) {
24842
25603
  xhr.setRequestHeader("Content-Type", "application/json");
24843
- xhr.send(JSON.stringify(request.content));
25604
+ xhr.send(JSON.stringify(request2.content));
24844
25605
  } else {
24845
25606
  xhr.send();
24846
25607
  }
24847
25608
  } else {
24848
25609
  const headers = Object.assign(
24849
25610
  {},
24850
- request.headers,
24851
- request.content ? {
25611
+ request2.headers,
25612
+ request2.content ? {
24852
25613
  "Content-Type": "application/json"
24853
25614
  } : {}
24854
25615
  );
24855
25616
  fetch(url, {
24856
- method: request.method,
25617
+ method: request2.method,
24857
25618
  headers,
24858
- body: request.content ? JSON.stringify(request.content) : void 0
25619
+ body: request2.content ? JSON.stringify(request2.content) : void 0
24859
25620
  }).then((response) => {
24860
25621
  const responseType = response.headers.get("content-type");
24861
25622
  if (responseType) {
24862
25623
  if (responseType.indexOf("/json") !== -1) {
24863
25624
  response.json().then((json) => {
24864
- this.doResponse(response.status, json, request);
25625
+ this.doResponse(response.status, json, request2);
24865
25626
  });
24866
25627
  } else {
24867
25628
  if (this.context.editorConnection) {
@@ -24877,7 +25638,7 @@ var require_restnode = __commonJS({
24877
25638
  }
24878
25639
  } else {
24879
25640
  response.text().then((raw) => {
24880
- this.doResponse(response.status, raw, request);
25641
+ this.doResponse(response.status, raw, request2);
24881
25642
  });
24882
25643
  }
24883
25644
  }).catch((e) => {
@@ -24895,7 +25656,7 @@ var require_restnode = __commonJS({
24895
25656
  resource = resource.replace("{" + key + "}", this._internal.inputValues[key]);
24896
25657
  }
24897
25658
  }
24898
- const request = {
25659
+ const request2 = {
24899
25660
  resource,
24900
25661
  headers: {},
24901
25662
  method: this._internal.method !== void 0 ? this._internal.method : "GET",
@@ -24905,10 +25666,10 @@ var require_restnode = __commonJS({
24905
25666
  this._internal.requestFunc.apply(this._internal.self, [
24906
25667
  this._internal.inputValues,
24907
25668
  this._internal.outputValuesProxy,
24908
- request
25669
+ request2
24909
25670
  ]);
24910
25671
  }
24911
- this.doExternalFetch(request);
25672
+ this.doExternalFetch(request2);
24912
25673
  },
24913
25674
  cancelFetch: function() {
24914
25675
  if (typeof _noodl_cloud_runtime_version === "undefined") {
@@ -25699,656 +26460,13 @@ var require_lodash = __commonJS({
25699
26460
  }
25700
26461
  });
25701
26462
 
25702
- // ../noodl-runtime/src/utils.ts
25703
- var utils_exports = {};
25704
- __export(utils_exports, {
25705
- getAbsoluteUrl: () => getAbsoluteUrl,
25706
- logJavaScriptNodeError: () => logJavaScriptNodeError,
25707
- thrownMessage: () => thrownMessage
25708
- });
25709
- function getAbsoluteUrl(_url) {
25710
- const url = String(_url);
25711
- if (!url || url[0] === "/" || url.includes("://") || url.startsWith("data:")) {
25712
- return url;
25713
- }
25714
- return (Noodl.baseUrl || "/") + url;
25715
- }
25716
- function thrownMessage(error) {
25717
- if (error && error.message) return String(error.message);
25718
- try {
25719
- return String(error);
25720
- } catch {
25721
- return typeof error;
25722
- }
25723
- }
25724
- function logJavaScriptNodeError(error) {
25725
- const prefix = "Error in JS node run code.";
25726
- if (error === null || typeof error !== "object" && typeof error !== "function") {
25727
- console.log(prefix, thrownMessage(error));
25728
- return;
25729
- }
25730
- const proto = Object.getPrototypeOf(error);
25731
- const kind = proto && proto.constructor && proto.constructor.name ? proto.constructor.name : "Error";
25732
- console.log(prefix, kind + ": " + thrownMessage(error), error.stack);
25733
- }
25734
- var init_utils = __esm({
25735
- "../noodl-runtime/src/utils.ts"() {
25736
- }
25737
- });
25738
-
25739
- // ../noodl-runtime/src/componentwalk.ts
25740
- var componentwalk_exports = {};
25741
- __export(componentwalk_exports, {
25742
- COMPONENT_OBJECT_TYPES: () => COMPONENT_OBJECT_TYPES,
25743
- componentAncestorNames: () => componentAncestorNames,
25744
- componentAncestors: () => componentAncestors,
25745
- findAncestorWithComponentObject: () => findAncestorWithComponentObject,
25746
- findAncestorWithName: () => findAncestorWithName,
25747
- findAncestorWithNodeType: () => findAncestorWithNodeType,
25748
- findAncestorWithProperty: () => findAncestorWithProperty,
25749
- findComponentAncestor: () => findComponentAncestor,
25750
- parentComponentOf: () => parentComponentOf,
25751
- scopeChain: () => scopeChain,
25752
- scopeChainNames: () => scopeChainNames
25753
- });
25754
- function parentComponentOf(component) {
25755
- if (!component) return void 0;
25756
- let parent;
25757
- if (component.getRoots().length > 0) {
25758
- const root2 = component.getRoots()[0];
25759
- if (root2.getVisualParentNode) {
25760
- const visualParent = root2.getVisualParentNode();
25761
- if (visualParent) {
25762
- parent = visualParent.nodeScope.componentOwner;
25763
- }
25764
- } else if (root2.parentNodeScope) {
25765
- parent = component.parentNodeScope.componentOwner;
25766
- }
25767
- } else if (component.parentNodeScope) {
25768
- parent = component.parentNodeScope.componentOwner;
25769
- }
25770
- if (parent && parent.nodeScope && parent.nodeScope.componentOwner !== component) {
25771
- return parent;
25772
- }
25773
- return void 0;
25774
- }
25775
- function componentAncestors(component) {
25776
- const ancestors = [];
25777
- let current = component;
25778
- for (let depth = 0; depth < MAX_WALK_DEPTH; depth++) {
25779
- const parent = parentComponentOf(current);
25780
- if (!parent) break;
25781
- ancestors.push(parent);
25782
- current = parent;
25783
- }
25784
- return ancestors;
25785
- }
25786
- function findComponentAncestor(component, predicate) {
25787
- let current = component;
25788
- for (let depth = 0; depth < MAX_WALK_DEPTH; depth++) {
25789
- const parent = parentComponentOf(current);
25790
- if (!parent) return void 0;
25791
- if (predicate(parent)) return parent;
25792
- current = parent;
25793
- }
25794
- return void 0;
25795
- }
25796
- function findAncestorWithNodeType(component, types) {
25797
- return findComponentAncestor(
25798
- component,
25799
- (candidate) => types.some((type) => candidate.nodeScope.getNodesWithType(type).length > 0)
25800
- );
25801
- }
25802
- function findAncestorWithComponentObject(component) {
25803
- return findAncestorWithNodeType(component, COMPONENT_OBJECT_TYPES);
25804
- }
25805
- function findAncestorWithName(component, name2) {
25806
- return findComponentAncestor(component, (candidate) => candidate.name === name2);
25807
- }
25808
- function scopeChain(component) {
25809
- const chain2 = [];
25810
- let current = component;
25811
- for (let depth = 0; depth < MAX_WALK_DEPTH; depth++) {
25812
- if (!current) break;
25813
- chain2.push(current);
25814
- if (!current.parentNodeScope) break;
25815
- current = current.parentNodeScope.componentOwner;
25816
- }
25817
- return chain2;
25818
- }
25819
- function scopeChainNames(component) {
25820
- return scopeChain(component).map((entry) => entry.name);
25821
- }
25822
- function findAncestorWithProperty(component, property2) {
25823
- const chain2 = scopeChain(component);
25824
- for (let i2 = 0; i2 < chain2.length; i2++) {
25825
- if (chain2[i2][property2] !== void 0) return chain2[i2];
25826
- }
25827
- return void 0;
25828
- }
25829
- function componentAncestorNames(component) {
25830
- return componentAncestors(component).map((ancestor) => ancestor.name);
25831
- }
25832
- var MAX_WALK_DEPTH, COMPONENT_OBJECT_TYPES;
25833
- var init_componentwalk = __esm({
25834
- "../noodl-runtime/src/componentwalk.ts"() {
25835
- "use strict";
25836
- MAX_WALK_DEPTH = 1e3;
25837
- COMPONENT_OBJECT_TYPES = ["net.noodl.ComponentObject", "Component State"];
25838
- }
25839
- });
25840
-
25841
- // ../noodl-runtime/src/resolvedtarget.ts
25842
- function summariseTargets(labels) {
25843
- const distinct = [];
25844
- for (let i2 = 0; i2 < labels.length; i2++) {
25845
- const label = labels[i2];
25846
- if (label === void 0) continue;
25847
- if (distinct.indexOf(label) === -1) distinct.push(label);
25848
- }
25849
- if (distinct.length === 0) return void 0;
25850
- if (distinct.length === 1) return "\u2192 " + distinct[0];
25851
- const listed = distinct.slice(0, MAX_NAMES_LISTED).join(", ");
25852
- const rest2 = distinct.length - MAX_NAMES_LISTED;
25853
- return "\u2192 " + distinct.length + " targets: " + listed + (rest2 > 0 ? ", +" + rest2 : "");
25854
- }
25855
- var MAX_NAMES_LISTED, ResolvedTargetReporter;
25856
- var init_resolvedtarget = __esm({
25857
- "../noodl-runtime/src/resolvedtarget.ts"() {
25858
- "use strict";
25859
- MAX_NAMES_LISTED = 3;
25860
- ResolvedTargetReporter = class {
25861
- constructor() {
25862
- /** Weak, so a torn-down runtime's bookkeeping goes with it and needs no reset call. */
25863
- this._byContext = /* @__PURE__ */ new WeakMap();
25864
- }
25865
- /**
25866
- * Record what `node` bound to and push the summary to the editor.
25867
- *
25868
- * Safe to call every resolution; identical summaries are dropped rather than sent, so a
25869
- * node that re-resolves each frame costs one string comparison.
25870
- */
25871
- report(node, target) {
25872
- const state2 = this._stateFor(node);
25873
- if (!state2) return;
25874
- let instances = state2.byGraphNode.get(node.id);
25875
- if (!instances) {
25876
- instances = /* @__PURE__ */ new Map();
25877
- state2.byGraphNode.set(node.id, instances);
25878
- }
25879
- instances.set(node, target);
25880
- this._flush(node, state2, instances);
25881
- }
25882
- /** Drop an instance. Call from `_onNodeDeleted`, or this map is a leak. */
25883
- forget(node) {
25884
- const state2 = this._stateFor(node);
25885
- if (!state2) return;
25886
- const instances = state2.byGraphNode.get(node.id);
25887
- if (!instances) return;
25888
- instances.delete(node);
25889
- if (instances.size === 0) {
25890
- state2.byGraphNode.delete(node.id);
25891
- state2.lastSent.delete(node.id);
25892
- return;
25893
- }
25894
- this._flush(node, state2, instances);
25895
- }
25896
- _stateFor(node) {
25897
- const context = node.context;
25898
- if (!context) return void 0;
25899
- let state2 = this._byContext.get(context);
25900
- if (!state2) {
25901
- state2 = { byGraphNode: /* @__PURE__ */ new Map(), lastSent: /* @__PURE__ */ new Map() };
25902
- this._byContext.set(context, state2);
25903
- }
25904
- return state2;
25905
- }
25906
- _flush(node, state2, instances) {
25907
- const labels = [];
25908
- instances.forEach((label) => labels.push(label));
25909
- const summary = summariseTargets(labels);
25910
- if (state2.lastSent.has(node.id) && state2.lastSent.get(node.id) === summary) return;
25911
- state2.lastSent.set(node.id, summary);
25912
- const editorConnection = node.context && node.context.editorConnection;
25913
- if (!editorConnection || !editorConnection.isRunningLocally()) return;
25914
- if (typeof editorConnection.sendNodeSubLabel !== "function") return;
25915
- editorConnection.sendNodeSubLabel(node.id, summary);
25916
- }
25917
- };
25918
- }
25919
- });
25920
-
25921
- // ../noodl-runtime/src/foreachitem.ts
25922
- var foreachitem_exports = {};
25923
- __export(foreachitem_exports, {
25924
- forgetForEachItem: () => forgetForEachItem,
25925
- resolveForEachItem: () => resolveForEachItem
25926
- });
25927
- function resolveForEachItem(node, options = {}) {
25928
- const chain2 = scopeChain(node.nodeScope.componentOwner);
25929
- const wanted = options.target;
25930
- if (wanted) {
25931
- const named2 = firstNamed(chain2, wanted);
25932
- if (!named2) {
25933
- return miss(
25934
- node,
25935
- "repeater-item/target-not-found",
25936
- 'No component named "' + wanted + '" contains this node',
25937
- wanted,
25938
- { target: wanted, scope: scopeChainNames(node.nodeScope.componentOwner) }
25939
- );
25940
- }
25941
- if (named2[FOR_EACH_MODEL] === void 0) {
25942
- return miss(
25943
- node,
25944
- "repeater-item/target-has-no-item",
25945
- 'The component "' + wanted + '" has no current item \u2014 it is not used as a Repeater or Run Tasks template',
25946
- wanted,
25947
- { target: wanted }
25948
- );
25949
- }
25950
- return hit(node, named2);
25951
- }
25952
- const owner = firstWithItem(chain2);
25953
- if (!owner) {
25954
- return miss(
25955
- node,
25956
- "repeater-item/no-item-in-scope",
25957
- 'Id Source is set to "From repeater", but this node is not inside a Repeater or Run Tasks template',
25958
- void 0,
25959
- { scope: scopeChainNames(node.nodeScope.componentOwner) }
25960
- );
25961
- }
25962
- return hit(node, owner);
25963
- }
25964
- function forgetForEachItem(node) {
25965
- resolvedTargets.forget(node);
25966
- lastMissByNode.delete(node);
25967
- }
25968
- function firstNamed(chain2, name2) {
25969
- for (let i2 = 0; i2 < chain2.length; i2++) {
25970
- if (chain2[i2].name === name2) return chain2[i2];
25971
- }
25972
- return void 0;
25973
- }
25974
- function firstWithItem(chain2) {
25975
- for (let i2 = 0; i2 < chain2.length; i2++) {
25976
- if (chain2[i2][FOR_EACH_MODEL] !== void 0) return chain2[i2];
25977
- }
25978
- return void 0;
25979
- }
25980
- function hit(node, owner) {
25981
- lastMissByNode.delete(node);
25982
- resolvedTargets.report(node, owner.name);
25983
- return owner[FOR_EACH_MODEL];
25984
- }
25985
- function miss(node, code, message, target, detail) {
25986
- resolvedTargets.report(node, void 0);
25987
- const seen = code + "|" + (target || "");
25988
- if (lastMissByNode.get(node) !== seen) {
25989
- lastMissByNode.set(node, seen);
25990
- node.raiseRuntimeError(code, message, detail);
25991
- }
25992
- return void 0;
25993
- }
25994
- var FOR_EACH_MODEL, resolvedTargets, lastMissByNode;
25995
- var init_foreachitem = __esm({
25996
- "../noodl-runtime/src/foreachitem.ts"() {
25997
- "use strict";
25998
- init_componentwalk();
25999
- init_resolvedtarget();
26000
- FOR_EACH_MODEL = "_forEachModel";
26001
- resolvedTargets = new ResolvedTargetReporter();
26002
- lastMissByNode = /* @__PURE__ */ new WeakMap();
26003
- }
26004
- });
26005
-
26006
- // ../noodl-runtime/src/javascriptnodeparser.js
26007
- var require_javascriptnodeparser = __commonJS({
26008
- "../noodl-runtime/src/javascriptnodeparser.js"(exports2, module2) {
26009
- "use strict";
26010
- var Model27 = require_model2();
26011
- var { getAbsoluteUrl: getAbsoluteUrl2 } = (init_utils(), __toCommonJS(utils_exports));
26012
- var { findAncestorWithComponentObject: findAncestorWithComponentObject2 } = (init_componentwalk(), __toCommonJS(componentwalk_exports));
26013
- var { resolveForEachItem: resolveForEachItem2 } = (init_foreachitem(), __toCommonJS(foreachitem_exports));
26014
- var userFunctionsCache = {};
26015
- function JavascriptNodeParser4(code, options) {
26016
- this.inputs = {};
26017
- this.outputs = {};
26018
- this.error = void 0;
26019
- this.code = code;
26020
- const node = options ? options.node : void 0;
26021
- this._initializeAPIs();
26022
- var userCode = userFunctionsCache[code];
26023
- if (!userCode) {
26024
- try {
26025
- userCode = new Function(["define", "script", "Node", "Component"], JavascriptNodeParser4.getCodePrefix() + code);
26026
- userFunctionsCache[code] = userCode;
26027
- } catch (e) {
26028
- this.error = e.message;
26029
- console.error(e);
26030
- }
26031
- }
26032
- if (userCode) {
26033
- try {
26034
- userCode(
26035
- this.define.bind(this),
26036
- this.script.bind(this),
26037
- this.apis.Node,
26038
- node ? JavascriptNodeParser4.getComponentScopeForNode(node) : {}
26039
- );
26040
- this._afterSourced();
26041
- } catch (e) {
26042
- this.error = e.message;
26043
- console.error(e);
26044
- }
26045
- }
26046
- }
26047
- JavascriptNodeParser4.prototype.define = function(userObject) {
26048
- this.inputs = userObject.inputs || {};
26049
- this.outputs = userObject.outputs || {};
26050
- this.setup = userObject.setup;
26051
- this.change = userObject.run || userObject.change;
26052
- this.destroy = userObject.destroy;
26053
- this.definedObject = userObject;
26054
- };
26055
- function _scriptExtend(_this) {
26056
- var _extended = {
26057
- inputs: _this.inputs || {},
26058
- outputs: _this.outputs || {},
26059
- setup: function(inputs, outputs) {
26060
- this.inputs = inputs;
26061
- this.outputs = outputs;
26062
- this.setOutputs = function(states) {
26063
- for (var key3 in states) {
26064
- this.outputs[key3] = states[key3];
26065
- this.flagOutputDirty(key3);
26066
- }
26067
- };
26068
- if (_this.methods) {
26069
- for (var key2 in _this.methods) {
26070
- this[key2] = _this.methods[key2];
26071
- }
26072
- }
26073
- _this.setup && _this.setup.apply(this);
26074
- },
26075
- destroy: function(inputs, outputs) {
26076
- this.inputs = inputs;
26077
- this.outputs = outputs;
26078
- _this.destroy && _this.destroy.apply(this);
26079
- },
26080
- change: function(inputs, outputs) {
26081
- this.inputs = inputs;
26082
- this.outputs = outputs;
26083
- var old = this._oldInputs || {};
26084
- if (_this.changed) {
26085
- for (var key2 in inputs) {
26086
- if (inputs[key2] !== old[key2]) {
26087
- var changedFunction = _this.changed[key2];
26088
- if (typeof changedFunction === "function") changedFunction.apply(this, [inputs[key2], old[key2]]);
26089
- }
26090
- }
26091
- }
26092
- this._oldInputs = Object.assign({}, inputs);
26093
- }
26094
- };
26095
- if (_this.signals) {
26096
- for (var key in _this.signals) {
26097
- _extended[key] = _this.signals[key];
26098
- _extended.inputs[key] = "signal";
26099
- }
26100
- }
26101
- return _extended;
26102
- }
26103
- JavascriptNodeParser4.prototype.script = function(userObject) {
26104
- var _userObjectExtended = _scriptExtend(userObject);
26105
- this.inputs = _userObjectExtended.inputs || {};
26106
- this.outputs = _userObjectExtended.outputs || {};
26107
- this.setup = _userObjectExtended.setup;
26108
- this.change = _userObjectExtended.run || _userObjectExtended.change;
26109
- this.destroy = _userObjectExtended.destroy;
26110
- this.definedObject = _userObjectExtended;
26111
- };
26112
- JavascriptNodeParser4.prototype._initializeAPIs = function() {
26113
- this.apis = {
26114
- Node: {
26115
- Inputs: {},
26116
- Outputs: {},
26117
- Signals: {},
26118
- Setters: {}
26119
- }
26120
- };
26121
- };
26122
- JavascriptNodeParser4.prototype._afterSourced = function() {
26123
- if (this.definedObject !== void 0) return;
26124
- var _Node = this.apis.Node;
26125
- this.inputs = Object.assign({}, _Node.Inputs || {});
26126
- this.outputs = Object.assign({}, _Node.Outputs || {});
26127
- this.setup = function(inputs, outputs) {
26128
- const _this = this;
26129
- _Node.setOutputs = function(_outputs) {
26130
- for (var key2 in _outputs) {
26131
- outputs[key2] = _outputs[key2];
26132
- _this.flagOutputDirty(key2);
26133
- }
26134
- };
26135
- _Node.OnInit && _Node.OnInit.apply(this);
26136
- };
26137
- this.destroy = _Node.OnDestroy || this.destory;
26138
- this.change = (inputs, outputs, changedInputs) => {
26139
- for (var key2 in changedInputs) {
26140
- if (typeof _Node.Setters[key2] === "function") {
26141
- _Node.Setters[key2](inputs[key2]);
26142
- }
26143
- }
26144
- if (typeof _Node.OnInputsChanged === "function") {
26145
- _Node.OnInputsChanged();
26146
- }
26147
- };
26148
- this.definedObject = {
26149
- inputs: this.inputs,
26150
- outputs: this.outputs,
26151
- setup: this.setup,
26152
- destroy: this.destroy,
26153
- change: this.change
26154
- };
26155
- if (_Node.Signals !== void 0) {
26156
- for (var key in _Node.Signals) {
26157
- if (typeof _Node.Signals[key] === "function") {
26158
- this.inputs[key] = "signal";
26159
- this.definedObject[key] = _Node.Signals[key];
26160
- }
26161
- }
26162
- }
26163
- };
26164
- JavascriptNodeParser4.createFromCode = function(code, options) {
26165
- return new JavascriptNodeParser4(code, options);
26166
- };
26167
- function failedParser(message) {
26168
- var parser = Object.create(JavascriptNodeParser4.prototype);
26169
- parser.inputs = {};
26170
- parser.outputs = {};
26171
- parser.error = message;
26172
- parser.code = void 0;
26173
- parser.apis = { Node: {} };
26174
- return parser;
26175
- }
26176
- JavascriptNodeParser4.createFromURL = function(url, callback, options) {
26177
- url = getAbsoluteUrl2(url);
26178
- var settled = false;
26179
- function settle(parser) {
26180
- if (settled) return;
26181
- settled = true;
26182
- callback(parser);
26183
- }
26184
- var xhr = new window.XMLHttpRequest();
26185
- xhr.open("GET", url, true);
26186
- xhr.onreadystatechange = function() {
26187
- if (this.readyState === 4 || this.readyState === XMLHttpRequest.DONE) {
26188
- if (this.status !== 0 && (this.status < 200 || this.status >= 300)) {
26189
- settle(failedParser('Could not load "' + url + '": the server answered ' + this.status));
26190
- return;
26191
- }
26192
- if (this.status === 0) {
26193
- settle(failedParser('Could not load "' + url + '": the request failed'));
26194
- return;
26195
- }
26196
- settle(new JavascriptNodeParser4(this.response, options));
26197
- }
26198
- };
26199
- xhr.onerror = function() {
26200
- settle(failedParser('Could not load "' + url + '": the request failed'));
26201
- };
26202
- xhr.send();
26203
- };
26204
- JavascriptNodeParser4.parseAndAddPortsFromScript = function(script, ports, options) {
26205
- function _exists(port) {
26206
- if (typeof port === "string") return ports.find((p) => p.name === port) !== void 0;
26207
- else return ports.find((p) => p.name === port.name && p.plug === port.plug) !== void 0;
26208
- }
26209
- function _addPortsFromMatch(match, options2) {
26210
- if (match === void 0 || match === null) return;
26211
- const unique = {};
26212
- for (const _s of match) {
26213
- let name2 = _s[1];
26214
- if (name2 === void 0) continue;
26215
- unique[name2] = true;
26216
- }
26217
- Object.keys(unique).forEach((p) => {
26218
- if (_exists({
26219
- name: options2.prefix + p,
26220
- plug: options2.plug
26221
- }))
26222
- return;
26223
- ports.push({
26224
- name: options2.prefix + p,
26225
- displayName: p,
26226
- plug: options2.plug,
26227
- type: options2.type,
26228
- group: options2.group
26229
- });
26230
- });
26231
- }
26232
- if (!options.skipInputs) {
26233
- _addPortsFromMatch(script.matchAll(/Inputs\.([A-Za-z0-9_]+)/g), {
26234
- type: options.inputType || "*",
26235
- plug: "input",
26236
- group: options.inputGroup || "Inputs",
26237
- prefix: options.inputPrefix || ""
26238
- });
26239
- _addPortsFromMatch(script.matchAll(/Inputs\s*\[\s*(?:'|")(.*)(?:'|")\s*\]/g), {
26240
- type: options.inputType || "*",
26241
- plug: "inputs",
26242
- group: options.inputGroup || "Inputs",
26243
- prefix: options.inputPrefix || ""
26244
- });
26245
- }
26246
- if (!options.skipOutputs) {
26247
- if (!options.skipOutputSignals) {
26248
- _addPortsFromMatch(script.matchAll(/Outputs\.([A-Za-z0-9]+)\s*\(\s*\)/g), {
26249
- type: "signal",
26250
- plug: "output",
26251
- group: "Outputs",
26252
- prefix: options.outputPrefix || ""
26253
- });
26254
- _addPortsFromMatch(script.matchAll(/Outputs\s*\[\s*(?:'|")(.*)(?:'|")\s*\]\(\s*\)/g), {
26255
- type: "signal",
26256
- plug: "output",
26257
- group: "Outputs",
26258
- prefix: options.outputPrefix || ""
26259
- });
26260
- }
26261
- if (!options.skipRegularOutputs) {
26262
- _addPortsFromMatch(script.matchAll(/Outputs\.([A-Za-z0-9_]+)/g), {
26263
- type: "*",
26264
- plug: "output",
26265
- group: "Outputs",
26266
- prefix: options.outputPrefix || ""
26267
- });
26268
- _addPortsFromMatch(script.matchAll(/Outputs\s*\[\s*\"([^\"]*)\"\s*\]/g), {
26269
- type: "*",
26270
- plug: "output",
26271
- group: "Outputs",
26272
- prefix: options.outputPrefix || ""
26273
- });
26274
- }
26275
- }
26276
- };
26277
- JavascriptNodeParser4.prototype.getPorts = function() {
26278
- var ports = [];
26279
- var self2 = this;
26280
- Object.keys(this.inputs).forEach(function(name2) {
26281
- var inputPort = self2.inputs[name2];
26282
- var port = {
26283
- name: name2,
26284
- plug: "input"
26285
- };
26286
- if (typeof inputPort === "string") {
26287
- port.type = {
26288
- name: inputPort
26289
- };
26290
- port.group = "Inputs";
26291
- } else {
26292
- for (var p in inputPort) {
26293
- port[p] = inputPort[p];
26294
- }
26295
- }
26296
- ports.push(port);
26297
- });
26298
- Object.keys(this.outputs).forEach(function(name2) {
26299
- ports.push({
26300
- name: name2,
26301
- type: {
26302
- name: self2.outputs[name2]
26303
- },
26304
- plug: "output",
26305
- group: "Outputs"
26306
- });
26307
- });
26308
- JavascriptNodeParser4.parseAndAddPortsFromScript(this.code, ports, {});
26309
- return ports;
26310
- };
26311
- var _componentScopes = {};
26312
- function _findParentComponentStateModelId(node) {
26313
- const parent = findAncestorWithComponentObject2(node.nodeScope.componentOwner);
26314
- if (!parent) return;
26315
- return "componentState" + parent.getInstanceId();
26316
- }
26317
- JavascriptNodeParser4.getComponentScopeForNode = function(node) {
26318
- const componentId = node.nodeScope.componentOwner.getInstanceId();
26319
- if (_componentScopes[componentId] === void 0) {
26320
- _componentScopes[componentId] = {};
26321
- const componentObject = (node.nodeScope.modelScope || Model27).get("componentState" + componentId);
26322
- _componentScopes[componentId].Object = componentObject;
26323
- }
26324
- const parentComponentObjectId = _findParentComponentStateModelId(node);
26325
- const parentComponentObject = parentComponentObjectId !== void 0 ? (node.nodeScope.modelScope || Model27).get(parentComponentObjectId) : void 0;
26326
- _componentScopes[componentId].ParentObject = parentComponentObject;
26327
- Object.defineProperty(_componentScopes[componentId], "RepeaterObject", {
26328
- configurable: true,
26329
- enumerable: true,
26330
- get: function() {
26331
- return resolveForEachItem2(node);
26332
- }
26333
- });
26334
- return _componentScopes[componentId];
26335
- };
26336
- JavascriptNodeParser4.getCodePrefix = function() {
26337
- return "const Script = (typeof Node !== 'undefined')?Node:undefined;\n";
26338
- };
26339
- JavascriptNodeParser4.createNoodlAPI = function() {
26340
- return typeof window !== "undefined" && window.Noodl !== void 0 ? window.Noodl : {};
26341
- };
26342
- module2.exports = JavascriptNodeParser4;
26343
- }
26344
- });
26345
-
26346
26463
  // ../noodl-runtime/src/nodes/std-library/expression.ts
26347
26464
  var require_expression = __commonJS({
26348
26465
  "../noodl-runtime/src/nodes/std-library/expression.ts"(exports2, module2) {
26349
26466
  "use strict";
26350
26467
  init_expression_ports();
26351
26468
  init_logic_search_tags();
26469
+ init_printedcode();
26352
26470
  init_outcome();
26353
26471
  init_run_on_value_change();
26354
26472
  var Node17 = require_node2();
@@ -26577,11 +26695,27 @@ var require_expression = __commonJS({
26577
26695
  const args = Object.keys(this._internal.scope);
26578
26696
  this._internal.compiledWith = args.slice();
26579
26697
  args.push("Noodl");
26698
+ const printed = findPrintedBody(expression, false);
26699
+ if (printed) {
26700
+ this._internal.compiledWith = printed.params.slice(0, -1);
26701
+ this._internal.compileError = void 0;
26702
+ return printed.fn;
26703
+ }
26704
+ if (hasPrintedCode()) {
26705
+ try {
26706
+ const fn = compileCode(args, expression);
26707
+ this._internal.compileError = void 0;
26708
+ return fn;
26709
+ } catch (e) {
26710
+ this._internal.compileError = e.message;
26711
+ return void 0;
26712
+ }
26713
+ }
26580
26714
  const key = expression + args.join(" ");
26581
26715
  if (compiledFunctionsCache2.hasOwnProperty(key) === false) {
26582
- args.push(expression);
26716
+ const params = args.slice();
26583
26717
  try {
26584
- compiledFunctionsCache2[key] = construct(Function, args);
26718
+ compiledFunctionsCache2[key] = compileCode(params, expression);
26585
26719
  this._internal.compileError = void 0;
26586
26720
  } catch (e) {
26587
26721
  this._internal.compileError = e.message;
@@ -26613,7 +26747,7 @@ var require_expression = __commonJS({
26613
26747
  description: "JavaScript expression whose value becomes Result. Every name it reads becomes an input port, except JavaScript's own (String, Number, JSON, Date, parseInt, Math and the rest), the Math shortcuts (round, min, pi\u2026) and keywords such as typeof; a port can never be called one of those, nor run, expression or evaluateAtLoad, which are this node's own inputs",
26614
26748
  set: function(value2) {
26615
26749
  const internal2 = this._internal;
26616
- internal2.currentExpression = functionPreamble + "return (" + value2 + ");";
26750
+ internal2.currentExpression = expressionNodeBody(value2);
26617
26751
  internal2.compiledFunction = void 0;
26618
26752
  const newInputs = expressionPorts(value2);
26619
26753
  internal2.referencedPorts = newInputs;
@@ -26812,17 +26946,7 @@ var require_expression = __commonJS({
26812
26946
  }
26813
26947
  }
26814
26948
  };
26815
- var functionPreamble = [
26816
- 'var min = Math.min, max = Math.max, cos = Math.cos, sin = Math.sin, tan = Math.tan, sqrt = Math.sqrt, pi = Math.PI, round = Math.round, floor = Math.floor, ceil = Math.ceil, abs = Math.abs, random = Math.random, pow = Math.pow, log = Math.log, exp = Math.exp;try { var NoodlContext = (typeof Noodl !== "undefined") ? Noodl : (typeof global !== "undefined" && global.Noodl) || {}; var Variables = NoodlContext.Variables || {}; var Objects = NoodlContext.Objects || {}; var Arrays = NoodlContext.Arrays || {};} catch (e) { var Variables = {}, Objects = {}, Arrays = {};}'
26817
- ].join("");
26818
26949
  var NOT_EVALUATED = {};
26819
- function construct(constructor, args) {
26820
- function F() {
26821
- return constructor.apply(this, args);
26822
- }
26823
- F.prototype = constructor.prototype;
26824
- return new F();
26825
- }
26826
26950
  var compiledFunctionsCache2 = {};
26827
26951
  function reservedNameMessage(names) {
26828
26952
  const list = names.length > 1 ? names.slice(0, -1).join(", ") + " and " + names[names.length - 1] : names.join("");
@@ -26926,10 +27050,10 @@ function rawPositionFromStack(stack) {
26926
27050
  function stackLineOffset() {
26927
27051
  if (cachedOffset !== void 0) return cachedOffset;
26928
27052
  try {
26929
- const AsyncFunction = Object.getPrototypeOf(async function() {
27053
+ const AsyncFunction2 = Object.getPrototypeOf(async function() {
26930
27054
  }).constructor;
26931
27055
  let captured;
26932
- const probe = new AsyncFunction(
27056
+ const probe = new AsyncFunction2(
26933
27057
  "Inputs",
26934
27058
  "Outputs",
26935
27059
  "Noodl",
@@ -26984,12 +27108,12 @@ function undeclaredPortNameMessage(name2, side, isSignal = false) {
26984
27108
  function noOutputWrittenMessage(ports) {
26985
27109
  if (ports.length === 0) return "";
26986
27110
  const first2 = ports[0];
26987
- const named2 = ports.map((p) => '"' + p.label + '"').join(", ");
27111
+ const named3 = ports.map((p) => '"' + p.label + '"').join(", ");
26988
27112
  const which = ports.length === 1 ? "it" : '"' + first2.label + '"';
26989
27113
  if (first2.isSignal) {
26990
- return "The script ran but produced no output: " + named2 + " never fired. Fire " + which + " in the script with " + portUsage("Outputs", first2.label, true) + ".";
27114
+ return "The script ran but produced no output: " + named3 + " never fired. Fire " + which + " in the script with " + portUsage("Outputs", first2.label, true) + ".";
26991
27115
  }
26992
- return "The script ran but produced no output: " + named2 + " stayed empty. Write " + which + " in the script with " + portUsage("Outputs", first2.label, false) + " \u2014 assigning to a plain variable of the same name does not reach the port.";
27116
+ return "The script ran but produced no output: " + named3 + " stayed empty. Write " + which + " in the script with " + portUsage("Outputs", first2.label, false) + " \u2014 assigning to a plain variable of the same name does not reach the port.";
26993
27117
  }
26994
27118
  function proplistLabels(model2, parameter) {
26995
27119
  const rows = model2 && model2.parameters && model2.parameters[parameter];
@@ -27193,6 +27317,7 @@ var require_simplejavascript = __commonJS({
27193
27317
  init_scriptfiles();
27194
27318
  init_function_ports();
27195
27319
  init_tracecause();
27320
+ init_printedcode();
27196
27321
  var Node17 = require_node2();
27197
27322
  var JavascriptNodeParser4 = require_javascriptnodeparser();
27198
27323
  var { logJavaScriptNodeError: logJavaScriptNodeError2, thrownMessage: thrownMessage3 } = (init_utils(), __toCommonJS(utils_exports));
@@ -27291,6 +27416,7 @@ var require_simplejavascript = __commonJS({
27291
27416
  return names;
27292
27417
  }
27293
27418
  function publishHeldWrites(node) {
27419
+ sendHeldChanges(node);
27294
27420
  node._internal.heldWrites.forEach((prop) => {
27295
27421
  node.registerOutputIfNeeded("out-" + prop);
27296
27422
  node.flagOutputDirty("out-" + prop);
@@ -27334,7 +27460,7 @@ var require_simplejavascript = __commonJS({
27334
27460
  if (value2 !== this._internal.outputValues[prop]) {
27335
27461
  this.registerOutputIfNeeded("out-" + prop);
27336
27462
  this._internal.outputValues[prop] = value2;
27337
- this.flagOutputDirty("out-" + prop);
27463
+ holdChange(this, prop);
27338
27464
  this._internal.heldWrites.delete(prop);
27339
27465
  } else {
27340
27466
  this._internal.heldWrites.add(prop);
@@ -27513,7 +27639,7 @@ var require_simplejavascript = __commonJS({
27513
27639
  });
27514
27640
  },
27515
27641
  runScript: async function() {
27516
- const func = this._internal.func;
27642
+ const func = sendingChangesAfterTheSyncPart(this, this._internal.func);
27517
27643
  const tokens = this._internal.pendingRunOutcomes || [];
27518
27644
  this._internal.pendingRunOutcomes = void 0;
27519
27645
  if (func === void 0) {
@@ -27718,16 +27844,7 @@ var require_simplejavascript = __commonJS({
27718
27844
  parseScript: function(script) {
27719
27845
  let func;
27720
27846
  try {
27721
- const AsyncFunction = Object.getPrototypeOf(async function() {
27722
- }).constructor;
27723
- func = new AsyncFunction(
27724
- "Inputs",
27725
- "Outputs",
27726
- "Noodl",
27727
- "Component",
27728
- "Scripts",
27729
- JavascriptNodeParser4.getCodePrefix() + script
27730
- );
27847
+ func = compileCode(FUNCTION_NODE_PARAMS, functionNodeBody(script), { async: true });
27731
27848
  this._internal.parseError = void 0;
27732
27849
  this._internal.lastReportedError = void 0;
27733
27850
  } catch (e) {
@@ -27795,9 +27912,9 @@ var require_simplejavascript = __commonJS({
27795
27912
  return;
27796
27913
  }
27797
27914
  try {
27798
- const AsyncFunction = Object.getPrototypeOf(async function() {
27915
+ const AsyncFunction2 = Object.getPrototypeOf(async function() {
27799
27916
  }).constructor;
27800
- new AsyncFunction("Inputs", "Outputs", "Noodl", "Component", script);
27917
+ new AsyncFunction2("Inputs", "Outputs", "Noodl", "Component", script);
27801
27918
  context.editorConnection.clearWarning(node.component.name, node.id, "js-function-parse-waring");
27802
27919
  } catch (e) {
27803
27920
  context.editorConnection.sendWarning(node.component.name, node.id, "js-function-parse-waring", {
@@ -27955,6 +28072,32 @@ var require_simplejavascript = __commonJS({
27955
28072
  });
27956
28073
  }
27957
28074
  };
28075
+ function holdChange(node, prop) {
28076
+ const internal2 = node._internal;
28077
+ if (!internal2.heldChanges) internal2.heldChanges = /* @__PURE__ */ new Set();
28078
+ internal2.heldChanges.add(prop);
28079
+ if (internal2.heldChangesQueued) return;
28080
+ internal2.heldChangesQueued = true;
28081
+ Promise.resolve().then(() => sendHeldChanges(node));
28082
+ }
28083
+ function sendHeldChanges(node) {
28084
+ const internal2 = node._internal;
28085
+ internal2.heldChangesQueued = false;
28086
+ const held = internal2.heldChanges;
28087
+ if (!held || held.size === 0 || node._deleted) return;
28088
+ internal2.heldChanges = /* @__PURE__ */ new Set();
28089
+ held.forEach((prop) => node.flagOutputDirty("out-" + prop));
28090
+ }
28091
+ function sendingChangesAfterTheSyncPart(node, func) {
28092
+ if (func === void 0) return void 0;
28093
+ return function(...args) {
28094
+ try {
28095
+ return func.apply(this, args);
28096
+ } finally {
28097
+ sendHeldChanges(node);
28098
+ }
28099
+ };
28100
+ }
27958
28101
  module2.exports = SimpleJavascriptNodeModule;
27959
28102
  }
27960
28103
  });
@@ -28274,6 +28417,7 @@ var require_logic_builder = __commonJS({
28274
28417
  init_logic_builder_io2();
28275
28418
  init_logic_builder_probe();
28276
28419
  init_logic_search_tags();
28420
+ init_printedcode();
28277
28421
  init_outcome();
28278
28422
  var EdgeTriggeredInput7 = require_edgetriggeredinput();
28279
28423
  var LogicBuilderNode = {
@@ -28628,47 +28772,49 @@ var require_logic_builder = __commonJS({
28628
28772
  return null;
28629
28773
  }
28630
28774
  try {
28631
- const fn = new Function(
28632
- "Inputs",
28633
- "Outputs",
28634
- "Noodl",
28635
- "Variables",
28636
- "Objects",
28637
- "Arrays",
28638
- "sendSignalOnOutput",
28639
- "__triggerSignal__",
28640
- /**
28641
- * LGC-003 §1 — the ninth and tenth parameters, and the reason there is only ever one
28642
- * generated string.
28643
- *
28644
- * The editor emits `__p("<blockId>", …)` around every value block and `__s("<blockId>")`
28645
- * before every statement, always — there is no debug build and no release build, so
28646
- * there is no class of defect that appears only when nobody is watching. What changes
28647
- * is which functions land here: the shared identity pair, or a recorder.
28648
- *
28649
- * ⚠️ **Declared unconditionally, including for code generated before this existed.**
28650
- * A `generatedCode` string saved by an older editor mentions neither name, and an
28651
- * unused parameter costs nothing — whereas making the list conditional on the code
28652
- * would put a `code.indexOf('__p')` on the compile path and give the runtime two
28653
- * shapes of compiled function to reason about.
28654
- */
28655
- "__p",
28656
- "__s",
28657
- /**
28658
- * The eleventh parameter, and the only one that shadows a global rather than adding a
28659
- * name (FIX-004 redaction ruling b).
28660
- *
28661
- * ⚠️ **Order is the contract.** This list and the argument list in `_executeLogic` are
28662
- * positional, so a parameter added here and not there — or added in a different place —
28663
- * silently shifts every argument after it. `__triggerSignal__` was already once built
28664
- * and then not passed, which read as `undefined` inside every block program ever run.
28665
- * A spec asserts this node's parameter names in order for that reason.
28666
- *
28667
- * Declared unconditionally, exactly as `__p`/`__s` are: code generated before this
28668
- * existed says `console.log`, which is the whole point, and code that never mentions
28669
- * `console` pays one unused parameter.
28670
- */
28671
- "console",
28775
+ const fn = compileCode(
28776
+ [
28777
+ "Inputs",
28778
+ "Outputs",
28779
+ "Noodl",
28780
+ "Variables",
28781
+ "Objects",
28782
+ "Arrays",
28783
+ "sendSignalOnOutput",
28784
+ "__triggerSignal__",
28785
+ /**
28786
+ * LGC-003 §1 — the ninth and tenth parameters, and the reason there is only ever one
28787
+ * generated string.
28788
+ *
28789
+ * The editor emits `__p("<blockId>", …)` around every value block and `__s("<blockId>")`
28790
+ * before every statement, always — there is no debug build and no release build, so
28791
+ * there is no class of defect that appears only when nobody is watching. What changes
28792
+ * is which functions land here: the shared identity pair, or a recorder.
28793
+ *
28794
+ * ⚠️ **Declared unconditionally, including for code generated before this existed.**
28795
+ * A `generatedCode` string saved by an older editor mentions neither name, and an
28796
+ * unused parameter costs nothing — whereas making the list conditional on the code
28797
+ * would put a `code.indexOf('__p')` on the compile path and give the runtime two
28798
+ * shapes of compiled function to reason about.
28799
+ */
28800
+ "__p",
28801
+ "__s",
28802
+ /**
28803
+ * The eleventh parameter, and the only one that shadows a global rather than adding a
28804
+ * name (FIX-004 redaction ruling b).
28805
+ *
28806
+ * ⚠️ **Order is the contract.** This list and the argument list in `_executeLogic` are
28807
+ * positional, so a parameter added here and not there — or added in a different place —
28808
+ * silently shifts every argument after it. `__triggerSignal__` was already once built
28809
+ * and then not passed, which read as `undefined` inside every block program ever run.
28810
+ * A spec asserts this node's parameter names in order for that reason.
28811
+ *
28812
+ * Declared unconditionally, exactly as `__p`/`__s` are: code generated before this
28813
+ * existed says `console.log`, which is the whole point, and code that never mentions
28814
+ * `console` pays one unused parameter.
28815
+ */
28816
+ "console"
28817
+ ],
28672
28818
  code
28673
28819
  );
28674
28820
  return fn;
@@ -29891,22 +30037,22 @@ function connectionKey(dialect, base, token, where2) {
29891
30037
  const filter2 = filterKey(where2);
29892
30038
  return dialect + " " + base + " " + token + (filter2 ? " #" + filter2 : "");
29893
30039
  }
29894
- function connectionFor(request) {
29895
- const host = request.host || DEFAULT_HOST2;
30040
+ function connectionFor(request2) {
30041
+ const host = request2.host || DEFAULT_HOST2;
29896
30042
  let pool = POOLS.get(host);
29897
30043
  if (!pool) {
29898
30044
  pool = /* @__PURE__ */ new Map();
29899
30045
  POOLS.set(host, pool);
29900
30046
  }
29901
- const key = connectionKey(request.dialect.name, request.base, request.token, request.where);
30047
+ const key = connectionKey(request2.dialect.name, request2.base, request2.token, request2.where);
29902
30048
  const existing = pool.get(key);
29903
30049
  if (existing) return existing;
29904
30050
  const created = new SharedSseConnection(
29905
- request.dialect,
29906
- request.base,
29907
- request.token,
29908
- request.EventSourceImpl,
29909
- request.fetchImpl,
30051
+ request2.dialect,
30052
+ request2.base,
30053
+ request2.token,
30054
+ request2.EventSourceImpl,
30055
+ request2.fetchImpl,
29910
30056
  () => {
29911
30057
  const current = POOLS.get(host);
29912
30058
  if (current && current.get(key) === created) current.delete(key);
@@ -30118,9 +30264,9 @@ var init_SseConnectionPool = __esm({
30118
30264
  // ../noodl-runtime/src/api/backends/realtime/SseTransport.ts
30119
30265
  function entryIsAbout(entry, collection) {
30120
30266
  if (!entry || typeof entry !== "object") return true;
30121
- const named2 = entry.collection;
30122
- if (typeof named2 !== "string") return true;
30123
- return named2 === collection;
30267
+ const named3 = entry.collection;
30268
+ if (typeof named3 !== "string") return true;
30269
+ return named3 === collection;
30124
30270
  }
30125
30271
  var NODEGX_SSE, POCKETBASE_SSE, SseTransport;
30126
30272
  var init_SseTransport = __esm({
@@ -30779,6 +30925,19 @@ function recordFieldPorts(ctx, options) {
30779
30925
  }
30780
30926
  return ports;
30781
30927
  }
30928
+ function recordBuiltInDatePorts(ctx, existingPorts, options = {}) {
30929
+ if (!ctx.selectedCollection || !isParseWireContext(ctx)) return [];
30930
+ const have = new Set(existingPorts.map((port) => port.name));
30931
+ const ports = [];
30932
+ for (const field of RECORD_BUILT_IN_DATES) {
30933
+ if (have.has(`prop-${field}`)) continue;
30934
+ ports.push({ name: `prop-${field}`, displayName: field, type: { name: "date" }, plug: "output", group: "Properties" });
30935
+ if (options.includeChangedSignals && !have.has(`changed-${field}`)) {
30936
+ ports.push({ name: `changed-${field}`, displayName: `${field} Changed`, type: "signal", plug: "output", group: "Events" });
30937
+ }
30938
+ }
30939
+ return ports;
30940
+ }
30782
30941
  function recordPortType(field) {
30783
30942
  if (field.nativeType && Object.prototype.hasOwnProperty.call(PARSE_PORT_TYPES, field.nativeType)) {
30784
30943
  return { name: PARSE_PORT_TYPES[field.nativeType] };
@@ -30889,7 +31048,7 @@ function parseTypeNameFor(field) {
30889
31048
  function recordFilterBackendType(ctx, fallback) {
30890
31049
  return ctx.backendType || fallback;
30891
31050
  }
30892
- var PARSE_PORT_TYPES, PARSE_SYSTEM_CLASSES;
31051
+ var PARSE_PORT_TYPES, PARSE_SYSTEM_CLASSES, RECORD_BUILT_IN_DATES;
30893
31052
  var init_record_ports = __esm({
30894
31053
  "../noodl-runtime/src/nodes/std-library/data/record-ports.ts"() {
30895
31054
  init_resolveBackend_pure();
@@ -30904,6 +31063,7 @@ var init_record_ports = __esm({
30904
31063
  { label: "User", value: "_User" },
30905
31064
  { label: "Role", value: "_Role" }
30906
31065
  ]);
31066
+ RECORD_BUILT_IN_DATES = Object.freeze(["createdAt", "updatedAt"]);
30907
31067
  }
30908
31068
  });
30909
31069
 
@@ -31203,8 +31363,8 @@ function relationsFromDirectus(rows) {
31203
31363
  function relationsFromPostgrestSpec(spec) {
31204
31364
  const definitions = spec?.definitions ?? {};
31205
31365
  const result2 = [];
31206
- const analyse = (table) => {
31207
- const properties2 = definitions[table]?.properties ?? {};
31366
+ const analyse = (table2) => {
31367
+ const properties2 = definitions[table2]?.properties ?? {};
31208
31368
  const foreignKeys = [];
31209
31369
  let primaryKeyCount = 0;
31210
31370
  for (const [column, definition4] of Object.entries(properties2)) {
@@ -31216,8 +31376,8 @@ function relationsFromPostgrestSpec(spec) {
31216
31376
  }
31217
31377
  return { foreignKeys, primaryKeyCount };
31218
31378
  };
31219
- for (const table of Object.keys(definitions)) {
31220
- const { foreignKeys, primaryKeyCount } = analyse(table);
31379
+ for (const table2 of Object.keys(definitions)) {
31380
+ const { foreignKeys, primaryKeyCount } = analyse(table2);
31221
31381
  const isJunction = foreignKeys.length === 2 && primaryKeyCount === 2 && foreignKeys.every((fk) => fk.primaryKey);
31222
31382
  if (isJunction) {
31223
31383
  const [left, right] = foreignKeys;
@@ -31234,7 +31394,7 @@ function relationsFromPostgrestSpec(spec) {
31234
31394
  cardinality: "many",
31235
31395
  write: {
31236
31396
  kind: "junction",
31237
- collection: table,
31397
+ collection: table2,
31238
31398
  sourceField: near.column,
31239
31399
  targetField: far.column,
31240
31400
  // The pair *is* the primary key, so a duplicate is a `23505` and
@@ -31248,7 +31408,7 @@ function relationsFromPostgrestSpec(spec) {
31248
31408
  }
31249
31409
  for (const fk of foreignKeys) {
31250
31410
  result2.push({
31251
- collection: table,
31411
+ collection: table2,
31252
31412
  field: fk.column,
31253
31413
  target: fk.target,
31254
31414
  cardinality: "one",
@@ -31256,8 +31416,8 @@ function relationsFromPostgrestSpec(spec) {
31256
31416
  });
31257
31417
  result2.push({
31258
31418
  collection: fk.target,
31259
- field: table,
31260
- target: table,
31419
+ field: table2,
31420
+ target: table2,
31261
31421
  cardinality: "many",
31262
31422
  write: { kind: "foreignKey", field: fk.column, on: "target" }
31263
31423
  });
@@ -31530,11 +31690,11 @@ var init_filter = __esm({
31530
31690
 
31531
31691
  // ../nodegx-backend-contract/src/descriptors/helpers.ts
31532
31692
  function filterTable(fallback, overrides) {
31533
- const table = {};
31693
+ const table2 = {};
31534
31694
  for (const operator of FILTER_OPERATORS) {
31535
- table[operator] = overrides[operator] ?? fallback;
31695
+ table2[operator] = overrides[operator] ?? fallback;
31536
31696
  }
31537
- return Object.freeze(table);
31697
+ return Object.freeze(table2);
31538
31698
  }
31539
31699
  var supported, unsupported, degraded, conditional;
31540
31700
  var init_helpers = __esm({
@@ -32970,8 +33130,8 @@ var init_probes = __esm({
32970
33130
  const cacheKey = `${backendId}\0${key}`;
32971
33131
  const existing = this._inFlight.get(cacheKey);
32972
33132
  if (existing) return existing;
32973
- const request = { key, probe: capability.probe, url: url.replace(/\/+$/, ""), type };
32974
- const pending = this._runner(request).then((outcome) => {
33133
+ const request2 = { key, probe: capability.probe, url: url.replace(/\/+$/, ""), type };
33134
+ const pending = this._runner(request2).then((outcome) => {
32975
33135
  this._record(backendId, key, outcome);
32976
33136
  return outcome;
32977
33137
  }).catch(() => {
@@ -33030,12 +33190,12 @@ var init_operational = __esm({
33030
33190
  });
33031
33191
 
33032
33192
  // ../nodegx-backend-contract/src/targetGoes.ts
33033
- function whenTargetGoesProblems(table, columns) {
33193
+ function whenTargetGoesProblems(table2, columns) {
33034
33194
  const out = [];
33035
33195
  for (const col of columns) {
33036
33196
  const rule = col.whenTargetGoes;
33037
33197
  if (rule === void 0) continue;
33038
- const at = `"${table}.${col.name}"`;
33198
+ const at = `"${table2}.${col.name}"`;
33039
33199
  if (typeof rule !== "string" || !WHEN_TARGET_GOES.includes(rule)) {
33040
33200
  out.push(`${at} says "${String(rule)}" for when what it points at goes; it must be one of ${WHEN_TARGET_GOES.join(", ")}.`);
33041
33201
  } else if (col.type !== "Pointer") {
@@ -33050,12 +33210,12 @@ function whenTargetGoesProblems(table, columns) {
33050
33210
  }
33051
33211
  function rulesByTarget(schema) {
33052
33212
  const out = /* @__PURE__ */ new Map();
33053
- for (const table of schema.listTables()) {
33054
- for (const col of schema.getTableSchema(table)?.columns || []) {
33213
+ for (const table2 of schema.listTables()) {
33214
+ for (const col of schema.getTableSchema(table2)?.columns || []) {
33055
33215
  const rule = col.whenTargetGoes;
33056
33216
  if (col.type !== "Pointer" || !col.targetClass || !rule || !WHEN_TARGET_GOES.includes(rule)) continue;
33057
33217
  const list = out.get(col.targetClass) || [];
33058
- list.push({ collection: table, field: col.name, rule });
33218
+ list.push({ collection: table2, field: col.name, rule });
33059
33219
  out.set(col.targetClass, list);
33060
33220
  }
33061
33221
  }
@@ -33063,18 +33223,18 @@ function rulesByTarget(schema) {
33063
33223
  }
33064
33224
  function relations(schema) {
33065
33225
  const out = [];
33066
- for (const table of schema.listTables())
33067
- for (const col of schema.getTableSchema(table)?.columns || []) if (col.type === "Relation") out.push([table, col.name, col.targetClass || ""]);
33226
+ for (const table2 of schema.listTables())
33227
+ for (const col of schema.getTableSchema(table2)?.columns || []) if (col.type === "Relation") out.push([table2, col.name, col.targetClass || ""]);
33068
33228
  return out;
33069
33229
  }
33070
33230
  function pairsOf(rels, schema, collection, objectId) {
33071
33231
  const out = [];
33072
- for (const [table, field, target] of rels) {
33073
- if (table === collection) {
33074
- const ids = schema.getRelatedIds(table, objectId, field);
33075
- for (const relatedId of Array.isArray(ids) ? ids : []) out.push({ collection: table, objectId, field, relatedId: String(relatedId) });
33232
+ for (const [table2, field, target] of rels) {
33233
+ if (table2 === collection) {
33234
+ const ids = schema.getRelatedIds(table2, objectId, field);
33235
+ for (const relatedId of Array.isArray(ids) ? ids : []) out.push({ collection: table2, objectId, field, relatedId: String(relatedId) });
33076
33236
  }
33077
- if (target === collection) for (const owner of schema.getRelationOwners(table, field, objectId)) out.push({ collection: table, objectId: owner, field, relatedId: objectId });
33237
+ if (target === collection) for (const owner of schema.getRelationOwners(table2, field, objectId)) out.push({ collection: table2, objectId: owner, field, relatedId: objectId });
33078
33238
  }
33079
33239
  return out;
33080
33240
  }
@@ -33089,7 +33249,7 @@ async function linkedIds(ctx, collection, field, id) {
33089
33249
  async function planDelete(ctx, collection, objectId) {
33090
33250
  const rules2 = rulesByTarget(ctx.schema);
33091
33251
  const rels = relations(ctx.schema);
33092
- if (!rules2.has(collection) && !rels.some(([table, , target]) => table === collection || target === collection)) return null;
33252
+ if (!rules2.has(collection) && !rels.some(([table2, , target]) => table2 === collection || target === collection)) return null;
33093
33253
  if (await ctx.count(collection, { objectId }) === 0) return null;
33094
33254
  const key = (c, id) => `${c}\0${id}`;
33095
33255
  const gone = [{ collection, objectId }];
@@ -33210,9 +33370,9 @@ function idOf(v) {
33210
33370
  if (typeof v === "string" && v) return v;
33211
33371
  return void 0;
33212
33372
  }
33213
- function targetOf(ctx, table, field) {
33214
- const col = ctx.schema.getTableSchema(table)?.columns?.find((c) => c.name === field);
33215
- if (!col?.targetClass) throw new Error(`${table}.${field} is not a link the schema knows the target of`);
33373
+ function targetOf(ctx, table2, field) {
33374
+ const col = ctx.schema.getTableSchema(table2)?.columns?.find((c) => c.name === field);
33375
+ if (!col?.targetClass) throw new Error(`${table2}.${field} is not a link the schema knows the target of`);
33216
33376
  return col.targetClass;
33217
33377
  }
33218
33378
  async function dryRunMigration(ctx, plan) {
@@ -33907,7 +34067,8 @@ var init_ParseWireAdapter = __esm({
33907
34067
  runId !== void 0 ? { "X-NodeGX-Run": runId } : {},
33908
34068
  options.headers || {}
33909
34069
  );
33910
- fetch(endpoint + path8, {
34070
+ const send = typeof _noodl_cloudservices !== "undefined" && _noodl_cloudservices.fetch ? _noodl_cloudservices.fetch : fetch;
34071
+ send(endpoint + path8, {
33911
34072
  method: options.method || "GET",
33912
34073
  headers,
33913
34074
  body: JSON.stringify(options.content)
@@ -33962,8 +34123,9 @@ var init_ParseWireAdapter = __esm({
33962
34123
  // P99 HLT-023: pass the server's words on, as `fetch` and the rest do. Dropped here, a
33963
34124
  // refusal that names its cause (the per-run ceiling, a 429 with its class) reached the
33964
34125
  // function as "Failed to query."
33965
- error: function(res) {
33966
- options.error(res && res.error);
34126
+ // P115-HST006-STALEROWS: and the status, so a reader can tell a refusal (403) from a blip.
34127
+ error: function(res, status) {
34128
+ options.error(res && res.error, status);
33967
34129
  }
33968
34130
  });
33969
34131
  }
@@ -35242,8 +35404,8 @@ function savedItemToNeutral(item, resolve5, options) {
35242
35404
  if (isSavedGroup(item)) return savedFilterToNeutral(item, resolve5, options);
35243
35405
  const condition = item;
35244
35406
  const isConnected = condition.valueSource === "connected" && !!condition.valuePortName;
35245
- const resolved2 = isConnected && resolve5 ? resolve5(condition.valuePortName) : void 0;
35246
- const value2 = isConnected ? resolved2 !== void 0 || options.dropUnresolvedConnected ? resolved2 : condition.value : condition.value;
35407
+ const resolved3 = isConnected && resolve5 ? resolve5(condition.valuePortName) : void 0;
35408
+ const value2 = isConnected ? resolved3 !== void 0 || options.dropUnresolvedConnected ? resolved3 : condition.value : condition.value;
35247
35409
  if (condition.kind === "relation") {
35248
35410
  if (value2 === void 0 || value2 === null || value2 === "") return null;
35249
35411
  return {
@@ -37579,7 +37741,8 @@ var init_RestDataAdapter = __esm({
37579
37741
  const total = options.count ? readTotalCount(profile, body, headers, rows.length) : void 0;
37580
37742
  options.success(records, total);
37581
37743
  },
37582
- fail: (message) => options.error(message)
37744
+ fail: (message, status) => options.error(message, status)
37745
+ // P115-HST006-STALEROWS: a refusal is told apart
37583
37746
  }
37584
37747
  );
37585
37748
  }
@@ -39128,8 +39291,19 @@ var require_cloudstore = __commonJS({
39128
39291
  }
39129
39292
  return obj;
39130
39293
  }
39294
+ function _schemaOf(collectionName2) {
39295
+ const collection = collectionName2 !== void 0 ? CloudStore7._collections[collectionName2] : void 0;
39296
+ if (!collection) return void 0;
39297
+ if (collection.schema) return collection.schema;
39298
+ if (!Array.isArray(collection.columns)) return void 0;
39299
+ const properties2 = {};
39300
+ for (const column of collection.columns) {
39301
+ if (column && column.name) properties2[column.name] = { type: column.type, targetClass: column.targetClass };
39302
+ }
39303
+ return { properties: properties2 };
39304
+ }
39131
39305
  function _serializeObject(data, collectionName2, modelScope) {
39132
- if (CloudStore7._collections[collectionName2]) var schema = CloudStore7._collections[collectionName2].schema;
39306
+ var schema = _schemaOf(collectionName2);
39133
39307
  for (var key in data) {
39134
39308
  var _type = schema && schema.properties && schema.properties[key] ? schema.properties[key].type : void 0;
39135
39309
  if (data[key] === void 0 || data[key] === null) {
@@ -39214,14 +39388,14 @@ var require_cloudstore = __commonJS({
39214
39388
  function _fromJSON(item, collectionName2, modelScope) {
39215
39389
  const m = (modelScope || Model27).get(item.objectId);
39216
39390
  m._class = collectionName2;
39217
- if (collectionName2 !== void 0 && CloudStore7._collections[collectionName2] !== void 0)
39218
- var schema = CloudStore7._collections[collectionName2].schema;
39391
+ var schema = _schemaOf(collectionName2);
39219
39392
  for (var key in item) {
39220
39393
  if (key === "objectId" || key === "ACL") continue;
39221
39394
  var _type = schema && schema.properties && schema.properties[key] ? schema.properties[key].type : void 0;
39222
39395
  if (_type === void 0 && item[key] && item[key].__type === "Pointer" && item[key].objectId !== void 0) {
39223
39396
  _type = "Pointer";
39224
39397
  }
39398
+ if (_type === void 0 && (key === "createdAt" || key === "updatedAt")) _type = "Date";
39225
39399
  const value2 = _deserializeJSON(item[key], _type, modelScope);
39226
39400
  if (Array.isArray(value2) && sameList(m.get(key), value2)) continue;
39227
39401
  m.set(key, value2);
@@ -39438,8 +39612,19 @@ function convertVisualFilter(query, options) {
39438
39612
  });
39439
39613
  return Object.keys(where2).length === 0 ? void 0 : where2;
39440
39614
  }
39615
+ function instantOf(operand) {
39616
+ let at;
39617
+ if (operand instanceof Date) at = operand.getTime();
39618
+ else if (operand && operand.__type === "Date" && typeof operand.iso === "string") at = Date.parse(operand.iso);
39619
+ else if (typeof operand === "string") at = Date.parse(operand);
39620
+ return at === void 0 || Number.isNaN(at) ? void 0 : at;
39621
+ }
39441
39622
  function matchesOperator(value2, op, condition) {
39442
39623
  const operand = condition[op];
39624
+ if (value2 instanceof Date && Object.prototype.hasOwnProperty.call(DATE_COMPARISONS, op)) {
39625
+ const at = instantOf(operand);
39626
+ if (at !== void 0) return DATE_COMPARISONS[op](value2.getTime(), at);
39627
+ }
39443
39628
  switch (op) {
39444
39629
  case "$eq":
39445
39630
  return operand && operand.__type === "Pointer" ? value2 === operand.objectId : value2 == operand;
@@ -39518,8 +39703,8 @@ function convertVisualSorting(sorting) {
39518
39703
  }
39519
39704
  function convertFilterOp(filter2, options) {
39520
39705
  try {
39521
- const resolved2 = resolveRelatedClasses(filter2, options.modelScope);
39522
- return toParseWhere(resolved2, {
39706
+ const resolved3 = resolveRelatedClasses(filter2, options.modelScope);
39707
+ return toParseWhere(resolved3, {
39523
39708
  backend: backendType(),
39524
39709
  schema: schemaFor(options.collectionName)
39525
39710
  });
@@ -39531,13 +39716,21 @@ function convertFilterOp(filter2, options) {
39531
39716
  throw e;
39532
39717
  }
39533
39718
  }
39534
- var CloudStore, ModelImport2, Model5;
39719
+ var CloudStore, ModelImport2, Model5, DATE_COMPARISONS;
39535
39720
  var init_queryutils = __esm({
39536
39721
  "../noodl-runtime/src/api/queryutils.ts"() {
39537
39722
  init_translators2();
39538
39723
  CloudStore = require_cloudstore();
39539
39724
  ModelImport2 = require_model2();
39540
39725
  Model5 = ModelImport2;
39726
+ DATE_COMPARISONS = {
39727
+ $eq: (a, b) => a === b,
39728
+ $ne: (a, b) => a !== b,
39729
+ $lt: (a, b) => a < b,
39730
+ $lte: (a, b) => a <= b,
39731
+ $gt: (a, b) => a > b,
39732
+ $gte: (a, b) => a >= b
39733
+ };
39541
39734
  }
39542
39735
  });
39543
39736
 
@@ -40118,8 +40311,9 @@ var require_dbcollectionnode2 = __commonJS({
40118
40311
  this.setCollection(_c);
40119
40312
  this.sendSignalOnOutput("fetched");
40120
40313
  },
40121
- error: (err) => {
40122
- if (this._internal.collection === void 0) this.setCollection(_c);
40314
+ error: (err, status) => {
40315
+ const refused = status === 401 || status === 403;
40316
+ if (refused || this._internal.collection === void 0) this.setCollection(_c);
40123
40317
  this.setError(err || "Failed to fetch.");
40124
40318
  }
40125
40319
  });
@@ -40943,7 +41137,9 @@ var require_dbmodelnode2 = __commonJS({
40943
41137
  includeChangedSignals: true
40944
41138
  }) : [];
40945
41139
  ports.push(...fieldPorts);
40946
- ports.push(...recordWiredFieldPorts(node, fieldPorts, { plug: "output" }));
41140
+ const datePorts = recordBuiltInDatePorts(ctx, fieldPorts, { includeChangedSignals: true });
41141
+ ports.push(...datePorts);
41142
+ ports.push(...recordWiredFieldPorts(node, [...fieldPorts, ...datePorts], { plug: "output" }));
40947
41143
  sendSchemaPorts(editorConnection, node.id, ports, { staticPorts: staticPortNames(ModelNodeDefinition3) });
40948
41144
  }
40949
41145
  var DbModelNodeModule = {
@@ -41514,8 +41710,8 @@ var require_dbmodelcrudbase = __commonJS({
41514
41710
  const store = CloudStore7.forBackend(modelScope, backendId);
41515
41711
  return store ? store.currentUserId() : void 0;
41516
41712
  } else {
41517
- const request = modelScope.get("Request");
41518
- return request.UserId;
41713
+ const request2 = modelScope.get("Request");
41714
+ return request2.UserId;
41519
41715
  }
41520
41716
  }
41521
41717
  function _addAccessControl(def2) {
@@ -45139,6 +45335,7 @@ var require_mapcollectionnode = __commonJS({
45139
45335
  "../noodl-runtime/src/nodes/std-library/data/mapcollectionnode.ts"(exports2, module2) {
45140
45336
  "use strict";
45141
45337
  init_outcome();
45338
+ init_printedcode();
45142
45339
  init_itemsinput();
45143
45340
  var Node17 = require_node2();
45144
45341
  var Collection5 = require_collection();
@@ -45257,7 +45454,7 @@ var require_mapcollectionnode = __commonJS({
45257
45454
  compileMapScript: function(code) {
45258
45455
  this._internal.mapCode = code;
45259
45456
  try {
45260
- this._internal.mapFunc = new Function("map", "object", code);
45457
+ this._internal.mapFunc = compileCode(MAP_COLLECTION_PARAMS, code);
45261
45458
  } catch (e) {
45262
45459
  this._internal.mapFunc = void 0;
45263
45460
  this._internal.mapCompileError = e.message || String(e);
@@ -47744,12 +47941,12 @@ var require_datetostring = __commonJS({
47744
47941
  if (rendered.indexOf(needle) === -1) return;
47745
47942
  rendered = rendered.split(needle).join(render());
47746
47943
  };
47747
- const named2 = (options) => new Intl.DateTimeFormat(locale, zone ? { ...options, timeZone: zone } : options).format(t);
47944
+ const named3 = (options) => new Intl.DateTimeFormat(locale, zone ? { ...options, timeZone: zone } : options).format(t);
47748
47945
  const hours12 = (fields.hours + 11) % 12 + 1;
47749
47946
  const meridiem = fields.hours < 12 ? "am" : "pm";
47750
- substitute("dayName", () => named2({ weekday: "long" }));
47751
- substitute("dayShort", () => named2({ weekday: "short" }));
47752
- substitute("monthName", () => named2({ month: "long" }));
47947
+ substitute("dayName", () => named3({ weekday: "long" }));
47948
+ substitute("dayShort", () => named3({ weekday: "short" }));
47949
+ substitute("monthName", () => named3({ month: "long" }));
47753
47950
  substitute("hours12", () => ("0" + hours12).slice(-2));
47754
47951
  substitute("h12", () => String(hours12));
47755
47952
  substitute("ampm", () => meridiem);
@@ -50437,9 +50634,9 @@ var init_EntityDecoder = __esm({
50437
50634
  replacement = ncrResult;
50438
50635
  tier = LIMIT_TIER_BASE;
50439
50636
  } else {
50440
- const resolved2 = this._resolveName(token);
50441
- replacement = resolved2?.value;
50442
- tier = resolved2?.tier;
50637
+ const resolved3 = this._resolveName(token);
50638
+ replacement = resolved3?.value;
50639
+ tier = resolved3?.tier;
50443
50640
  }
50444
50641
  if (replacement === void 0) {
50445
50642
  i2++;
@@ -51117,7 +51314,7 @@ var init_DocTypeReader = __esm({
51117
51314
  });
51118
51315
 
51119
51316
  // ../../node_modules/anynum/digitTable.js
51120
- var SCRIPT_ZEROS, NOT_DIGIT, HIGH_MAP, LOW_MAX, LOW_MIN, TABLE_OFFSET, TABLE_SIZE, TABLE;
51317
+ var SCRIPT_ZEROS, NOT_DIGIT, HIGH_MAP, LOW_MAX, LOW_MIN, TABLE_OFFSET, TABLE_SIZE, TABLE2;
51121
51318
  var init_digitTable = __esm({
51122
51319
  "../../node_modules/anynum/digitTable.js"() {
51123
51320
  SCRIPT_ZEROS = [
@@ -51257,12 +51454,12 @@ var init_digitTable = __esm({
51257
51454
  LOW_MIN = 1632;
51258
51455
  TABLE_OFFSET = LOW_MIN;
51259
51456
  TABLE_SIZE = LOW_MAX - LOW_MIN + 1;
51260
- TABLE = new Uint8Array(TABLE_SIZE).fill(NOT_DIGIT);
51457
+ TABLE2 = new Uint8Array(TABLE_SIZE).fill(NOT_DIGIT);
51261
51458
  for (const zero of SCRIPT_ZEROS) {
51262
51459
  for (let d = 0; d < 10; d++) {
51263
51460
  const cp = zero + d;
51264
51461
  if (cp <= LOW_MAX) {
51265
- TABLE[cp - TABLE_OFFSET] = d;
51462
+ TABLE2[cp - TABLE_OFFSET] = d;
51266
51463
  } else {
51267
51464
  HIGH_MAP.set(cp, d);
51268
51465
  }
@@ -51300,7 +51497,7 @@ function anynum(str2) {
51300
51497
  }
51301
51498
  continue;
51302
51499
  }
51303
- if (TABLE[cc - TABLE_OFFSET] !== NOT_DIGIT || MINUS_SET.has(cc)) {
51500
+ if (TABLE2[cc - TABLE_OFFSET] !== NOT_DIGIT || MINUS_SET.has(cc)) {
51304
51501
  firstHit = i2;
51305
51502
  break;
51306
51503
  }
@@ -51338,7 +51535,7 @@ function anynum(str2) {
51338
51535
  chars.push("-");
51339
51536
  continue;
51340
51537
  }
51341
- const d = TABLE[cc - TABLE_OFFSET];
51538
+ const d = TABLE2[cc - TABLE_OFFSET];
51342
51539
  chars.push(d !== NOT_DIGIT ? String.fromCharCode(d + 48) : str2[i2]);
51343
51540
  }
51344
51541
  return chars.join("");
@@ -54286,9 +54483,9 @@ function firstOf(...values2) {
54286
54483
  function toISODate(value2) {
54287
54484
  const raw = text(value2).trim().replace(/\s*\([^)]*\)$/, "");
54288
54485
  if (!raw) return null;
54289
- const named2 = /\s([A-Z]{1,5})$/.exec(raw);
54290
- if (named2 && ZONE_NAMES_READ.indexOf(named2[1]) === -1) return null;
54291
- const zoned = !!named2 || /(?:Z|[+-]\d{2}:?\d{2})$/.test(raw);
54486
+ const named3 = /\s([A-Z]{1,5})$/.exec(raw);
54487
+ if (named3 && ZONE_NAMES_READ.indexOf(named3[1]) === -1) return null;
54488
+ const zoned = !!named3 || /(?:Z|[+-]\d{2}:?\d{2})$/.test(raw);
54292
54489
  const asUTC = zoned || /^\d{4}-\d{2}-\d{2}$/.test(raw) ? raw : /^\d{4}-\d{2}-\d{2}T/.test(raw) ? raw + "Z" : raw + " GMT";
54293
54490
  const ms = Date.parse(asUTC);
54294
54491
  return isNaN(ms) ? null : new Date(ms).toISOString();
@@ -57347,9 +57544,9 @@ function captureGroups(m) {
57347
57544
  }
57348
57545
  function namedCaptureGroups(m) {
57349
57546
  const out = {};
57350
- const named2 = m.groups;
57351
- if (named2) {
57352
- for (const key in named2) out[key] = named2[key] === void 0 ? "" : named2[key];
57547
+ const named3 = m.groups;
57548
+ if (named3) {
57549
+ for (const key in named3) out[key] = named3[key] === void 0 ? "" : named3[key];
57353
57550
  }
57354
57551
  return out;
57355
57552
  }
@@ -60947,6 +61144,7 @@ var require_globalstoresubscribenode = __commonJS({
60947
61144
  description: "The watched value: one key gives that key, several give an object of just those keys, none gives the whole store",
60948
61145
  group: "Data",
60949
61146
  getter: function() {
61147
+ if (!this._internal.unsubscribe) return void 0;
60950
61148
  return this.projectValue(globalStoreManager.getState(this._internal.storeName));
60951
61149
  }
60952
61150
  },
@@ -68282,8 +68480,8 @@ function sourceName(el) {
68282
68480
  return label.length > 60 ? label.slice(0, 57) + "\u2026" : label || "item";
68283
68481
  }
68284
68482
  function zoneName(zone, el) {
68285
- const named2 = String(zone._internal.dropZoneName || "").trim();
68286
- if (named2) return named2;
68483
+ const named3 = String(zone._internal.dropZoneName || "").trim();
68484
+ if (named3) return named3;
68287
68485
  const label = el && el.getAttribute("aria-label");
68288
68486
  if (label) return label;
68289
68487
  const all = orderedZones(zone);
@@ -69189,6 +69387,133 @@ var init_tooltips = __esm({
69189
69387
  }
69190
69388
  });
69191
69389
 
69390
+ // ../noodl-viewer-react/src/keyboard-click.ts
69391
+ function holdsPressable(el) {
69392
+ return el.querySelector(PRESSABLE_INSIDE) !== null;
69393
+ }
69394
+ function clickIsWired(node) {
69395
+ if (!node.hasOutput("onClick")) return false;
69396
+ return reachesSomething(node.getOutput("onClick"), 0);
69397
+ }
69398
+ function reachesSomething(output, depth) {
69399
+ if (!output.hasConnections()) return false;
69400
+ if (!Array.isArray(output.connections)) return true;
69401
+ return output.connections.some((c) => !goesNowhere(c, depth));
69402
+ }
69403
+ function goesNowhere(connection, depth) {
69404
+ const target = connection.node;
69405
+ if (!target || target.name !== "Component Outputs" || typeof connection.inputPortName !== "string") return false;
69406
+ const owner = target.nodeScope?.componentOwner;
69407
+ if (!owner || depth > 16 || owner._internal?.creatorCallbacks) return false;
69408
+ if (typeof owner.hasOutput !== "function" || typeof owner.getOutput !== "function") return false;
69409
+ if (!owner.hasOutput(connection.inputPortName)) return true;
69410
+ return !reachesSomething(owner.getOutput(connection.inputPortName), depth + 1);
69411
+ }
69412
+ function isNativelyInteractive(el) {
69413
+ const tag = el.tagName;
69414
+ if (tag === "BUTTON" || tag === "INPUT" || tag === "SELECT" || tag === "TEXTAREA" || tag === "SUMMARY") return true;
69415
+ if ((tag === "A" || tag === "AREA") && el.hasAttribute("href")) return true;
69416
+ if ((tag === "VIDEO" || tag === "AUDIO") && el.hasAttribute("controls")) return true;
69417
+ return el.isContentEditable === true;
69418
+ }
69419
+ function isSpace(e) {
69420
+ return e.key === " " || e.key === "Spacebar";
69421
+ }
69422
+ function isOwnKey(el, e) {
69423
+ return e.target === el && !e.defaultPrevented && !e.altKey && !e.ctrlKey && !e.metaKey && !e.isComposing;
69424
+ }
69425
+ function mark(el) {
69426
+ let spaceArmed = false;
69427
+ const onKeyDown2 = (e) => {
69428
+ if (!isOwnKey(el, e)) return;
69429
+ if (e.key === "Enter") {
69430
+ e.preventDefault();
69431
+ if (!e.repeat) el.click();
69432
+ } else if (isSpace(e)) {
69433
+ e.preventDefault();
69434
+ if (!e.repeat) spaceArmed = true;
69435
+ }
69436
+ };
69437
+ const onKeyUp = (e) => {
69438
+ if (!isSpace(e)) return;
69439
+ const armed = spaceArmed;
69440
+ spaceArmed = false;
69441
+ if (armed && e.target === el && !e.defaultPrevented) el.click();
69442
+ };
69443
+ const m = { el, added: [], onKeyDown: onKeyDown2, onKeyUp, observer: null };
69444
+ if (isNativelyInteractive(el)) return m;
69445
+ refresh(m);
69446
+ if (typeof MutationObserver !== "undefined") {
69447
+ m.observer = new MutationObserver(() => refresh(m));
69448
+ m.observer.observe(el, {
69449
+ childList: true,
69450
+ subtree: true,
69451
+ attributes: true,
69452
+ attributeFilter: ["tabindex", "contenteditable", "href", "controls", "type"]
69453
+ });
69454
+ }
69455
+ return m;
69456
+ }
69457
+ function refresh(m) {
69458
+ const { el } = m;
69459
+ const want = !holdsPressable(el);
69460
+ if (want && !m.added.length) {
69461
+ if (!el.hasAttribute("tabindex")) {
69462
+ el.setAttribute("tabindex", "0");
69463
+ m.added.push("tabindex");
69464
+ }
69465
+ if (!el.hasAttribute("role")) {
69466
+ el.setAttribute("role", "button");
69467
+ m.added.push("role");
69468
+ }
69469
+ if (m.added.length) {
69470
+ el.setAttribute(KEYBOARD_CLICK_ATTRIBUTE, "");
69471
+ m.added.push(KEYBOARD_CLICK_ATTRIBUTE);
69472
+ el.addEventListener("keydown", m.onKeyDown);
69473
+ el.addEventListener("keyup", m.onKeyUp);
69474
+ }
69475
+ } else if (!want && m.added.length) {
69476
+ giveBack(m);
69477
+ }
69478
+ }
69479
+ function giveBack(m) {
69480
+ for (const name2 of m.added) m.el.removeAttribute(name2);
69481
+ m.added = [];
69482
+ m.el.removeEventListener("keydown", m.onKeyDown);
69483
+ m.el.removeEventListener("keyup", m.onKeyUp);
69484
+ }
69485
+ function unmark(m) {
69486
+ m.observer?.disconnect();
69487
+ giveBack(m);
69488
+ }
69489
+ function syncKeyboardClick(node) {
69490
+ const el = typeof node.getDOMElement === "function" ? node.getDOMElement() : null;
69491
+ const want = el && clickIsWired(node) ? el : null;
69492
+ const was = marked.get(node);
69493
+ if (was && was.el === want) return;
69494
+ if (was) {
69495
+ unmark(was);
69496
+ marked.delete(node);
69497
+ }
69498
+ if (want) marked.set(node, mark(want));
69499
+ }
69500
+ var KEYBOARD_CLICK_ATTRIBUTE, PRESSABLE_INSIDE, marked, KEYBOARD_CLICK_HOOKS;
69501
+ var init_keyboard_click = __esm({
69502
+ "../noodl-viewer-react/src/keyboard-click.ts"() {
69503
+ KEYBOARD_CLICK_ATTRIBUTE = "data-ndl-keyboard-click";
69504
+ PRESSABLE_INSIDE = 'button, input:not([type="hidden"]), select, textarea, summary, a[href], area[href], video[controls], audio[controls], [contenteditable=""], [contenteditable="true"], [tabindex]:not([tabindex="-1"])';
69505
+ marked = /* @__PURE__ */ new WeakMap();
69506
+ KEYBOARD_CLICK_HOOKS = {
69507
+ onFirstConnectionAdded() {
69508
+ syncKeyboardClick(this);
69509
+ },
69510
+ onLastConnectionRemoved() {
69511
+ syncKeyboardClick(this);
69512
+ }
69513
+ };
69514
+ }
69515
+ });
69516
+
69192
69517
  // ../noodl-viewer-react/src/node-shared-port-definitions.ts
69193
69518
  function humanCorner(suffix) {
69194
69519
  return suffix.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
@@ -69456,6 +69781,7 @@ var init_node_shared_port_definitions = __esm({
69456
69781
  init_fontloader();
69457
69782
  init_media_source();
69458
69783
  init_tooltips();
69784
+ init_keyboard_click();
69459
69785
  SIZE_MODES = ["explicit", "contentWidth", "contentHeight", "contentSize"];
69460
69786
  node_shared_port_definitions_default = {
69461
69787
  addInputProps: addInputProps2,
@@ -69963,7 +70289,9 @@ var init_node_shared_port_definitions = __esm({
69963
70289
  description: "Fires when this element is clicked or tapped",
69964
70290
  group: "Events",
69965
70291
  type: "signal",
69966
- propPath: "pointer"
70292
+ propPath: "pointer",
70293
+ ...KEYBOARD_CLICK_HOOKS
70294
+ // P121-TWO003-GROUPKEYBOARD: wired, the element is a button to Tab and a screen reader
69967
70295
  },
69968
70296
  pointerDown: {
69969
70297
  displayName: "Pointer Down",
@@ -72561,8 +72889,8 @@ function readColor(value2, depth = 0) {
72561
72889
  const asVar = VAR_FN.exec(text2);
72562
72890
  if (asVar) {
72563
72891
  if (depth >= 8) return null;
72564
- const resolved2 = cssVariableValue(asVar[1]);
72565
- if (resolved2) return readColor(resolved2, depth + 1);
72892
+ const resolved3 = cssVariableValue(asVar[1]);
72893
+ if (resolved3) return readColor(resolved3, depth + 1);
72566
72894
  if (asVar[2] !== void 0) return readColor(asVar[2], depth + 1);
72567
72895
  return null;
72568
72896
  }
@@ -73684,6 +74012,7 @@ function createNodeFromReactComponent(def2) {
73684
74012
  }
73685
74013
  if (element) syncDataAttributesOnElement(this);
73686
74014
  if (element) elementChanged(this, element);
74015
+ syncKeyboardClick(this);
73687
74016
  },
73688
74017
  /**
73689
74018
  * NDA-012 (Visual) check A3 — run an imperative action on the inner React component,
@@ -74110,6 +74439,7 @@ var init_react_component_node = __esm({
74110
74439
  init_mergedeep();
74111
74440
  init_node_shared_port_definitions();
74112
74441
  init_node_transitions();
74442
+ init_keyboard_click();
74113
74443
  ICON_SOURCE_DIAGNOSTIC = "visual/icon-source-not-an-icon";
74114
74444
  DATA_ATTRIBUTE_NAME_PATTERN = "^data-[a-z0-9][a-z0-9._-]*$";
74115
74445
  DATA_ATTRIBUTE_NAME = new RegExp(DATA_ATTRIBUTE_NAME_PATTERN);
@@ -76690,7 +77020,14 @@ var init_TextInput = __esm({
76690
77020
  ref: props.useLabel ? void 0 : noodlRootRef(this.props.noodlNode),
76691
77021
  ...props.useLabel ? void 0 : dataAttributeProps(props.dom),
76692
77022
  style: props.useLabel ? { ...clearedRootStyles(style2), ...inputWrapperStyle } : inputWrapperStyle,
76693
- "noodl-style-tag": "inputWrapper"
77023
+ "noodl-style-tag": "inputWrapper",
77024
+ onMouseDown: (e) => {
77025
+ const field = this.ref.current;
77026
+ if (!field || !props.enabled || e.button !== 0 || field.contains(e.target)) return;
77027
+ e.preventDefault();
77028
+ window.addEventListener("click", preventGlobalFocusChange, true);
77029
+ this.focus();
77030
+ }
76694
77031
  },
76695
77032
  props.useIcon && props.iconPlacement === "left" ? _renderIcon() : null,
76696
77033
  inputContent,
@@ -80880,6 +81217,38 @@ function _typeName(t) {
80880
81217
  if (typeof t === "object") return t.name;
80881
81218
  else return t;
80882
81219
  }
81220
+ function isInsideRow(node, row) {
81221
+ if (node === row) return true;
81222
+ let owner = (node.parentNodeScope || node.nodeScope)?.componentOwner;
81223
+ for (let depth = 0; owner && depth < 64; depth++) {
81224
+ if (owner === row) return true;
81225
+ const next = (owner.parentNodeScope || owner.nodeScope)?.componentOwner;
81226
+ if (next === owner) return false;
81227
+ owner = next;
81228
+ }
81229
+ return false;
81230
+ }
81231
+ function settleRow(context, row) {
81232
+ const self2 = row;
81233
+ for (let pass = 0; pass < 10; pass++) {
81234
+ const dirty = context._dirtyNodes;
81235
+ if (!Array.isArray(dirty)) return;
81236
+ const mine = [];
81237
+ for (let i2 = 0; i2 < dirty.length; i2++) {
81238
+ const node = dirty[i2];
81239
+ if (node && node._dirty && !node._deleted && mine.indexOf(node) === -1 && isInsideRow(node, self2))
81240
+ mine.push(node);
81241
+ }
81242
+ if (mine.length === 0) return;
81243
+ for (let i2 = 0; i2 < mine.length; i2++) {
81244
+ try {
81245
+ mine[i2].update();
81246
+ } catch (e) {
81247
+ console.error(e);
81248
+ }
81249
+ }
81250
+ }
81251
+ }
80883
81252
  var import_react16, import_runtime4, import_collection, import_model5, ITEMS_DIAGNOSTIC, defaultDynamicScript, ForEachDefinition, defaultMapCode, ForEachModule, foreach_default;
80884
81253
  var init_foreach = __esm({
80885
81254
  "../noodl-viewer-react/src/nodes/std-library/data/foreach.tsx"() {
@@ -81253,6 +81622,7 @@ var init_foreach = __esm({
81253
81622
  }
81254
81623
  }
81255
81624
  };
81625
+ settleRow(this.context, itemNode);
81256
81626
  const forEachActions = itemNode.nodeScope.getNodesWithType("For Each Actions");
81257
81627
  for (let j = 0; j < forEachActions.length; j++) {
81258
81628
  forEachActions[j].signalAdded();
@@ -81856,18 +82226,18 @@ function Columns(props) {
81856
82226
  return () => observer.disconnect();
81857
82227
  }, [masonry, children.length, containerWidth]);
81858
82228
  const columnLayout = readColumnLayoutString(props.layoutString);
81859
- const resolved2 = columnLayout === null ? null : resolveColumnLayout(columnLayout, props, containerWidth, children.length);
81860
- const breakpoint = resolved2?.breakpoint ?? "Default";
82229
+ const resolved3 = columnLayout === null ? null : resolveColumnLayout(columnLayout, props, containerWidth, children.length);
82230
+ const breakpoint = resolved3?.breakpoint ?? "Default";
81861
82231
  (0, import_react17.useEffect)(() => {
81862
82232
  props.onBreakpointChanged?.(breakpoint);
81863
82233
  if (breakpoint === "Medium") props.onAtMedium?.();
81864
82234
  else if (breakpoint === "Small") props.onAtSmall?.();
81865
82235
  }, [breakpoint]);
81866
82236
  if (!props.children) return null;
81867
- if (resolved2 === null) {
82237
+ if (resolved3 === null) {
81868
82238
  return /* @__PURE__ */ import_react17.default.createElement(import_react17.default.Fragment, null, props.children);
81869
82239
  }
81870
- const { layout, columnAmount, fractionSize } = resolved2;
82240
+ const { layout, columnAmount, fractionSize } = resolved3;
81871
82241
  columnAmountRef.current = columnAmount;
81872
82242
  const columnLefts = masonry ? computeColumnOffsets(layout, fractionSize) : null;
81873
82243
  const packed = masonry && masonryOffsets !== null && masonryOffsets.tops.length === children.length;
@@ -90070,10 +90440,16 @@ function Text(props) {
90070
90440
  ...pointerProps(props),
90071
90441
  style: style2
90072
90442
  },
90073
- renderableText(props.text)
90443
+ style2.textOverflow === "ellipsis" ? (
90444
+ // P18-S112-FLEXELLIPSIS — the Text is `display: flex` (its default CSS, which Text Vertical Align's `alignItems`
90445
+ // needs), so its words were an anonymous flex item and `text-overflow` on the element drew no "…": Ellipsis
90446
+ // looked the same as Clip. The words go in a block of their own that may shrink to the box and draws the "…";
90447
+ // the element keeps its flex, so both alignments still place them.
90448
+ /* @__PURE__ */ import_react22.default.createElement("span", { style: { ...ELLIPSIS_LINE, overflow: style2.overflow } }, renderableText(props.text))
90449
+ ) : renderableText(props.text)
90074
90450
  );
90075
90451
  }
90076
- var import_react22;
90452
+ var import_react22, ELLIPSIS_LINE;
90077
90453
  var init_Text = __esm({
90078
90454
  "../noodl-viewer-react/src/components/visual/Text/Text.tsx"() {
90079
90455
  import_react22 = __toESM(require_react());
@@ -90081,6 +90457,7 @@ var init_Text = __esm({
90081
90457
  init_layout();
90082
90458
  init_pointerlisteners();
90083
90459
  init_noodl_root_ref();
90460
+ ELLIPSIS_LINE = { minWidth: 0, textOverflow: "ellipsis", whiteSpace: "nowrap" };
90084
90461
  }
90085
90462
  });
90086
90463
 
@@ -90454,7 +90831,6 @@ var init_Video = __esm({
90454
90831
  ...videoProps,
90455
90832
  playsInline: true,
90456
90833
  src,
90457
- ...pointerProps(this.props),
90458
90834
  ref: (video) => {
90459
90835
  this.video = video;
90460
90836
  this.props.innerRef(video);
@@ -90473,7 +90849,7 @@ var init_Video = __esm({
90473
90849
  this.canPlay = false;
90474
90850
  }
90475
90851
  setSourceObject(src) {
90476
- if (this.video.srcObject !== src) {
90852
+ if (this.video && this.video.srcObject !== src) {
90477
90853
  this.video.srcObject = src;
90478
90854
  this.canPlay = false;
90479
90855
  }
@@ -90579,6 +90955,7 @@ var init_Video = __esm({
90579
90955
  CachedVideo,
90580
90956
  {
90581
90957
  ...props.dom,
90958
+ ...pointerProps(this.props),
90582
90959
  className: withDefaultsClass(props.className, defaultsClass),
90583
90960
  style: style2,
90584
90961
  innerRef: (video) => {
@@ -97687,6 +98064,7 @@ var init_parentcomponentobject = __esm({
97687
98064
  */
97688
98065
  nodeScopeDidInitialize() {
97689
98066
  this.context.scheduleAfterUpdate(() => {
98067
+ if (this._deleted) return;
97690
98068
  this._internal.resolutionIsLoud = true;
97691
98069
  this.onComponentStateNodesChanged();
97692
98070
  });
@@ -97812,8 +98190,8 @@ var init_parentcomponentobject = __esm({
97812
98190
  const self2 = this.nodeScope.componentOwner;
97813
98191
  const wanted = this._internal.targetComponent;
97814
98192
  if (wanted) {
97815
- const named2 = findAncestorWithName(self2, wanted);
97816
- if (!named2) {
98193
+ const named3 = findAncestorWithName(self2, wanted);
98194
+ if (!named3) {
97817
98195
  this._internal.parentComponentName = void 0;
97818
98196
  resolvedTargets2.report(this, void 0);
97819
98197
  this.reportMiss("parent-component-object/target-not-found", 'No ancestor component named "' + wanted + '"', {
@@ -97822,7 +98200,7 @@ var init_parentcomponentobject = __esm({
97822
98200
  });
97823
98201
  return;
97824
98202
  }
97825
- if (!COMPONENT_OBJECT_TYPES.some((type) => named2.nodeScope.getNodesWithType(type).length > 0)) {
98203
+ if (!COMPONENT_OBJECT_TYPES.some((type) => named3.nodeScope.getNodesWithType(type).length > 0)) {
97826
98204
  this._internal.parentComponentName = void 0;
97827
98205
  resolvedTargets2.report(this, void 0);
97828
98206
  this.reportMiss(
@@ -97832,11 +98210,11 @@ var init_parentcomponentobject = __esm({
97832
98210
  );
97833
98211
  return;
97834
98212
  }
97835
- this._internal.parentComponentName = named2.name;
98213
+ this._internal.parentComponentName = named3.name;
97836
98214
  this._internal.lastMissCode = void 0;
97837
98215
  this._internal.lastError = void 0;
97838
- resolvedTargets2.report(this, named2.name);
97839
- return "componentState" + named2.getInstanceId();
98216
+ resolvedTargets2.report(this, named3.name);
98217
+ return "componentState" + named3.getInstanceId();
97840
98218
  }
97841
98219
  const parent = findAncestorWithComponentObject(self2);
97842
98220
  if (!parent) {
@@ -98015,22 +98393,22 @@ var init_setparentcomponentobjectproperties = __esm({
98015
98393
  const self2 = this.nodeScope.componentOwner;
98016
98394
  const wanted = this._internal.targetComponent;
98017
98395
  if (wanted) {
98018
- const named2 = findAncestorWithName(self2, wanted);
98019
- if (!named2) {
98396
+ const named3 = findAncestorWithName(self2, wanted);
98397
+ if (!named3) {
98020
98398
  return {
98021
98399
  missCode: "set-parent-component-object-properties/target-not-found",
98022
98400
  missMessage: 'No ancestor component named "' + wanted + '"',
98023
98401
  missDetail: { target: wanted, ancestors: componentAncestorNames(self2) }
98024
98402
  };
98025
98403
  }
98026
- if (!COMPONENT_OBJECT_TYPES.some((type) => named2.nodeScope.getNodesWithType(type).length > 0)) {
98404
+ if (!COMPONENT_OBJECT_TYPES.some((type) => named3.nodeScope.getNodesWithType(type).length > 0)) {
98027
98405
  return {
98028
98406
  missCode: "set-parent-component-object-properties/target-has-no-object",
98029
98407
  missMessage: 'The component "' + wanted + '" has no Component Object node',
98030
98408
  missDetail: { target: wanted }
98031
98409
  };
98032
98410
  }
98033
- return { id: "componentState" + named2.getInstanceId(), name: named2.name };
98411
+ return { id: "componentState" + named3.getInstanceId(), name: named3.name };
98034
98412
  }
98035
98413
  const parent = findAncestorWithComponentObject(self2);
98036
98414
  if (!parent) {
@@ -100335,15 +100713,15 @@ var init_closepopup = __esm({
100335
100713
  const candidates = popups.map((component) => component.name);
100336
100714
  const wanted = this._internal.targetComponent;
100337
100715
  if (wanted) {
100338
- const named2 = popups.find((component) => component.name === wanted);
100339
- if (!named2) {
100716
+ const named3 = popups.find((component) => component.name === wanted);
100717
+ if (!named3) {
100340
100718
  return {
100341
100719
  candidates,
100342
100720
  missCode: "close-popup/target-not-found",
100343
100721
  missMessage: 'This node is not inside a popup named "' + wanted + '"' + (candidates.length ? " \u2014 it is inside: " + candidates.join(", ") : "")
100344
100722
  };
100345
100723
  }
100346
- return { popup: named2, close: named2._popupCloseHandler, candidates };
100724
+ return { popup: named3, close: named3._popupCloseHandler, candidates };
100347
100725
  }
100348
100726
  if (this._internal.closeCallback) {
100349
100727
  return { popup: popups[0], close: this._internal.closeCallback, candidates };
@@ -100755,7 +101133,9 @@ var init_userservice = __esm({
100755
101133
  this.adapter = new ParseAuthAdapter({
100756
101134
  // The module-scope serialiser, exactly as before — `_User` properties have
100757
101135
  // always been serialised against the process-wide Model store.
100758
- serializeObject: (data, collectionName2) => import_cloudstore2.default._serializeObject(data, collectionName2)
101136
+ // P115-HST006-VIEWERTS2554: the third argument (the model scope) is named, undefined, as JavaScript already
101137
+ // passed it: the runtime's generated types declare all three, and the production viewer build type-checks.
101138
+ serializeObject: (data, collectionName2) => import_cloudstore2.default._serializeObject(data, collectionName2, void 0)
100759
101139
  });
100760
101140
  this._bridge(this.adapter);
100761
101141
  if (this._consumeAuthReturn()) return;
@@ -100808,12 +101188,12 @@ var init_userservice = __esm({
100808
101188
  */
100809
101189
  _handle(backendId) {
100810
101190
  if (backendId && backendId !== ACTIVE_BACKEND) {
100811
- const named2 = resolveBackendFromRuntime(backendId);
100812
- return named2 ? named2.handle : void 0;
101191
+ const named3 = resolveBackendFromRuntime(backendId);
101192
+ return named3 ? named3.handle : void 0;
100813
101193
  }
100814
101194
  if (!this.endpoint) {
100815
- const resolved2 = resolveBackendFromRuntime(ACTIVE_BACKEND);
100816
- if (resolved2) return resolved2.handle;
101195
+ const resolved3 = resolveBackendFromRuntime(ACTIVE_BACKEND);
101196
+ if (resolved3) return resolved3.handle;
100817
101197
  }
100818
101198
  return {
100819
101199
  id: "_active_",
@@ -102063,7 +102443,7 @@ var init_signinwith = __esm({
102063
102443
  const tokens = [this.beginOutcome()];
102064
102444
  if (state2.succeeded) {
102065
102445
  this._internal.notice = state2.notice;
102066
- this._internal.error = void 0;
102446
+ this._internal.error = "";
102067
102447
  this.flagOutputDirty("notice");
102068
102448
  this.flagOutputDirty("error");
102069
102449
  reportOutcomes(this, tokens, "done");
@@ -111406,9 +111786,9 @@ var require_fast_uri = __commonJS({
111406
111786
  }
111407
111787
  function resolve5(baseURI, relativeURI, options) {
111408
111788
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
111409
- const resolved2 = resolveComponent(parse(baseURI, schemelessOptions), parse(relativeURI, schemelessOptions), schemelessOptions, true);
111789
+ const resolved3 = resolveComponent(parse(baseURI, schemelessOptions), parse(relativeURI, schemelessOptions), schemelessOptions, true);
111410
111790
  schemelessOptions.skipEscape = true;
111411
- return serialize(resolved2, schemelessOptions);
111791
+ return serialize(resolved3, schemelessOptions);
111412
111792
  }
111413
111793
  function resolveComponent(base, relative3, options, skipNormalization) {
111414
111794
  const target = {};
@@ -114719,7 +115099,7 @@ var require_package = __commonJS({
114719
115099
  "package.json"(exports2, module2) {
114720
115100
  module2.exports = {
114721
115101
  name: "@nodegx/preview",
114722
- version: "0.2.7",
115102
+ version: "0.2.9",
114723
115103
  description: "Standalone live-preview harness: renders a NodeGX (OpenNoodl) v2 project in a browser with no editor process, and reloads it when the files on disk change.",
114724
115104
  license: "GPL-3.0-only",
114725
115105
  homepage: "https://nodegx.io",
@@ -164665,7 +165045,7 @@ var node_catalog_default = {
164665
165045
  "always: the size it holds now, a bare number read in the unit it held; drawn at the next paint"
164666
165046
  ],
164667
165047
  visible: [
164668
- "always: shown or hidden at the next paint, its space kept; hidden, a Focus does not reach it"
165048
+ "always: shown or hidden at once, its space kept; hidden, a Focus does not reach it"
164669
165049
  ]
164670
165050
  },
164671
165051
  warnings: {
@@ -166850,7 +167230,7 @@ var node_catalog_default = {
166850
167230
  "always: the page, or the scrolling Group holding it, scrolls until the box can be seen"
166851
167231
  ],
166852
167232
  visible: [
166853
- "always: shown or hidden at the next paint, its space kept; hidden, a Focus does not reach it"
167233
+ "always: shown or hidden at once, its space kept; hidden, a Focus does not reach it"
166854
167234
  ]
166855
167235
  },
166856
167236
  warnings: {
@@ -169462,7 +169842,7 @@ var node_catalog_default = {
169462
169842
  "always: the size it holds now, a bare number read in the unit it held; drawn at the next paint"
169463
169843
  ],
169464
169844
  visible: [
169465
- "always: shown or hidden at the next paint, its space kept; hidden, a Focus does not reach it"
169845
+ "always: shown or hidden at once, its space kept; hidden, a Focus does not reach it"
169466
169846
  ]
169467
169847
  },
169468
169848
  warnings: {
@@ -171644,7 +172024,7 @@ var node_catalog_default = {
171644
172024
  "always: the page, or the scrolling Group holding it, scrolls until the button can be seen"
171645
172025
  ],
171646
172026
  visible: [
171647
- "always: shown or hidden at the next paint, its space kept; hidden, it takes no click and a Focus does not reach it"
172027
+ "always: shown or hidden at once, its space kept; hidden, it takes no click and a Focus does not reach it"
171648
172028
  ]
171649
172029
  },
171650
172030
  warnings: {
@@ -174049,7 +174429,7 @@ var node_catalog_default = {
174049
174429
  "always: the size it holds now, a bare number read in the unit it held; drawn at the next paint"
174050
174430
  ],
174051
174431
  visible: [
174052
- "always: shown or hidden at the next paint, its space kept; hidden, a Focus does not reach it"
174432
+ "always: shown or hidden at once, its space kept; hidden, a Focus does not reach it"
174053
174433
  ]
174054
174434
  },
174055
174435
  warnings: {
@@ -176919,7 +177299,7 @@ var node_catalog_default = {
176919
177299
  "always: the size it holds now, a bare number read in the unit it held; drawn at the next paint"
176920
177300
  ],
176921
177301
  visible: [
176922
- "always: shown or hidden at the next paint, its space kept; hidden, a Focus does not reach it"
177302
+ "always: shown or hidden at once, its space kept; hidden, a Focus does not reach it"
176923
177303
  ],
176924
177304
  opacity: [
176925
177305
  "always: how see-through it is; at exactly 0 it takes no pointer, and an act goes to what is behind it"
@@ -181761,7 +182141,7 @@ var node_catalog_default = {
181761
182141
  },
181762
182142
  isSignal: false,
181763
182143
  default: false,
181764
- description: "Whether a request with no valid session token is allowed to run this function at all"
182144
+ description: "Whether a request with no valid session token is allowed to run this function at all. A run the app starts itself \u2014 a schedule, a row change, a run from Studio \u2014 is always allowed and sees nobody signed in; a webhook is a request like any other"
181765
182145
  },
181766
182146
  {
181767
182147
  name: "params",
@@ -183818,14 +184198,14 @@ var TOKEN_COOKIE = "nodegx_token";
183818
184198
  function mintToken() {
183819
184199
  return (0, import_node_crypto.randomBytes)(32).toString("hex");
183820
184200
  }
183821
- function resolveAccess(request = {}) {
183822
- const shared = request.share === true;
184201
+ function resolveAccess(request2 = {}) {
184202
+ const shared = request2.share === true;
183823
184203
  return {
183824
- host: shared ? request.host || ALL_INTERFACES : LOOPBACK,
184204
+ host: shared ? request2.host || ALL_INTERFACES : LOOPBACK,
183825
184205
  shared,
183826
184206
  // A shared server always has a token. An unshared one still gets one, so that turning
183827
184207
  // sharing on later cannot find itself without a credential and invent a weaker path.
183828
- token: request.token || mintToken()
184208
+ token: request2.token || mintToken()
183829
184209
  };
183830
184210
  }
183831
184211
  function tokenMatches(candidate, token) {
@@ -183841,15 +184221,15 @@ function isLoopbackAddress(address) {
183841
184221
  if (addr === "::1") return true;
183842
184222
  return /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(addr);
183843
184223
  }
183844
- function tokenFromRequest(request) {
183845
- const headers = request.headers || {};
184224
+ function tokenFromRequest(request2) {
184225
+ const headers = request2.headers || {};
183846
184226
  const header = headers[TOKEN_HEADER];
183847
184227
  if (typeof header === "string" && header.length > 0) return header;
183848
184228
  const auth = headers["authorization"];
183849
184229
  if (typeof auth === "string" && /^Bearer\s+/i.test(auth)) return auth.replace(/^Bearer\s+/i, "");
183850
- if (typeof request.url === "string") {
184230
+ if (typeof request2.url === "string") {
183851
184231
  try {
183852
- const query = new URL(request.url, "http://placeholder.invalid").searchParams.get(TOKEN_QUERY);
184232
+ const query = new URL(request2.url, "http://placeholder.invalid").searchParams.get(TOKEN_QUERY);
183853
184233
  if (query) return query;
183854
184234
  } catch {
183855
184235
  }
@@ -183863,11 +184243,11 @@ function tokenFromRequest(request) {
183863
184243
  }
183864
184244
  return null;
183865
184245
  }
183866
- function authoriseRequest(request, access) {
183867
- if (!access.shared || isLoopbackAddress(request.remoteAddress)) {
184246
+ function authoriseRequest(request2, access) {
184247
+ if (!access.shared || isLoopbackAddress(request2.remoteAddress)) {
183868
184248
  return { ok: true, reason: "loopback", setCookie: null };
183869
184249
  }
183870
- const presented = tokenFromRequest(request);
184250
+ const presented = tokenFromRequest(request2);
183871
184251
  if (presented === null) {
183872
184252
  return { ok: false, reason: "no-token", status: 401, body: UNAUTHORISED_BODY };
183873
184253
  }
@@ -184216,6 +184596,13 @@ var CommentsModel = class extends import_model15.default {
184216
184596
 
184217
184597
  // ../noodl-editor/src/editor/src/models/warningsmodel.ts
184218
184598
  var import_model16 = __toESM(require_model());
184599
+ function sameWarning(a, b) {
184600
+ try {
184601
+ return JSON.stringify(a) === JSON.stringify(b);
184602
+ } catch {
184603
+ return false;
184604
+ }
184605
+ }
184219
184606
  var WarningsModel = class _WarningsModel extends import_model16.default {
184220
184607
  constructor() {
184221
184608
  super();
@@ -184228,13 +184615,23 @@ var WarningsModel = class _WarningsModel extends import_model16.default {
184228
184615
  static {
184229
184616
  this.instance = new _WarningsModel();
184230
184617
  }
184618
+ /**
184619
+ * P132-HIDDENPANELCHURN: a set that changes nothing says nothing. `readNameList` clears its warning on every read,
184620
+ * and the Components panel reads page info (so names) on every `warningsChanged`: when a clear of a warning that was
184621
+ * not there still announced a change, the two fed each other once per `setTimeout(1)`, ~480 times a second, for as
184622
+ * long as a project was open (the panel, the top bar and every mounted dialog re-rendering each time).
184623
+ * The same object set again still announces: its owner may have changed it in place.
184624
+ */
184231
184625
  setWarning(ref, warning) {
184232
184626
  var w = this.getWarningsForRef(ref, warning !== void 0);
184233
184627
  if (!warning) {
184234
- if (w) delete w[ref.key];
184628
+ if (!w || w[ref.key] === void 0) return;
184629
+ delete w[ref.key];
184235
184630
  } else {
184236
184631
  warning.level = warning.level || "warning";
184632
+ const had = w[ref.key];
184237
184633
  w[ref.key] = { ref, warning };
184634
+ if (had && had.warning !== warning && sameWarning(had.warning, warning)) return;
184238
184635
  }
184239
184636
  this.scheduleNotifyChanged();
184240
184637
  }
@@ -185708,8 +186105,8 @@ function renderMarkdown(md) {
185708
186105
  continue;
185709
186106
  }
185710
186107
  if (lines.every((l) => /^\s*>\s?/.test(l))) {
185711
- const quoted = lines.map((l) => l.replace(/^\s*>\s?/, "")).join("\n");
185712
- html.push(`<blockquote>${renderMarkdown(quoted)}</blockquote>`);
186108
+ const quoted2 = lines.map((l) => l.replace(/^\s*>\s?/, "")).join("\n");
186109
+ html.push(`<blockquote>${renderMarkdown(quoted2)}</blockquote>`);
185713
186110
  continue;
185714
186111
  }
185715
186112
  if (lines.every((l) => /^\s*[-*]\s+/.test(l))) {
@@ -189209,11 +189606,11 @@ var TokenResolver = class _TokenResolver {
189209
189606
  }
189210
189607
  const token = this.tokens.get(tokenName);
189211
189608
  if (!token) return void 0;
189212
- const resolved2 = this._resolveValue(token.value, depth);
189213
- if (resolved2 !== void 0) {
189214
- this.cache.set(tokenName, resolved2);
189609
+ const resolved3 = this._resolveValue(token.value, depth);
189610
+ if (resolved3 !== void 0) {
189611
+ this.cache.set(tokenName, resolved3);
189215
189612
  }
189216
- return resolved2;
189613
+ return resolved3;
189217
189614
  }
189218
189615
  /**
189219
189616
  * P102 CMP-001 §3 — resolve every `var()` **inside** a value, so a preview can paint it.
@@ -190891,18 +191288,18 @@ function capabilityProbes() {
190891
191288
  if (!instance) instance = new CapabilityProbeCache({ runner: runProbe });
190892
191289
  return instance;
190893
191290
  }
190894
- async function runProbe(request) {
190895
- switch (request.key) {
191291
+ async function runProbe(request2) {
191292
+ switch (request2.key) {
190896
191293
  case "realtime.subscribe":
190897
- return probeRealtime(request);
191294
+ return probeRealtime(request2);
190898
191295
  case "data.aggregate":
190899
- return probeAggregate(request);
191296
+ return probeAggregate(request2);
190900
191297
  default:
190901
- throw new Error(`No probe implemented for ${request.key}`);
191298
+ throw new Error(`No probe implemented for ${request2.key}`);
190902
191299
  }
190903
191300
  }
190904
- function probeRealtime(request) {
190905
- const url = websocketUrl(request.url, request.probe.path);
191301
+ function probeRealtime(request2) {
191302
+ const url = websocketUrl(request2.url, request2.probe.path);
190906
191303
  return new Promise((resolve5) => {
190907
191304
  let settled = false;
190908
191305
  let socket = null;
@@ -190935,8 +191332,8 @@ function probeRealtime(request) {
190935
191332
  socket.onclose = () => settle({ verdict: "unsupported", at: Date.now(), detail: "the websocket closed without upgrading" });
190936
191333
  });
190937
191334
  }
190938
- async function probeAggregate(request) {
190939
- const response = await fetchWithDeadline(`${request.url}${request.probe.path}`, request.probe.method);
191335
+ async function probeAggregate(request2) {
191336
+ const response = await fetchWithDeadline(`${request2.url}${request2.probe.path}`, request2.probe.method);
190940
191337
  if (!response) return { verdict: "unsupported", at: Date.now(), detail: "the server did not answer" };
190941
191338
  if (response.status !== 200) {
190942
191339
  return { verdict: "unsupported", at: Date.now(), detail: `the server answered ${response.status}` };
@@ -191121,11 +191518,11 @@ var ParameterValueResolver = class {
191121
191518
  * ```
191122
191519
  */
191123
191520
  static toString(paramValue) {
191124
- const resolved2 = this.resolve(paramValue, "display" /* Display */);
191125
- if (typeof resolved2 === "object" && resolved2 !== null) {
191521
+ const resolved3 = this.resolve(paramValue, "display" /* Display */);
191522
+ if (typeof resolved3 === "object" && resolved3 !== null) {
191126
191523
  return "";
191127
191524
  }
191128
- return String(resolved2 ?? "");
191525
+ return String(resolved3 ?? "");
191129
191526
  }
191130
191527
  /**
191131
191528
  * Safely converts any parameter value to a number for display.
@@ -191144,15 +191541,15 @@ var ParameterValueResolver = class {
191144
191541
  * ```
191145
191542
  */
191146
191543
  static toNumber(paramValue) {
191147
- const resolved2 = this.resolve(paramValue, "display" /* Display */);
191148
- if (typeof resolved2 === "object" && resolved2 !== null) {
191544
+ const resolved3 = this.resolve(paramValue, "display" /* Display */);
191545
+ if (typeof resolved3 === "object" && resolved3 !== null) {
191149
191546
  return void 0;
191150
191547
  }
191151
191548
  const rawValue = isExpressionParameter(paramValue) ? paramValue.fallback : paramValue;
191152
191549
  if (rawValue === null || rawValue === void 0) {
191153
191550
  return void 0;
191154
191551
  }
191155
- const num = Number(resolved2);
191552
+ const num = Number(resolved3);
191156
191553
  return isNaN(num) ? void 0 : num;
191157
191554
  }
191158
191555
  /**
@@ -191172,11 +191569,11 @@ var ParameterValueResolver = class {
191172
191569
  * ```
191173
191570
  */
191174
191571
  static toBoolean(paramValue) {
191175
- const resolved2 = this.resolve(paramValue, "display" /* Display */);
191176
- if (typeof resolved2 === "object" && resolved2 !== null) {
191572
+ const resolved3 = this.resolve(paramValue, "display" /* Display */);
191573
+ if (typeof resolved3 === "object" && resolved3 !== null) {
191177
191574
  return false;
191178
191575
  }
191179
- return Boolean(resolved2);
191576
+ return Boolean(resolved3);
191180
191577
  }
191181
191578
  /**
191182
191579
  * Checks if a parameter value is an expression parameter.
@@ -191222,7 +191619,7 @@ var NodeGraphNode = class _NodeGraphNode extends import_model22.default {
191222
191619
  }
191223
191620
  /** Get the label of the node */
191224
191621
  get label() {
191225
- if (!this._label) return this.type.labelForNode(this);
191622
+ if (!this._label) return this.derivedTitle ?? this.type.labelForNode(this);
191226
191623
  return this._label;
191227
191624
  }
191228
191625
  /** Set the label of the node */
@@ -191230,6 +191627,12 @@ var NodeGraphNode = class _NodeGraphNode extends import_model22.default {
191230
191627
  this._label = value2;
191231
191628
  this.notifyListeners("labelChanged");
191232
191629
  }
191630
+ /** Set the derived title. `undefined` clears it. */
191631
+ setDerivedTitle(title) {
191632
+ if (this.derivedTitle === title) return;
191633
+ this.derivedTitle = title;
191634
+ this.notifyListeners("derivedTitleChanged");
191635
+ }
191233
191636
  /** Set the runtime sub-label. `undefined` clears it. */
191234
191637
  setRuntimeSubLabel(subLabel) {
191235
191638
  if (this.runtimeSubLabel === subLabel) return;
@@ -193843,9 +194246,9 @@ function conditionIsUnsatisfied(condition, params) {
193843
194246
  return result2 === false;
193844
194247
  }
193845
194248
  function resolveAgainstDefaults(params, defaults) {
193846
- const resolved2 = { ...defaults };
193847
- for (const [name2, value2] of Object.entries(params)) if (value2 !== void 0) resolved2[name2] = value2;
193848
- return resolved2;
194249
+ const resolved3 = { ...defaults };
194250
+ for (const [name2, value2] of Object.entries(params)) if (value2 !== void 0) resolved3[name2] = value2;
194251
+ return resolved3;
193849
194252
  }
193850
194253
  function conditionForInput(groups, portName) {
193851
194254
  if (!groups) return void 0;
@@ -193884,6 +194287,7 @@ var NUMBER_WITH_UNIT = /^\s*(-?\d+(?:\.\d+)?)\s*(px|%|vw|vh|em|rem|deg|s|ms)\s*$
193884
194287
  function isPlainObject2(value2) {
193885
194288
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
193886
194289
  }
194290
+ var TOKEN_IN_VALUE = /var\(--[A-Za-z0-9_-]+\)/;
193887
194291
  function isTokenReference2(value2) {
193888
194292
  return typeof value2 === "string" && value2.startsWith("var(");
193889
194293
  }
@@ -193955,10 +194359,11 @@ function unitsFormat(type) {
193955
194359
  suggestion: JSON.stringify({ value: Number(parsed[1]), unit: parsed[2] })
193956
194360
  };
193957
194361
  }
194362
+ const token = typeof value2 === "string" ? TOKEN_IN_VALUE.exec(value2)?.[0] : void 0;
193958
194363
  return {
193959
194364
  severity: "error",
193960
- message: `expects a number or { "value", "unit" } object. Got ${describeValue2(value2)}.`,
193961
- suggestion: JSON.stringify({ value: 16, unit: unit2 })
194365
+ message: `expects a number, a { "value", "unit" } object or a var(--token) reference. Got ${describeValue2(value2)}.` + (token ? ` This port takes a token alone, not inside an expression: use ${token}, or add a token that holds the size you want.` : ""),
194366
+ suggestion: JSON.stringify(token ?? { value: 16, unit: unit2 })
193962
194367
  };
193963
194368
  }
193964
194369
  };
@@ -194428,13 +194833,13 @@ function checkParameterValues(nodes, catalog, options) {
194428
194833
  });
194429
194834
  }
194430
194835
  if (dynamicSkips.length > 0) {
194431
- const named2 = dynamicSkips.map((n) => `"${n}"`).join(", ");
194836
+ const named3 = dynamicSkips.map((n) => `"${n}"`).join(", ");
194432
194837
  const rawNote = catalog.dynamicPortNote(node.type) ?? "this node determines ports at runtime";
194433
194838
  const note = /[.!?]$/.test(rawNote.trim()) ? rawNote.trim() : `${rawNote.trim()}.`;
194434
194839
  diagnostics.push({
194435
194840
  code: "dynamic-port-skipped" /* DynamicPortSkipped */,
194436
194841
  severity: "info",
194437
- message: `${dynamicSkips.length === 1 ? "Parameter" : "Parameters"} ${named2} on ${node.type} ${dynamicSkips.length === 1 ? "names" : "name"} no port the catalog can see, and ${dynamicSkips.length === 1 ? "it was" : "they were"} not checked: ` + note + " So this node is unverified by that check rather than verified as correct.",
194842
+ message: `${dynamicSkips.length === 1 ? "Parameter" : "Parameters"} ${named3} on ${node.type} ${dynamicSkips.length === 1 ? "names" : "name"} no port the catalog can see, and ${dynamicSkips.length === 1 ? "it was" : "they were"} not checked: ` + note + " So this node is unverified by that check rather than verified as correct.",
194438
194843
  location: {
194439
194844
  component,
194440
194845
  nodeId: node.id,
@@ -194529,6 +194934,55 @@ function cloudPortMeaning(type, plug) {
194529
194934
  init_scriptfiles();
194530
194935
  var FUNCTION_NODE_TYPE = "JavaScriptFunction";
194531
194936
 
194937
+ // ../noodl-editor/src/editor/src/models/nodelibrary/cloudDynamicPorts.ts
194938
+ init_function_ports();
194939
+ function proplist(parameters, name2) {
194940
+ const value2 = parameters[name2];
194941
+ return Array.isArray(value2) ? value2 : [];
194942
+ }
194943
+ function scriptPortsFromSource(script) {
194944
+ const ports = [];
194945
+ if (typeof script !== "string") return ports;
194946
+ const names = functionScriptPortNames(script);
194947
+ const add = (name2, plug, type, prefix) => {
194948
+ if (ports.some((p) => p.name === prefix + name2 && p.plug === plug)) return;
194949
+ ports.push({ name: prefix + name2, displayName: name2, plug, type, group: plug === "input" ? "Inputs" : "Outputs" });
194950
+ };
194951
+ for (const name2 of names.inputs) add(name2, "input", "*", "in-");
194952
+ for (const name2 of names.signals) add(name2, "output", "signal", "out-");
194953
+ for (const name2 of names.outputs) add(name2, "output", "*", "out-");
194954
+ return ports;
194955
+ }
194956
+ function scriptPortsForNode(node) {
194957
+ const parameters = node.parameters || {};
194958
+ const ports = [];
194959
+ for (const spec of proplist(parameters, "scriptOutputs")) {
194960
+ if (!spec.label) continue;
194961
+ ports.push({
194962
+ name: "out-" + spec.label,
194963
+ displayName: spec.label,
194964
+ plug: "output",
194965
+ type: parameters["outtype-" + spec.label] || "*",
194966
+ group: "Outputs"
194967
+ });
194968
+ }
194969
+ for (const spec of proplist(parameters, "scriptInputs")) {
194970
+ if (!spec.label) continue;
194971
+ ports.push({
194972
+ name: "in-" + spec.label,
194973
+ displayName: spec.label,
194974
+ plug: "input",
194975
+ type: parameters["intype-" + spec.label] || "string",
194976
+ group: "Inputs"
194977
+ });
194978
+ }
194979
+ for (const port of scriptPortsFromSource(parameters["functionScript"])) {
194980
+ if (ports.some((p) => p.name === port.name && p.plug === port.plug)) continue;
194981
+ ports.push(port);
194982
+ }
194983
+ return ports;
194984
+ }
194985
+
194532
194986
  // ../noodl-editor/src/editor/src/validation/functionPorts.ts
194533
194987
  var SCRIPT_NODE_API_MEMBERS = [
194534
194988
  "Inputs",
@@ -194580,8 +195034,8 @@ function parentAxis(parent, catalog) {
194580
195034
  const declared2 = PARENT_MAIN_AXIS[parent.type];
194581
195035
  if (declared2 === void 0) return void 0;
194582
195036
  if (declared2 !== "fromFlexDirection") return declared2;
194583
- const resolved2 = resolveAgainstDefaults(parent.parameters ?? {}, catalog.inputDefaults(parent.type));
194584
- const flexDirection = resolved2["flexDirection"];
195037
+ const resolved3 = resolveAgainstDefaults(parent.parameters ?? {}, catalog.inputDefaults(parent.type));
195038
+ const flexDirection = resolved3["flexDirection"];
194585
195039
  if (flexDirection === "row") return "row";
194586
195040
  if (flexDirection === "column" || flexDirection === void 0) return "column";
194587
195041
  return void 0;
@@ -194784,7 +195238,11 @@ var AUTHORED_BLOCKING_WARNINGS = /* @__PURE__ */ new Set([
194784
195238
  // Bug P121-TWO003-SCRIPTCOMPILE — the runtime's own compile fails, so every Run fails. No benign
194785
195239
  // reading for a graph an agent just wrote; the write said nothing before, and the first person
194786
195240
  // to run the function got "That could not be done."
194787
- "function-script-not-compiled" /* FunctionScriptNotCompiled */
195241
+ "function-script-not-compiled" /* FunctionScriptNotCompiled */,
195242
+ // Bug P127-BKO006-RUNONCHANGEGUESS — a `runOnChange-` name a Function does not have is never read
195243
+ // (2,805 right and 5 wrong over 2,718 Functions, all five agent-written); the message names the
195244
+ // right one.
195245
+ "function-run-on-change-unknown" /* FunctionRunOnChangeUnknown */
194788
195246
  ]);
194789
195247
 
194790
195248
  // ../noodl-editor/src/editor/src/validation/diagnosticExamples.ts
@@ -194924,6 +195382,12 @@ var DIAGNOSTIC_EXAMPLES = [
194924
195382
  code: "function-guards-an-open-collection" /* FunctionGuardsAnOpenCollection */,
194925
195383
  examples: ["cloud-members-can-edit-my-records"],
194926
195384
  why: `the records only a function creates, with the collection's create rule "nobody": the function runs as the system`
195385
+ },
195386
+ // P112-OWN018-FANOUT (ruled 2026-10-27 "Teach it and warn") — the warning carries the chained shape.
195387
+ {
195388
+ code: "condition-reads-a-siblings-change" /* ConditionReadsASiblingsChange */,
195389
+ examples: ["score-then-move-on"],
195390
+ why: "the press evaluating the gate that reads, and that gate's Done evaluating the gate that moves on, so the score is decided first"
194927
195391
  }
194928
195392
  ];
194929
195393
 
@@ -196214,9 +196678,9 @@ var dialogWithoutName = {
196214
196678
  if (typeof accessibleName === "string" && accessibleName.trim() !== "") continue;
196215
196679
  const target = node.parameters?.target;
196216
196680
  if (typeof target !== "string" || target.trim() === "") continue;
196217
- const resolved2 = byName.has(target) ? target : void 0;
196218
- if (resolved2 === void 0) continue;
196219
- if (subtreeHasHeading(resolved2, byName, /* @__PURE__ */ new Set())) continue;
196681
+ const resolved3 = byName.has(target) ? target : void 0;
196682
+ if (resolved3 === void 0) continue;
196683
+ if (subtreeHasHeading(resolved3, byName, /* @__PURE__ */ new Set())) continue;
196220
196684
  diagnostics.push({
196221
196685
  code: "dialog-without-name" /* DialogWithoutName */,
196222
196686
  severity: "warning",
@@ -196398,9 +196862,9 @@ var CODE_PREFIX = "const Script = (typeof Node !== 'undefined')?Node:undefined;\
196398
196862
  var PARAMS2 = ["Inputs", "Outputs", "Noodl", "Component", "Scripts"];
196399
196863
  function functionScriptCompileError(script) {
196400
196864
  try {
196401
- const AsyncFunction = Object.getPrototypeOf(async function() {
196865
+ const AsyncFunction2 = Object.getPrototypeOf(async function() {
196402
196866
  }).constructor;
196403
- new AsyncFunction(...PARAMS2, CODE_PREFIX + script);
196867
+ new AsyncFunction2(...PARAMS2, CODE_PREFIX + script);
196404
196868
  return void 0;
196405
196869
  } catch (e) {
196406
196870
  const message = e instanceof Error ? e.message : String(e);
@@ -196510,6 +196974,156 @@ var functionNeverReruns = {
196510
196974
  }
196511
196975
  };
196512
196976
 
196977
+ // ../noodl-editor/src/editor/src/validation/rules/functionRunOnChangeUnknown.ts
196978
+ var RUN_ON_CHANGE_PREFIX4 = "runOnChange-";
196979
+ var FUNCTION_INPUT_PREFIX = "in-";
196980
+ var functionRunOnChangeUnknown = {
196981
+ code: "function-run-on-change-unknown" /* FunctionRunOnChangeUnknown */,
196982
+ description: "A Function has a Run On Value Change setting under a name it does not have (its boxes are runOnChange-in-<input>).",
196983
+ defaultEnabled: true,
196984
+ run(ctx) {
196985
+ const out = [];
196986
+ for (const { component } of ctx.components) {
196987
+ for (const node of component.nodes) {
196988
+ if (node.type !== FUNCTION_NODE_TYPE || !node.parameters) continue;
196989
+ const guessed = Object.keys(node.parameters).filter(
196990
+ (key) => key.startsWith(RUN_ON_CHANGE_PREFIX4) && !key.startsWith(RUN_ON_CHANGE_PREFIX4 + FUNCTION_INPUT_PREFIX)
196991
+ );
196992
+ if (guessed.length === 0) continue;
196993
+ const inputs = scriptPortsForNode(node).filter((p) => p.plug === "input" && p.name.startsWith(FUNCTION_INPUT_PREFIX)).map((p) => p.name.slice(FUNCTION_INPUT_PREFIX.length));
196994
+ const name2 = node.label ? `"${node.label}"` : "This Function";
196995
+ for (const key of guessed) {
196996
+ const wanted = key.slice(RUN_ON_CHANGE_PREFIX4.length);
196997
+ const input2 = inputs.includes(wanted) ? wanted : nearest(wanted, inputs);
196998
+ const right = input2 !== void 0 ? `${RUN_ON_CHANGE_PREFIX4}${FUNCTION_INPUT_PREFIX}${input2}` : void 0;
196999
+ out.push({
197000
+ code: "function-run-on-change-unknown" /* FunctionRunOnChangeUnknown */,
197001
+ severity: "warning",
197002
+ message: `${name2} has no setting "${key}", so nothing reads it` + (input2 === wanted ? ` and a new "${wanted}" still runs it. ` : ". ") + `A Function's Run On Value Change box for an input is "runOnChange-in-<input>"` + (right ? input2 === wanted ? `: write "${right}".` : `; its script reads no "${wanted}" (the nearest input is "${input2}": "${right}").` : `, and its script reads no inputs.`),
197003
+ location: {
197004
+ component: component.name,
197005
+ nodeId: node.id,
197006
+ nodeType: node.type,
197007
+ nodeLabel: node.label,
197008
+ port: key,
197009
+ plug: "input"
197010
+ },
197011
+ ...right ? { suggestion: `${right}: ${JSON.stringify(node.parameters[key])}` } : {}
197012
+ });
197013
+ }
197014
+ }
197015
+ }
197016
+ return out;
197017
+ }
197018
+ };
197019
+
197020
+ // ../noodl-editor/src/editor/src/validation/rules/conditionReadsASiblingsChange.ts
197021
+ var CONDITION = "Condition";
197022
+ var conditionReadsASiblingsChange = {
197023
+ code: "condition-reads-a-siblings-change" /* ConditionReadsASiblingsChange */,
197024
+ description: "Two Conditions evaluated by one signal, where one's On True or On False changes what the other reads.",
197025
+ defaultEnabled: true,
197026
+ run(ctx) {
197027
+ const out = [];
197028
+ const { catalog } = ctx;
197029
+ for (const { component, nodeById } of ctx.components) {
197030
+ let exclusiveStates = function(a, b) {
197031
+ const stateOf = (gate) => {
197032
+ const c = (incoming.get(gate) ?? []).find((w) => w.toProperty === "condition");
197033
+ return c && nodeById.get(c.fromId)?.type === "States" && c.fromProperty.startsWith("at-") ? c : void 0;
197034
+ };
197035
+ const sa = stateOf(a);
197036
+ const sb = stateOf(b);
197037
+ return !!sa && !!sb && sa.fromId === sb.fromId && sa.fromProperty !== sb.fromProperty;
197038
+ }, feedingValues = function(gate) {
197039
+ const seen = /* @__PURE__ */ new Set();
197040
+ const stack = (incoming.get(gate) ?? []).filter((c) => c.toProperty === "condition").map((c) => c.fromId);
197041
+ while (stack.length > 0) {
197042
+ const id = stack.pop();
197043
+ if (id === gate || seen.has(id)) continue;
197044
+ seen.add(id);
197045
+ if (!passesThrough(id)) continue;
197046
+ const type = nodeById.get(id)?.type;
197047
+ for (const c of incoming.get(id) ?? []) {
197048
+ if (type && catalog.getPort(type, "input", c.toProperty)?.isSignal) continue;
197049
+ stack.push(c.fromId);
197050
+ }
197051
+ }
197052
+ return seen;
197053
+ }, reaches2 = function(gate, targets) {
197054
+ if (targets.size === 0) return false;
197055
+ const seen = /* @__PURE__ */ new Set([gate]);
197056
+ const stack = (outgoing.get(gate) ?? []).map((c) => c.toId);
197057
+ while (stack.length > 0) {
197058
+ const id = stack.pop();
197059
+ if (targets.has(id)) return true;
197060
+ if (seen.has(id)) continue;
197061
+ seen.add(id);
197062
+ if (!passesThrough(id)) continue;
197063
+ for (const c of outgoing.get(id) ?? []) stack.push(c.toId);
197064
+ }
197065
+ return false;
197066
+ };
197067
+ const outgoing = /* @__PURE__ */ new Map();
197068
+ const incoming = /* @__PURE__ */ new Map();
197069
+ for (const c of component.connections) {
197070
+ (outgoing.get(c.fromId) ?? outgoing.set(c.fromId, []).get(c.fromId)).push(c);
197071
+ (incoming.get(c.toId) ?? incoming.set(c.toId, []).get(c.toId)).push(c);
197072
+ }
197073
+ const isCondition = (id) => nodeById.get(id)?.type === CONDITION;
197074
+ const passesThrough = (id) => {
197075
+ const type = nodeById.get(id)?.type;
197076
+ const known = type ? catalog.getNode(type) : void 0;
197077
+ return !!known && !known.isVisual;
197078
+ };
197079
+ const gatesBySource = /* @__PURE__ */ new Map();
197080
+ for (const c of component.connections) {
197081
+ if (c.toProperty !== "eval" || !isCondition(c.toId)) continue;
197082
+ const key = `${c.fromId}\0${c.fromProperty}`;
197083
+ const gates = gatesBySource.get(key) ?? [];
197084
+ if (!gates.includes(c.toId)) gates.push(c.toId);
197085
+ gatesBySource.set(key, gates);
197086
+ }
197087
+ const reported = /* @__PURE__ */ new Set();
197088
+ for (const [key, gates] of gatesBySource) {
197089
+ if (gates.length < 2) continue;
197090
+ const sourceId = key.split("\0")[0];
197091
+ for (const reader of gates) {
197092
+ if (reported.has(reader)) continue;
197093
+ const feeds = feedingValues(reader);
197094
+ for (const writer of gates) {
197095
+ if (writer === reader) continue;
197096
+ if (exclusiveStates(reader, writer)) continue;
197097
+ if (!reaches2(writer, feeds)) continue;
197098
+ reported.add(reader);
197099
+ const r = nodeById.get(reader);
197100
+ const w = nodeById.get(writer);
197101
+ const rName = r.label ? `"${r.label}"` : "This Condition";
197102
+ const wName = w.label ? `"${w.label}"` : "another Condition";
197103
+ const sName = nodeById.get(sourceId)?.label ? `"${nodeById.get(sourceId).label}"` : "the same signal";
197104
+ out.push({
197105
+ code: "condition-reads-a-siblings-change" /* ConditionReadsASiblingsChange */,
197106
+ severity: "warning",
197107
+ message: `${rName} and ${wName} are both evaluated by ${sName}, and what ${wName} does changes what ${rName} reads. ${rName} reads its Condition after that change, whichever order the two are wired in. If it should decide on the value from before, chain them: ${rName}'s Done into ${wName}'s Evaluate, instead of both from ${sName}.`,
197108
+ location: {
197109
+ component: component.name,
197110
+ nodeId: r.id,
197111
+ nodeType: r.type,
197112
+ nodeLabel: r.label,
197113
+ port: "eval",
197114
+ plug: "input"
197115
+ },
197116
+ suggestion: `${r.id}.done \u2192 ${w.id}.eval`
197117
+ });
197118
+ break;
197119
+ }
197120
+ }
197121
+ }
197122
+ }
197123
+ return out;
197124
+ }
197125
+ };
197126
+
196513
197127
  // ../noodl-editor/src/editor/src/validation/rules/layoutFillTraps.ts
196514
197128
  var GROUP = "Group";
196515
197129
  var CONTENT_WIDTH = /* @__PURE__ */ new Set(["contentSize", "contentWidth"]);
@@ -196617,6 +197231,181 @@ var rowOfWordsFillsItsColumn = {
196617
197231
  }
196618
197232
  };
196619
197233
 
197234
+ // ../noodl-editor/src/editor/src/validation/rules/bandWithoutShell.ts
197235
+ var GROUP2 = "Group";
197236
+ var resolved2 = (node, catalog) => resolveAgainstDefaults(node.parameters ?? {}, catalog.inputDefaults(node.type));
197237
+ var named2 = (nodes) => nodes.slice(0, 4).map((n) => n.label ? `"${n.label}"` : n.type).join(", ") + (nodes.length > 4 ? ", \u2026" : "");
197238
+ var isSet2 = (value2) => value2 !== void 0 && value2 !== null && value2 !== "" && value2 !== 0;
197239
+ function isFullWidth(value2) {
197240
+ if (widthIsPercentage(value2) !== true) return false;
197241
+ const n = typeof value2 === "object" && value2 !== null ? value2.value : parseFloat(String(value2));
197242
+ return Number(n) >= 100;
197243
+ }
197244
+ function spans(params) {
197245
+ return isFullWidth(params["width"]) && !isSet2(params["maxWidth"]) && !isSet2(params["paddingLeft"]) && !isSet2(params["paddingRight"]);
197246
+ }
197247
+ var isCard = (params) => isSet2(params["borderRadius"]) || painted(params["borderStyle"]);
197248
+ var SECTION_ELEMENTS = /* @__PURE__ */ new Set(["section", "header", "footer"]);
197249
+ var painted = (value2) => isSet2(value2) && value2 !== "transparent" && value2 !== "none";
197250
+ function isBand(node, catalog) {
197251
+ if (node.type !== GROUP2) return false;
197252
+ const params = resolved2(node, catalog);
197253
+ if (!spans(params)) return false;
197254
+ if ((params["flexDirection"] ?? "column") !== "column") return false;
197255
+ if (params["alignItems"] !== "center") return false;
197256
+ if (params["position"] === "absolute" || params["position"] === "fixed") return false;
197257
+ if (isCard(params)) return false;
197258
+ return isSet2(params["paddingTop"]) || isSet2(params["paddingBottom"]) || painted(params["backgroundColor"]) || painted(params["backgroundGradient"]) || painted(params["backgroundImage"]) || SECTION_ELEMENTS.has(String(params["as"] ?? ""));
197259
+ }
197260
+ var bandWithoutShell = {
197261
+ code: "band-without-shell" /* BandWithoutShell */,
197262
+ description: "A full-width band holds its content directly instead of inside one shell, so the content runs to the window edge.",
197263
+ defaultEnabled: true,
197264
+ run(ctx) {
197265
+ const out = [];
197266
+ for (const { component, nodeById } of ctx.components) {
197267
+ const inFlowChildren2 = (parent) => (parent.children ?? []).map((id) => nodeById.get(id)).filter((n) => {
197268
+ if (!n) return false;
197269
+ if (isComponentRef(n.type)) return true;
197270
+ if (!ctx.catalog.getNode(n.type)?.isVisual) return false;
197271
+ const p = resolved2(n, ctx.catalog);
197272
+ return p["position"] !== "absolute" && p["position"] !== "fixed";
197273
+ });
197274
+ const guarded = (n, depth = 0) => {
197275
+ if (isComponentRef(n.type)) return true;
197276
+ if (n.type !== GROUP2) return false;
197277
+ const p = resolved2(n, ctx.catalog);
197278
+ if (isSet2(p["maxWidth"]) || isSet2(p["paddingLeft"]) || isSet2(p["paddingRight"])) return true;
197279
+ const kids = inFlowChildren2(n);
197280
+ return depth < 4 && kids.length > 0 && kids.every((k) => guarded(k, depth + 1));
197281
+ };
197282
+ for (const band of component.nodes) {
197283
+ if (!isBand(band, ctx.catalog)) continue;
197284
+ let placed = true;
197285
+ for (let up = band.parent ? nodeById.get(band.parent) : void 0; up; up = up.parent ? nodeById.get(up.parent) : void 0) {
197286
+ if (up.type === "Page") break;
197287
+ const p = up.type === GROUP2 ? resolved2(up, ctx.catalog) : void 0;
197288
+ if (!p || !spans(p) || isCard(p)) {
197289
+ placed = false;
197290
+ break;
197291
+ }
197292
+ }
197293
+ if (!placed) continue;
197294
+ const inside = inFlowChildren2(band);
197295
+ if (inside.length === 0) continue;
197296
+ if (inside.some((n) => isBand(n, ctx.catalog))) continue;
197297
+ const bare = inside.filter((n) => !guarded(n));
197298
+ if (bare.length === 0) continue;
197299
+ const what = bare.length === inside.length && inside.length > 1 ? `it holds ${inside.length} things directly (${named2(inside)}) instead of one shell` : `${named2(bare)} ${bare.length === 1 ? "sits" : "sit"} in it outside a shell`;
197300
+ out.push({
197301
+ code: "band-without-shell" /* BandWithoutShell */,
197302
+ severity: "warning",
197303
+ message: `This is a full-width band (a section of the page), but ${what}, so its words and pictures run to the edge of the window on a desktop. Put everything it holds inside ONE Group with the style vocabulary's "shell" look (maxWidth 1200px, paddingLeft and paddingRight var(--space-6), sizeMode contentHeight), and make that Group the band's only child.`,
197304
+ location: {
197305
+ component: component.name,
197306
+ nodeId: band.id,
197307
+ nodeType: band.type,
197308
+ ...band.label ? { nodeLabel: band.label } : {}
197309
+ },
197310
+ suggestion: 'one child Group with the "shell" look'
197311
+ });
197312
+ }
197313
+ }
197314
+ return out;
197315
+ }
197316
+ };
197317
+
197318
+ // ../noodl-editor/src/editor/src/validation/rules/clickAreaHoldsAControl.ts
197319
+ var CONTROL_TYPES = /* @__PURE__ */ new Map([
197320
+ ["net.noodl.controls.button", "Button"],
197321
+ ["net.noodl.controls.textinput", "Text Input"],
197322
+ ["net.noodl.controls.checkbox", "Checkbox"],
197323
+ ["net.noodl.controls.radiobutton", "Radio Button"],
197324
+ ["net.noodl.controls.options", "Dropdown"],
197325
+ ["net.noodl.controls.range", "Slider"]
197326
+ ]);
197327
+ var CLICK = "onClick";
197328
+ var COMPONENT_OUTPUTS = "Component Outputs";
197329
+ var clickWired = (component, node) => component.connections.some((c) => c.fromId === node.id && c.fromProperty === CLICK);
197330
+ function reaches(component, nodeById, node, port, used) {
197331
+ return component.connections.some((c) => {
197332
+ if (c.fromId !== node.id || c.fromProperty !== port) return false;
197333
+ if (nodeById.get(c.toId)?.type !== COMPONENT_OUTPUTS) return true;
197334
+ return used === "all" || used.has(c.toProperty);
197335
+ });
197336
+ }
197337
+ var quoted = (node) => node.label ? ` ("${node.label}")` : "";
197338
+ var clickAreaHoldsAControl = {
197339
+ code: "click-area-holds-a-control" /* ClickAreaHoldsAControl */,
197340
+ description: "An element whose Click is wired holds a control, so the keyboard reaches the control and not the element.",
197341
+ defaultEnabled: true,
197342
+ run(ctx) {
197343
+ const out = [];
197344
+ const byPath = new Map(ctx.components.map((c) => [refToPath(c.component.name), c]));
197345
+ const memo = /* @__PURE__ */ new Map();
197346
+ const componentHolds = (ref, used) => {
197347
+ const path8 = refToPath(ref);
197348
+ const key = `${path8}|${[...used].sort().join(",")}`;
197349
+ if (memo.has(key)) return memo.get(key) ?? null;
197350
+ memo.set(key, null);
197351
+ const entry = byPath.get(path8);
197352
+ let found = null;
197353
+ if (entry) {
197354
+ for (const node of entry.component.nodes) {
197355
+ found = held(node, entry.component, entry.nodeById, used);
197356
+ if (found) break;
197357
+ }
197358
+ }
197359
+ memo.set(key, found);
197360
+ return found;
197361
+ };
197362
+ function held(node, component, nodeById, used) {
197363
+ const control = CONTROL_TYPES.get(node.type);
197364
+ if (control) return `a ${control}${quoted(node)}`;
197365
+ if (reaches(component, nodeById, node, CLICK, used)) {
197366
+ return `${node.label ? `"${node.label}"` : "an element"}, which answers a click of its own`;
197367
+ }
197368
+ if (isComponentRef(node.type)) {
197369
+ const ports = new Set(component.connections.filter((c) => c.fromId === node.id).map((c) => c.fromProperty));
197370
+ const usedHere = new Set([...ports].filter((port) => reaches(component, nodeById, node, port, used)));
197371
+ const inside = componentHolds(node.type, usedHere);
197372
+ if (inside) return `the component ${node.label ? `"${node.label}"` : `"${refToPath(node.type)}"`}, which holds ${inside}`;
197373
+ }
197374
+ return null;
197375
+ }
197376
+ for (const { component, nodeById } of ctx.components) {
197377
+ for (const area of component.nodes) {
197378
+ if (CONTROL_TYPES.has(area.type) || !clickWired(component, area)) continue;
197379
+ if (!ctx.catalog.getNode(area.type)?.isVisual) continue;
197380
+ let inner = null;
197381
+ const stack = [...area.children ?? []];
197382
+ while (stack.length && !inner) {
197383
+ const node = nodeById.get(stack.shift());
197384
+ if (!node) continue;
197385
+ inner = held(node, component, nodeById, "all");
197386
+ stack.push(...node.children ?? []);
197387
+ }
197388
+ if (!inner) continue;
197389
+ const name2 = area.label ? `"${area.label}"` : `This ${ctx.catalog.getNode(area.type)?.displayName ?? area.type}`;
197390
+ out.push({
197391
+ code: "click-area-holds-a-control" /* ClickAreaHoldsAControl */,
197392
+ severity: "info",
197393
+ message: `${name2} answers a click. It holds ${inner}. The Tab key stops on what it holds instead. A person using a keyboard or a screen reader cannot press ${area.label ? name2 : "it"} itself. If its click does something nothing inside it does, give that its own Button.`,
197394
+ location: {
197395
+ component: component.name,
197396
+ nodeId: area.id,
197397
+ nodeType: area.type,
197398
+ ...area.label ? { nodeLabel: area.label } : {},
197399
+ port: CLICK,
197400
+ plug: "output"
197401
+ }
197402
+ });
197403
+ }
197404
+ }
197405
+ return out;
197406
+ }
197407
+ };
197408
+
196620
197409
  // ../noodl-editor/src/editor/src/validation/rules/index.ts
196621
197410
  var ALL_RULES = [
196622
197411
  duplicateNodeId,
@@ -196673,6 +197462,10 @@ var ALL_RULES = [
196673
197462
  // arrangement ones.
196674
197463
  functionScriptNotCompiled,
196675
197464
  functionNeverReruns,
197465
+ functionRunOnChangeUnknown,
197466
+ // P112-OWN018-FANOUT (ruled 2026-10-27 "Teach it and warn") — beside the Function rules: what a graph's signals do in
197467
+ // what order, read from the wires. Two gates off one signal, one changing what the other reads.
197468
+ conditionReadsASiblingsChange,
196676
197469
  repeatedSiblingSubtree,
196677
197470
  // DEF-025 — beside `repeatedSiblingSubtree` because both read the visual
196678
197471
  // tree's arrangement rather than wires: that one asks whether siblings
@@ -196686,10 +197479,15 @@ var ALL_RULES = [
196686
197479
  // against the shipped corpus before they were written — this one is 0 hits
196687
197480
  // on all ten templates.
196688
197481
  dialogWithoutName,
197482
+ // P121-TWO003-NESTEDBUTTON (ruled 2026-10-27) — beside the two above: what a keyboard and a screen reader reach, read
197483
+ // from the arrangement. An info, live, so the Problems panel and an agent's write both say it.
197484
+ clickAreaHoldsAControl,
196689
197485
  // P112-OWN020-PILLWRAP / FILLGROW (ruled 2026-10-26: warn and teach) — a node with no size setting fills its parent,
196690
197486
  // read from the arrangement like the two above, and live so a person sees it while editing.
196691
197487
  contentRowSplitsItsChildren,
196692
197488
  rowOfWordsFillsItsColumn,
197489
+ // P112 OWN-028 AC3 — beside the two above: a band's content outside a shell, read from the arrangement, live.
197490
+ bandWithoutShell,
196693
197491
  oversizedPage,
196694
197492
  // LEG-002 — last, and deliberately: it is the only rule in the set that
196695
197493
  // reports a matter of legibility rather than of correctness, and a reader
@@ -196919,21 +197717,21 @@ function answering(port) {
196919
197717
  });
196920
197718
  }
196921
197719
  async function keepOwnBackend(projectDir, log2) {
196922
- const named2 = namedBackend(projectDir);
196923
- if (!named2) return { first: { state: "none" }, stop: () => void 0 };
197720
+ const named3 = namedBackend(projectDir);
197721
+ if (!named3) return { first: { state: "none" }, stop: () => void 0 };
196924
197722
  const root2 = backendsRoot();
196925
197723
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
196926
197724
  let child = null;
196927
197725
  let stopped = false;
196928
- const recordFile = path6.join(root2, named2.id, "runtime.json");
197726
+ const recordFile = path6.join(root2, named3.id, "runtime.json");
196929
197727
  const writeRecord = (pid, entry, name2) => {
196930
197728
  const record = {
196931
197729
  version: 1,
196932
- backendId: named2.id,
197730
+ backendId: named3.id,
196933
197731
  backendName: name2,
196934
197732
  pid,
196935
- port: named2.port,
196936
- endpoint: named2.endpoint,
197733
+ port: named3.port,
197734
+ endpoint: named3.endpoint,
196937
197735
  entry,
196938
197736
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
196939
197737
  owner: { kind: "preview", pid: process.pid, startedAt, projectDir },
@@ -196952,20 +197750,20 @@ async function keepOwnBackend(projectDir, log2) {
196952
197750
  }
196953
197751
  };
196954
197752
  const look = async () => {
196955
- const configFile = path6.join(root2, named2.id, "config.json");
196956
- if (!fs5.existsSync(configFile)) return { state: "missing", id: named2.id, root: root2 };
196957
- if (child && child.exitCode === null) return { state: "running", id: named2.id, port: named2.port, owner: "this preview" };
196958
- if (await answering(named2.port)) {
197753
+ const configFile = path6.join(root2, named3.id, "config.json");
197754
+ if (!fs5.existsSync(configFile)) return { state: "missing", id: named3.id, root: root2 };
197755
+ if (child && child.exitCode === null) return { state: "running", id: named3.id, port: named3.port, owner: "this preview" };
197756
+ if (await answering(named3.port)) {
196959
197757
  let owner = "another process";
196960
197758
  try {
196961
197759
  owner = JSON.parse(fs5.readFileSync(recordFile, "utf8"))?.owner?.kind ?? owner;
196962
197760
  } catch {
196963
197761
  }
196964
- return { state: "running", id: named2.id, port: named2.port, owner };
197762
+ return { state: "running", id: named3.id, port: named3.port, owner };
196965
197763
  }
196966
197764
  const entry = resolveServiceEntry();
196967
- if (!entry) return { state: "no-service", id: named2.id };
196968
- let name2 = named2.id;
197765
+ if (!entry) return { state: "no-service", id: named3.id };
197766
+ let name2 = named3.id;
196969
197767
  try {
196970
197768
  name2 = JSON.parse(fs5.readFileSync(configFile, "utf8")).name || name2;
196971
197769
  } catch {
@@ -196974,11 +197772,11 @@ async function keepOwnBackend(projectDir, log2) {
196974
197772
  entry,
196975
197773
  "serve",
196976
197774
  "--data-dir",
196977
- path6.join(root2, named2.id),
197775
+ path6.join(root2, named3.id),
196978
197776
  "--port",
196979
- String(named2.port),
197777
+ String(named3.port),
196980
197778
  "--backend-id",
196981
- named2.id,
197779
+ named3.id,
196982
197780
  "--backend-name",
196983
197781
  name2,
196984
197782
  "--parent-pid",
@@ -197009,7 +197807,7 @@ async function keepOwnBackend(projectDir, log2) {
197009
197807
  proc.kill("SIGKILL");
197010
197808
  } catch {
197011
197809
  }
197012
- return { state: "failed", id: named2.id, why: ready };
197810
+ return { state: "failed", id: named3.id, why: ready };
197013
197811
  }
197014
197812
  child = proc;
197015
197813
  writeRecord(proc.pid, entry, name2);
@@ -197017,13 +197815,13 @@ async function keepOwnBackend(projectDir, log2) {
197017
197815
  if (ownRecord()) fs5.rmSync(recordFile, { force: true });
197018
197816
  if (!stopped) log2(` ! the app's backend stopped; looking again in ${HEARTBEAT_MS / 1e3} s`);
197019
197817
  });
197020
- return { state: "started", id: named2.id, port: named2.port, pid: proc.pid };
197818
+ return { state: "started", id: named3.id, port: named3.port, pid: proc.pid };
197021
197819
  };
197022
197820
  const say = (s, quiet) => {
197023
- if (s.state === "started") log2(` \u2713 started the app's backend (${s.id}) on ${named2.endpoint}`);
197821
+ if (s.state === "started") log2(` \u2713 started the app's backend (${s.id}) on ${named3.endpoint}`);
197024
197822
  else if (s.state === "failed") log2(` \u2717 the app's backend (${s.id}) did not start: ${s.why}`);
197025
197823
  else if (quiet) return;
197026
- else if (s.state === "running") log2(` \u2713 the app's backend (${s.id}) is already running on ${named2.endpoint} (${s.owner})`);
197824
+ else if (s.state === "running") log2(` \u2713 the app's backend (${s.id}) is already running on ${named3.endpoint} (${s.owner})`);
197027
197825
  else if (s.state === "missing")
197028
197826
  log2(` ! the app names a backend (${s.id}) that is not on this machine (${s.root}) \u2014 its saves and records will fail`);
197029
197827
  else if (s.state === "no-service") log2(` ! the app names a backend (${s.id}) but this preview has no backend service to start it with`);
@@ -197464,6 +198262,7 @@ function validationWarningLines(state2) {
197464
198262
  if (state2.kind !== "ok" || !state2.report) return [];
197465
198263
  return state2.report.diagnostics.filter((d) => d.severity === "warning").map((d) => `${d.code} in ${d.component}${d.nodeLabel || d.nodeId ? ` (${d.nodeLabel ?? d.nodeId})` : ""}: ${d.message}`);
197466
198264
  }
198265
+ var BACKEND_PREFIX = "/__nodegx/backend";
197467
198266
  var MIME = {
197468
198267
  ".html": "text/html; charset=utf-8",
197469
198268
  ".js": "application/javascript; charset=utf-8",
@@ -197577,6 +198376,10 @@ var PreviewServer = class {
197577
198376
  const url = new URL(req.url ?? "/", "http://localhost");
197578
198377
  const pathname = decodeURIComponent(url.pathname);
197579
198378
  if (pathname === "/__preview/events") return this.serveEvents(req, res);
198379
+ const backendPort = this.sharedBackendPort();
198380
+ if (backendPort && (pathname === BACKEND_PREFIX || pathname.startsWith(BACKEND_PREFIX + "/"))) {
198381
+ return this.proxyToBackend(req, res, backendPort);
198382
+ }
197580
198383
  if (pathname === "/__preview/state") {
197581
198384
  const status = {
197582
198385
  state: this.state,
@@ -197600,7 +198403,11 @@ var PreviewServer = class {
197600
198403
  if (!bundle) return this.notFound(res);
197601
198404
  return this.sendDynamic(res, bundle, "application/json; charset=utf-8");
197602
198405
  }
197603
- if (pathname === "/nodegx-config.json") return this.sendDynamic(res, "{}", "application/json; charset=utf-8");
198406
+ if (pathname === "/nodegx-config.json") {
198407
+ const origin = backendPort ? pageOrigin(req) : null;
198408
+ const config = origin ? { cloudservices: { endpoint: origin + BACKEND_PREFIX } } : {};
198409
+ return this.sendDynamic(res, JSON.stringify(config), "application/json; charset=utf-8");
198410
+ }
197604
198411
  const asset = pathname.slice(1);
197605
198412
  if (DEPLOY_ASSETS.includes(asset)) {
197606
198413
  return this.sendFile(req, res, deployAssetPath(asset));
@@ -197651,6 +198458,46 @@ var PreviewServer = class {
197651
198458
  this.clients.delete(res);
197652
198459
  });
197653
198460
  }
198461
+ /** The backend port a SHARED preview carries, else undefined. */
198462
+ sharedBackendPort() {
198463
+ return this.access.shared && this.options.backendPort ? this.options.backendPort : void 0;
198464
+ }
198465
+ /**
198466
+ * P112-OWN023-PHONEPREVIEW — one request on to the backend on loopback, streamed both ways (its realtime channel is a
198467
+ * long `text/event-stream`). The backend is told where the page reached it (`Host`, `X-Forwarded-Prefix`), so a
198468
+ * File's url it answers with leads back through here; the preview's own token is not passed on.
198469
+ */
198470
+ proxyToBackend(req, res, port) {
198471
+ const raw = req.url ?? "/";
198472
+ const rest2 = raw.slice(BACKEND_PREFIX.length) || "/";
198473
+ const headers = { ...req.headers };
198474
+ delete headers[TOKEN_HEADER];
198475
+ const cookie = withoutCookie(req.headers.cookie, TOKEN_COOKIE);
198476
+ if (cookie) headers.cookie = cookie;
198477
+ else delete headers.cookie;
198478
+ headers["x-forwarded-prefix"] = BACKEND_PREFIX;
198479
+ headers["x-forwarded-proto"] = "http";
198480
+ const peer = req.socket.remoteAddress;
198481
+ if (peer) headers["x-forwarded-for"] = peer;
198482
+ const upstream = http.request(
198483
+ { host: "127.0.0.1", port, method: req.method, path: rest2.startsWith("/") ? rest2 : "/" + rest2, headers },
198484
+ (answer) => {
198485
+ res.writeHead(answer.statusCode ?? 502, answer.headers);
198486
+ answer.pipe(res);
198487
+ }
198488
+ );
198489
+ upstream.on("error", (err) => {
198490
+ if (res.headersSent) {
198491
+ res.destroy(err);
198492
+ return;
198493
+ }
198494
+ res.writeHead(502, { "content-type": "text/plain; charset=utf-8", "cache-control": "no-store" });
198495
+ res.end(`The app's backend on this computer (port ${port}) did not answer: ${err.message}
198496
+ `);
198497
+ });
198498
+ res.on("close", () => upstream.destroy());
198499
+ req.pipe(upstream);
198500
+ }
197654
198501
  sendJson(res, body) {
197655
198502
  this.sendDynamic(res, JSON.stringify(body, null, 2), "application/json; charset=utf-8");
197656
198503
  }
@@ -197695,6 +198542,15 @@ var PreviewServer = class {
197695
198542
  res.end("Not found");
197696
198543
  }
197697
198544
  };
198545
+ function pageOrigin(req) {
198546
+ const host = String(req.headers.host || "");
198547
+ return /^[A-Za-z0-9.\-[\]:]+$/.test(host) ? `http://${host}` : null;
198548
+ }
198549
+ function withoutCookie(header, name2) {
198550
+ if (!header) return void 0;
198551
+ const kept = header.split(";").map((part) => part.trim()).filter((part) => part && part.split("=")[0].trim() !== name2);
198552
+ return kept.length ? kept.join("; ") : void 0;
198553
+ }
197698
198554
 
197699
198555
  // src/watcher.ts
197700
198556
  var import_chokidar = __toESM(require("chokidar"));
@@ -197747,6 +198603,7 @@ Options:
197747
198603
  --port <n> Port to listen on (default 8575, 0 for any free port).
197748
198604
  --host <addr> Address to bind (default 127.0.0.1). Any address but loopback also turns
197749
198605
  on the token: the printed URL carries it, and without it nothing is served.
198606
+ A phone on the same Wi-Fi then reaches the app's own backend through it too.
197750
198607
  --token <t> Use this token rather than minting one.
197751
198608
  --debounce <ms> Quiet period before rebuilding after a change (default 120).
197752
198609
  --no-watch Render once and serve; do not watch for changes.
@@ -197860,7 +198717,8 @@ async function main() {
197860
198717
  log(`noodl-preview \u2014 ${dir} (${format}), ${types} node types`);
197861
198718
  const shared = args.host !== "127.0.0.1" && args.host !== "localhost";
197862
198719
  const access = resolveAccess({ share: shared, host: args.host, token: args.token });
197863
- const server = new PreviewServer({ projectDir: dir, port: args.port, host: args.host, access });
198720
+ const backendPort = format === "v2" ? namedBackend(dir)?.port : void 0;
198721
+ const server = new PreviewServer({ projectDir: dir, port: args.port, host: args.host, access, backendPort });
197864
198722
  let port;
197865
198723
  try {
197866
198724
  port = await server.listen();