@syntrologie/runtime-sdk 2.4.0-canary.18 → 2.4.0-canary.19

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.
Files changed (36) hide show
  1. package/dist/actions/schema.d.ts +7256 -384
  2. package/dist/actions/schema.js +2 -2
  3. package/dist/actions/types.d.ts +7 -0
  4. package/dist/anchor/AnchorResolver.d.ts +18 -0
  5. package/dist/anchor/index.d.ts +2 -0
  6. package/dist/{chunk-LZLDT5DA.js → chunk-LR5AA5SE.js} +2 -2
  7. package/dist/{chunk-NR57IT54.js → chunk-LRN3K2VD.js} +282 -100
  8. package/dist/chunk-LRN3K2VD.js.map +7 -0
  9. package/dist/{chunk-4NYS7GAW.js → chunk-P5G4KT2U.js} +39 -6
  10. package/dist/chunk-P5G4KT2U.js.map +7 -0
  11. package/dist/config/schema.d.ts +448 -40
  12. package/dist/config/schema.js +1 -1
  13. package/dist/context/schema.d.ts +8 -8
  14. package/dist/decisions/schema.d.ts +424 -1408
  15. package/dist/decisions/schema.js +5 -1
  16. package/dist/decisions/types.d.ts +22 -0
  17. package/dist/events/registerConfigPredicates.d.ts +6 -10
  18. package/dist/events/schema.d.ts +8 -8
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.js +9 -77
  21. package/dist/index.js.map +3 -3
  22. package/dist/overlays/schema.d.ts +22 -22
  23. package/dist/react.js +3 -3
  24. package/dist/runtime.d.ts +3 -0
  25. package/dist/smart-canvas.esm.js +36 -37
  26. package/dist/smart-canvas.esm.js.map +4 -4
  27. package/dist/smart-canvas.js +318 -177
  28. package/dist/smart-canvas.js.map +4 -4
  29. package/dist/smart-canvas.min.js +36 -37
  30. package/dist/smart-canvas.min.js.map +4 -4
  31. package/dist/version.d.ts +1 -1
  32. package/package.json +7 -7
  33. package/schema/canvas-config.schema.json +996 -56
  34. package/dist/chunk-4NYS7GAW.js.map +0 -7
  35. package/dist/chunk-NR57IT54.js.map +0 -7
  36. /package/dist/{chunk-LZLDT5DA.js.map → chunk-LR5AA5SE.js.map} +0 -0
@@ -12767,7 +12767,7 @@ var SyntrologieSDK = (() => {
12767
12767
  ANIMATION_KEYFRAMES: () => ANIMATION_KEYFRAMES,
12768
12768
  ActivationConfigZ: () => ActivationConfigZ,
12769
12769
  AddClassZ: () => AddClassZ,
12770
- AnchorIdZ: () => AnchorIdZ,
12770
+ AnchorIdZ: () => AnchorIdZ2,
12771
12771
  AnchorStateZ: () => AnchorStateZ,
12772
12772
  AnchorVisibleConditionZ: () => AnchorVisibleConditionZ,
12773
12773
  AppRegistry: () => AppRegistry,
@@ -12780,6 +12780,7 @@ var SyntrologieSDK = (() => {
12780
12780
  ConditionZ: () => ConditionZ,
12781
12781
  ContextManager: () => ContextManager,
12782
12782
  CooldownActiveConditionZ: () => CooldownActiveConditionZ,
12783
+ CounterDefZ: () => CounterDefZ,
12783
12784
  CtaButtonZ: () => CtaButtonZ,
12784
12785
  DEFAULT_COOLDOWN: () => DEFAULT_COOLDOWN,
12785
12786
  DEFAULT_TTL: () => DEFAULT_TTL,
@@ -12801,6 +12802,7 @@ var SyntrologieSDK = (() => {
12801
12802
  InsertHtmlZ: () => InsertHtmlZ,
12802
12803
  InsertPositionZ: () => InsertPositionZ,
12803
12804
  MAX_VISIBLE_TOASTS: () => MAX_VISIBLE_TOASTS,
12805
+ MatchOpZ: () => MatchOpZ,
12804
12806
  ModalContentZ: () => ModalContentZ,
12805
12807
  ModalZ: () => ModalZ,
12806
12808
  ModelStrategyZ: () => ModelStrategyZ,
@@ -12869,6 +12871,7 @@ var SyntrologieSDK = (() => {
12869
12871
  contentRuntime: () => runtime,
12870
12872
  coreActionStepSchemas: () => coreActionStepSchemas,
12871
12873
  createActionEngine: () => createActionEngine,
12874
+ createAnchorResolver: () => createAnchorResolver,
12872
12875
  createAppContext: () => createAppContext,
12873
12876
  createAppLoader: () => createAppLoader,
12874
12877
  createCanvasConfigFetcher: () => createCanvasConfigFetcher,
@@ -13068,9 +13071,12 @@ var SyntrologieSDK = (() => {
13068
13071
 
13069
13072
  // ../adaptives/adaptive-content/dist/runtime.js
13070
13073
  var executeInsertHtml = async (action, context) => {
13071
- const anchorEl = context.resolveAnchor(action.anchorId);
13074
+ let anchorEl = context.resolveAnchor(action.anchorId);
13075
+ if (!anchorEl && context.waitForAnchor) {
13076
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
13077
+ }
13072
13078
  if (!anchorEl) {
13073
- console.error(`[adaptive-content] Anchor not found for insertHtml, skipping: ${action.anchorId.selector}`);
13079
+ console.warn(`[adaptive-content] Anchor not found after waiting: ${action.anchorId.selector}`);
13074
13080
  return { cleanup: () => {
13075
13081
  } };
13076
13082
  }
@@ -13144,9 +13150,12 @@ var SyntrologieSDK = (() => {
13144
13150
  };
13145
13151
  };
13146
13152
  var executeSetText = async (action, context) => {
13147
- const anchorEl = context.resolveAnchor(action.anchorId);
13153
+ let anchorEl = context.resolveAnchor(action.anchorId);
13154
+ if (!anchorEl && context.waitForAnchor) {
13155
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
13156
+ }
13148
13157
  if (!anchorEl) {
13149
- console.error(`[adaptive-content] Anchor not found for setText, skipping: ${action.anchorId.selector}`);
13158
+ console.warn(`[adaptive-content] Anchor not found after waiting: ${action.anchorId.selector}`);
13150
13159
  return { cleanup: () => {
13151
13160
  } };
13152
13161
  }
@@ -13169,9 +13178,12 @@ var SyntrologieSDK = (() => {
13169
13178
  };
13170
13179
  };
13171
13180
  var executeSetAttr = async (action, context) => {
13172
- const anchorEl = context.resolveAnchor(action.anchorId);
13181
+ let anchorEl = context.resolveAnchor(action.anchorId);
13182
+ if (!anchorEl && context.waitForAnchor) {
13183
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
13184
+ }
13173
13185
  if (!anchorEl) {
13174
- console.error(`[adaptive-content] Anchor not found for setAttr, skipping: ${action.anchorId.selector}`);
13186
+ console.warn(`[adaptive-content] Anchor not found after waiting: ${action.anchorId.selector}`);
13175
13187
  return { cleanup: () => {
13176
13188
  } };
13177
13189
  }
@@ -13211,9 +13223,12 @@ var SyntrologieSDK = (() => {
13211
13223
  };
13212
13224
  };
13213
13225
  var executeAddClass = async (action, context) => {
13214
- const anchorEl = context.resolveAnchor(action.anchorId);
13226
+ let anchorEl = context.resolveAnchor(action.anchorId);
13227
+ if (!anchorEl && context.waitForAnchor) {
13228
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
13229
+ }
13215
13230
  if (!anchorEl) {
13216
- console.error(`[adaptive-content] Anchor not found for addClass, skipping: ${action.anchorId.selector}`);
13231
+ console.warn(`[adaptive-content] Anchor not found after waiting: ${action.anchorId.selector}`);
13217
13232
  return { cleanup: () => {
13218
13233
  } };
13219
13234
  }
@@ -13234,9 +13249,12 @@ var SyntrologieSDK = (() => {
13234
13249
  };
13235
13250
  };
13236
13251
  var executeRemoveClass = async (action, context) => {
13237
- const anchorEl = context.resolveAnchor(action.anchorId);
13252
+ let anchorEl = context.resolveAnchor(action.anchorId);
13253
+ if (!anchorEl && context.waitForAnchor) {
13254
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
13255
+ }
13238
13256
  if (!anchorEl) {
13239
- console.error(`[adaptive-content] Anchor not found for removeClass, skipping: ${action.anchorId.selector}`);
13257
+ console.warn(`[adaptive-content] Anchor not found after waiting: ${action.anchorId.selector}`);
13240
13258
  return { cleanup: () => {
13241
13259
  } };
13242
13260
  }
@@ -13257,9 +13275,12 @@ var SyntrologieSDK = (() => {
13257
13275
  };
13258
13276
  };
13259
13277
  var executeSetStyle = async (action, context) => {
13260
- const anchorEl = context.resolveAnchor(action.anchorId);
13278
+ let anchorEl = context.resolveAnchor(action.anchorId);
13279
+ if (!anchorEl && context.waitForAnchor) {
13280
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
13281
+ }
13261
13282
  if (!anchorEl) {
13262
- console.error(`[adaptive-content] Anchor not found for setStyle, skipping: ${action.anchorId.selector}`);
13283
+ console.warn(`[adaptive-content] Anchor not found after waiting: ${action.anchorId.selector}`);
13263
13284
  return { cleanup: () => {
13264
13285
  } };
13265
13286
  }
@@ -16732,9 +16753,12 @@ var SyntrologieSDK = (() => {
16732
16753
 
16733
16754
  // ../adaptives/adaptive-overlays/dist/runtime.js
16734
16755
  var executeHighlight = async (action, context) => {
16735
- const anchorEl = context.resolveAnchor(action.anchorId);
16756
+ let anchorEl = context.resolveAnchor(action.anchorId);
16757
+ if (!anchorEl && context.waitForAnchor) {
16758
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
16759
+ }
16736
16760
  if (!anchorEl) {
16737
- console.error(`[adaptive-overlays] Anchor not found for highlight, skipping: ${action.anchorId.selector}`);
16761
+ console.warn(`[adaptive-overlays] Anchor not found after waiting: ${action.anchorId.selector}`);
16738
16762
  return { cleanup: () => {
16739
16763
  } };
16740
16764
  }
@@ -16759,9 +16783,12 @@ var SyntrologieSDK = (() => {
16759
16783
  };
16760
16784
  };
16761
16785
  var executePulse = async (action, context) => {
16762
- const anchorEl = context.resolveAnchor(action.anchorId);
16786
+ let anchorEl = context.resolveAnchor(action.anchorId);
16787
+ if (!anchorEl && context.waitForAnchor) {
16788
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
16789
+ }
16763
16790
  if (!anchorEl) {
16764
- console.error(`[adaptive-overlays] Anchor not found for pulse, skipping: ${action.anchorId.selector}`);
16791
+ console.warn(`[adaptive-overlays] Anchor not found after waiting: ${action.anchorId.selector}`);
16765
16792
  return { cleanup: () => {
16766
16793
  } };
16767
16794
  }
@@ -16803,9 +16830,12 @@ var SyntrologieSDK = (() => {
16803
16830
  };
16804
16831
  };
16805
16832
  var executeBadge = async (action, context) => {
16806
- const anchorEl = context.resolveAnchor(action.anchorId);
16833
+ let anchorEl = context.resolveAnchor(action.anchorId);
16834
+ if (!anchorEl && context.waitForAnchor) {
16835
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
16836
+ }
16807
16837
  if (!anchorEl) {
16808
- console.error(`[adaptive-overlays] Anchor not found for badge, skipping: ${action.anchorId.selector}`);
16838
+ console.warn(`[adaptive-overlays] Anchor not found after waiting: ${action.anchorId.selector}`);
16809
16839
  return { cleanup: () => {
16810
16840
  } };
16811
16841
  }
@@ -16867,9 +16897,12 @@ var SyntrologieSDK = (() => {
16867
16897
  };
16868
16898
  };
16869
16899
  var executeTooltip = async (action, context) => {
16870
- const anchorEl = context.resolveAnchor(action.anchorId);
16900
+ let anchorEl = context.resolveAnchor(action.anchorId);
16901
+ if (!anchorEl && context.waitForAnchor) {
16902
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
16903
+ }
16871
16904
  if (!anchorEl) {
16872
- console.error(`[adaptive-overlays] Anchor not found for tooltip, skipping: ${action.anchorId.selector}`);
16905
+ console.warn(`[adaptive-overlays] Anchor not found after waiting: ${action.anchorId.selector}`);
16873
16906
  return { cleanup: () => {
16874
16907
  } };
16875
16908
  }
@@ -18232,41 +18265,6 @@ var SyntrologieSDK = (() => {
18232
18265
  forceUpdate();
18233
18266
  });
18234
18267
  }, [runtime7.accumulator]);
18235
- (0, import_react4.useEffect)(() => {
18236
- if (!config.scope || !runtime7.accumulator?.register)
18237
- return;
18238
- const { events: eventNames, urlContains, props: propFilters } = config.scope;
18239
- const keys = /* @__PURE__ */ new Set();
18240
- for (const action of config.actions) {
18241
- if (action.triggerWhen?.type === "rules") {
18242
- for (const rule of action.triggerWhen.rules) {
18243
- for (const cond of rule.conditions) {
18244
- if (cond.type === "event_count" && cond.key) {
18245
- keys.add(cond.key);
18246
- }
18247
- }
18248
- }
18249
- }
18250
- }
18251
- for (const key of keys) {
18252
- runtime7.accumulator.register(key, (event) => {
18253
- if (!eventNames.includes(event.name))
18254
- return false;
18255
- if (urlContains) {
18256
- const pathname = String(event.props?.pathname ?? "");
18257
- if (!pathname.includes(urlContains))
18258
- return false;
18259
- }
18260
- if (propFilters) {
18261
- for (const [k2, v2] of Object.entries(propFilters)) {
18262
- if (event.props?.[k2] !== v2)
18263
- return false;
18264
- }
18265
- }
18266
- return true;
18267
- });
18268
- }
18269
- }, [config.scope, config.actions, runtime7.accumulator]);
18270
18268
  (0, import_react4.useEffect)(() => {
18271
18269
  if (!runtime7.events.subscribe)
18272
18270
  return;
@@ -18725,41 +18723,6 @@ var SyntrologieSDK = (() => {
18725
18723
  forceUpdate();
18726
18724
  });
18727
18725
  }, [runtime7.accumulator]);
18728
- (0, import_react5.useEffect)(() => {
18729
- if (!config.scope || !runtime7.accumulator?.register)
18730
- return;
18731
- const { events: eventNames, urlContains, props: propFilters } = config.scope;
18732
- const keys = /* @__PURE__ */ new Set();
18733
- for (const action of config.actions) {
18734
- if (action.triggerWhen?.type === "rules") {
18735
- for (const rule of action.triggerWhen.rules) {
18736
- for (const cond of rule.conditions) {
18737
- if (cond.type === "event_count" && cond.key) {
18738
- keys.add(cond.key);
18739
- }
18740
- }
18741
- }
18742
- }
18743
- }
18744
- for (const key of keys) {
18745
- runtime7.accumulator.register(key, (event) => {
18746
- if (!eventNames.includes(event.name))
18747
- return false;
18748
- if (urlContains) {
18749
- const pathname = String(event.props?.pathname ?? "");
18750
- if (!pathname.includes(urlContains))
18751
- return false;
18752
- }
18753
- if (propFilters) {
18754
- for (const [k2, v2] of Object.entries(propFilters)) {
18755
- if (event.props?.[k2] !== v2)
18756
- return false;
18757
- }
18758
- }
18759
- return true;
18760
- });
18761
- }
18762
- }, [config.scope, config.actions, runtime7.accumulator]);
18763
18726
  const visibleTips = (0, import_react5.useMemo)(() => config.actions.filter((tip) => {
18764
18727
  if (!tip.triggerWhen)
18765
18728
  return true;
@@ -19151,7 +19114,7 @@ var SyntrologieSDK = (() => {
19151
19114
  }
19152
19115
 
19153
19116
  // src/version.ts
19154
- var SDK_VERSION = "2.4.0-canary.18";
19117
+ var SDK_VERSION = "2.4.0-canary.19";
19155
19118
 
19156
19119
  // src/types.ts
19157
19120
  var SDK_SCHEMA_VERSION = "2.0";
@@ -19509,56 +19472,66 @@ var SyntrologieSDK = (() => {
19509
19472
  };
19510
19473
 
19511
19474
  // src/events/registerConfigPredicates.ts
19475
+ var ELEMENT_CHAIN_FIELDS = /* @__PURE__ */ new Set(["tag_name", "$el_text"]);
19476
+ function isElementChainField(key) {
19477
+ return ELEMENT_CHAIN_FIELDS.has(key) || key.startsWith("attr__");
19478
+ }
19479
+ function checkMatchOp(op, value) {
19480
+ if (op.equals !== void 0) {
19481
+ return value === op.equals;
19482
+ }
19483
+ if (op.contains !== void 0) {
19484
+ return typeof value === "string" && value.includes(op.contains);
19485
+ }
19486
+ return false;
19487
+ }
19488
+ function buildPredicate(counter) {
19489
+ const { events: eventNames, match } = counter;
19490
+ return (event) => {
19491
+ if (!eventNames.includes(event.name)) return false;
19492
+ if (match) {
19493
+ for (const [key, op] of Object.entries(match)) {
19494
+ if (isElementChainField(key)) {
19495
+ const elements2 = event.props?.elements;
19496
+ if (!elements2) return false;
19497
+ const anyMatch = elements2.some((el) => checkMatchOp(op, el[key]));
19498
+ if (!anyMatch) return false;
19499
+ } else {
19500
+ if (!checkMatchOp(op, event.props?.[key])) return false;
19501
+ }
19502
+ }
19503
+ }
19504
+ return true;
19505
+ };
19506
+ }
19507
+ function registerFromTriggerWhen(triggerWhen, accumulator) {
19508
+ for (const rule of triggerWhen.rules) {
19509
+ for (const cond of rule.conditions) {
19510
+ if (cond.type === "event_count" && cond.key) {
19511
+ const counter = cond.counter;
19512
+ const predicate = counter ? buildPredicate(counter) : () => true;
19513
+ accumulator.register(cond.key, predicate);
19514
+ }
19515
+ }
19516
+ }
19517
+ }
19512
19518
  function registerConfigPredicates(tiles, accumulator, actions) {
19513
19519
  for (const tile of tiles) {
19514
19520
  const props = tile.props;
19515
19521
  if (!props) continue;
19516
- const scope = props.scope;
19517
- if (!scope?.events) continue;
19518
19522
  const tileActions = props.actions;
19519
19523
  if (!tileActions) continue;
19520
- const keys = /* @__PURE__ */ new Set();
19521
19524
  for (const action of tileActions) {
19522
19525
  if (action.triggerWhen?.type === "rules") {
19523
- for (const rule of action.triggerWhen.rules) {
19524
- for (const cond of rule.conditions) {
19525
- if (cond.type === "event_count" && cond.key) {
19526
- keys.add(cond.key);
19527
- }
19528
- }
19529
- }
19526
+ registerFromTriggerWhen(action.triggerWhen, accumulator);
19530
19527
  }
19531
19528
  }
19532
- if (keys.size === 0) continue;
19533
- const { events: eventNames, urlContains, props: propFilters } = scope;
19534
- for (const key of keys) {
19535
- accumulator.register(key, (event) => {
19536
- if (!eventNames.includes(event.name)) return false;
19537
- if (urlContains) {
19538
- const pathname = String(event.props?.pathname ?? "");
19539
- if (!pathname.includes(urlContains)) return false;
19540
- }
19541
- if (propFilters) {
19542
- for (const [k2, v2] of Object.entries(propFilters)) {
19543
- if (event.props?.[k2] !== v2) return false;
19544
- }
19545
- }
19546
- return true;
19547
- });
19548
- }
19549
19529
  }
19550
19530
  if (actions) {
19551
19531
  for (const rawAction of actions) {
19552
19532
  const action = rawAction;
19553
- const triggerWhen = action.triggerWhen;
19554
- if (triggerWhen?.type === "rules") {
19555
- for (const rule of triggerWhen.rules) {
19556
- for (const cond of rule.conditions) {
19557
- if (cond.type === "event_count" && cond.key) {
19558
- accumulator.register(cond.key, () => true);
19559
- }
19560
- }
19561
- }
19533
+ if (action.triggerWhen?.type === "rules") {
19534
+ registerFromTriggerWhen(action.triggerWhen, accumulator);
19562
19535
  }
19563
19536
  }
19564
19537
  }
@@ -21671,7 +21644,6 @@ ${cssRules}
21671
21644
  let cancelled = false;
21672
21645
  const run = async () => {
21673
21646
  if (batchHandleRef.current) {
21674
- console.log("[SmartCanvasApp] Reverting previous action batch before re-apply");
21675
21647
  try {
21676
21648
  await batchHandleRef.current.revertAll();
21677
21649
  } catch (err) {
@@ -21681,28 +21653,16 @@ ${cssRules}
21681
21653
  }
21682
21654
  if (cancelled) return;
21683
21655
  if (configState.actions.length > 0) {
21684
- console.log(
21685
- `[SmartCanvasApp] Applying ${configState.actions.length} action(s):`,
21686
- configState.actions.map(
21687
- (a2, i2) => `[${i2}] ${a2.kind}${a2.anchorId ? ` anchor="${a2.anchorId}"` : ""}${a2.label ? ` "${a2.label}"` : ""}`
21688
- ).join(", ")
21689
- );
21690
21656
  try {
21691
21657
  const handle = await runtime7.actions.applyBatch(configState.actions);
21692
21658
  if (cancelled) {
21693
21659
  await handle.revertAll();
21694
21660
  } else {
21695
21661
  batchHandleRef.current = handle;
21696
- console.log("[SmartCanvasApp] Action batch applied successfully");
21697
21662
  }
21698
21663
  } catch (err) {
21699
21664
  if (!cancelled) {
21700
- console.error(
21701
- "[SmartCanvasApp] Failed to apply actions:",
21702
- err,
21703
- "\nActions that failed:",
21704
- JSON.stringify(configState.actions, null, 2)
21705
- );
21665
+ console.error("[SmartCanvasApp] Failed to apply actions:", err);
21706
21666
  }
21707
21667
  }
21708
21668
  }
@@ -21711,9 +21671,6 @@ ${cssRules}
21711
21671
  return () => {
21712
21672
  cancelled = true;
21713
21673
  if (batchHandleRef.current) {
21714
- console.log(
21715
- "[SmartCanvasApp] Cleanup: reverting action batch (actions changed or unmount)"
21716
- );
21717
21674
  batchHandleRef.current.revertAll().catch((err) => {
21718
21675
  console.error("[SmartCanvasApp] Failed to revert actions on cleanup:", err);
21719
21676
  });
@@ -21944,7 +21901,7 @@ ${cssRules}
21944
21901
  console.log(
21945
21902
  "[SmartCanvas] Actions to apply:",
21946
21903
  canvasConfig.actions.map(
21947
- (a2, i2) => `[${i2}] ${a2.kind}${a2.anchorId ? ` anchor="${a2.anchorId}"` : ""}${a2.label ? ` "${a2.label}"` : ""}`
21904
+ (a2, i2) => `[${i2}] ${a2.kind}${a2.anchorId ? ` anchor="${typeof a2.anchorId === "string" ? a2.anchorId : a2.anchorId.selector}"` : ""}${a2.label ? ` "${a2.label}"` : ""}`
21948
21905
  ).join(", ")
21949
21906
  );
21950
21907
  }
@@ -34982,6 +34939,7 @@ ${cssRules}
34982
34939
  eventBus,
34983
34940
  surfaces,
34984
34941
  anchorResolver,
34942
+ waitForAnchor,
34985
34943
  adaptiveId,
34986
34944
  executorRegistry: executorRegistry2 = executorRegistry,
34987
34945
  subscribeNavigation,
@@ -35001,6 +34959,7 @@ ${cssRules}
35001
34959
  return {
35002
34960
  overlayRoot,
35003
34961
  resolveAnchor: anchorResolver,
34962
+ waitForAnchor,
35004
34963
  generateId: generateId2,
35005
34964
  publishEvent,
35006
34965
  adaptiveId,
@@ -35258,7 +35217,7 @@ ${cssRules}
35258
35217
  errorMessages,
35259
35218
  "\nActions:",
35260
35219
  actions.map(
35261
- (a2, i2) => ` [${i2}] ${a2.kind} ${a2.anchorId ? `anchor="${a2.anchorId}"` : ""} ${a2.label ? `label="${a2.label}"` : ""}`
35220
+ (a2, i2) => ` [${i2}] ${a2.kind} ${a2.anchorId ? `anchor="${typeof a2.anchorId === "string" ? a2.anchorId : a2.anchorId.selector}"` : ""} ${a2.label ? `label="${a2.label}"` : ""}`
35262
35221
  ).join("\n")
35263
35222
  );
35264
35223
  throw new Error(`Batch validation failed: ${errorMessages}`);
@@ -35346,7 +35305,11 @@ ${cssRules}
35346
35305
  };
35347
35306
  }
35348
35307
 
35349
- // src/decisions/schema.ts
35308
+ // ../sdk-contracts/dist/schemas.js
35309
+ var AnchorIdZ = external_exports.object({
35310
+ selector: external_exports.string(),
35311
+ route: external_exports.union([external_exports.string(), external_exports.array(external_exports.string())])
35312
+ }).strict();
35350
35313
  var PageUrlConditionZ = external_exports.object({
35351
35314
  type: external_exports.literal("page_url"),
35352
35315
  url: external_exports.string()
@@ -35399,12 +35362,21 @@ ${cssRules}
35399
35362
  limit: external_exports.number(),
35400
35363
  inverted: external_exports.boolean().optional()
35401
35364
  });
35365
+ var MatchOpZ = external_exports.object({
35366
+ equals: external_exports.union([external_exports.string(), external_exports.number(), external_exports.boolean()]).optional(),
35367
+ contains: external_exports.string().optional()
35368
+ });
35369
+ var CounterDefZ = external_exports.object({
35370
+ events: external_exports.array(external_exports.string()).min(1),
35371
+ match: external_exports.record(external_exports.string(), MatchOpZ).optional()
35372
+ });
35402
35373
  var EventCountConditionZ = external_exports.object({
35403
35374
  type: external_exports.literal("event_count"),
35404
35375
  key: external_exports.string(),
35405
35376
  operator: external_exports.enum(["gte", "lte", "eq", "gt", "lt"]),
35406
35377
  count: external_exports.number().int().min(0),
35407
- withinMs: external_exports.number().positive().optional()
35378
+ withinMs: external_exports.number().positive().optional(),
35379
+ counter: CounterDefZ.optional()
35408
35380
  });
35409
35381
  var ConditionZ = external_exports.discriminatedUnion("type", [
35410
35382
  PageUrlConditionZ,
@@ -35455,6 +35427,19 @@ ${cssRules}
35455
35427
  ModelStrategyZ,
35456
35428
  ExternalStrategyZ
35457
35429
  ]);
35430
+ var TriggerWhenZ = DecisionStrategyZ.nullable().optional();
35431
+ var EventScopeZ = external_exports.object({
35432
+ events: external_exports.array(external_exports.string()),
35433
+ urlContains: external_exports.string().optional(),
35434
+ props: external_exports.record(external_exports.union([external_exports.string(), external_exports.number(), external_exports.boolean()])).optional()
35435
+ });
35436
+ var NotifyZ = external_exports.object({
35437
+ title: external_exports.string().optional(),
35438
+ body: external_exports.string().optional(),
35439
+ icon: external_exports.string().optional()
35440
+ }).nullable().optional();
35441
+
35442
+ // src/decisions/schema.ts
35458
35443
  var RouteFilterZ = external_exports.object({
35459
35444
  include: external_exports.array(external_exports.string()).optional(),
35460
35445
  exclude: external_exports.array(external_exports.string()).optional()
@@ -35473,6 +35458,8 @@ ${cssRules}
35473
35458
  return ActivationConfigZ.safeParse(data);
35474
35459
  }
35475
35460
  var decisionSchemas = [
35461
+ { defName: "matchOp", schema: MatchOpZ },
35462
+ { defName: "counterDef", schema: CounterDefZ },
35476
35463
  { defName: "activationConfig", schema: ActivationConfigZ },
35477
35464
  { defName: "routeFilter", schema: RouteFilterZ },
35478
35465
  { defName: "ruleStrategy", schema: RuleStrategyZ },
@@ -35488,7 +35475,7 @@ ${cssRules}
35488
35475
  activation: ActivationConfigZ.optional(),
35489
35476
  triggerWhen: DecisionStrategyZ.nullable().optional()
35490
35477
  };
35491
- var AnchorIdZ = external_exports.object({
35478
+ var AnchorIdZ2 = external_exports.object({
35492
35479
  selector: external_exports.string(),
35493
35480
  route: external_exports.union([external_exports.string(), external_exports.array(external_exports.string())])
35494
35481
  }).strict();
@@ -35544,65 +35531,65 @@ ${cssRules}
35544
35531
  var ScrollLogicalPositionZ = external_exports.enum(["start", "center", "end", "nearest"]);
35545
35532
  var SetTextZ = external_exports.object({
35546
35533
  kind: external_exports.literal("content:setText"),
35547
- anchorId: AnchorIdZ,
35534
+ anchorId: AnchorIdZ2,
35548
35535
  text: external_exports.string(),
35549
35536
  label: external_exports.string().optional()
35550
35537
  }).extend(ActionActivationZ).strict();
35551
35538
  var SetAttrZ = external_exports.object({
35552
35539
  kind: external_exports.literal("content:setAttr"),
35553
- anchorId: AnchorIdZ,
35540
+ anchorId: AnchorIdZ2,
35554
35541
  attr: external_exports.string(),
35555
35542
  value: external_exports.string(),
35556
35543
  label: external_exports.string().optional()
35557
35544
  }).extend(ActionActivationZ).strict();
35558
35545
  var AddClassZ = external_exports.object({
35559
35546
  kind: external_exports.literal("content:addClass"),
35560
- anchorId: AnchorIdZ,
35547
+ anchorId: AnchorIdZ2,
35561
35548
  className: external_exports.string(),
35562
35549
  label: external_exports.string().optional()
35563
35550
  }).extend(ActionActivationZ).strict();
35564
35551
  var RemoveClassZ = external_exports.object({
35565
35552
  kind: external_exports.literal("content:removeClass"),
35566
- anchorId: AnchorIdZ,
35553
+ anchorId: AnchorIdZ2,
35567
35554
  className: external_exports.string(),
35568
35555
  label: external_exports.string().optional()
35569
35556
  }).extend(ActionActivationZ).strict();
35570
35557
  var SetStyleZ = external_exports.object({
35571
35558
  kind: external_exports.literal("content:setStyle"),
35572
- anchorId: AnchorIdZ,
35559
+ anchorId: AnchorIdZ2,
35573
35560
  styles: external_exports.record(external_exports.string()),
35574
35561
  label: external_exports.string().optional()
35575
35562
  }).extend(ActionActivationZ).strict();
35576
35563
  var InsertHtmlZ = external_exports.object({
35577
35564
  kind: external_exports.literal("content:insertHtml"),
35578
- anchorId: AnchorIdZ,
35565
+ anchorId: AnchorIdZ2,
35579
35566
  html: external_exports.string(),
35580
35567
  position: InsertPositionZ,
35581
35568
  label: external_exports.string().optional()
35582
35569
  }).extend(ActionActivationZ).strict();
35583
35570
  var HighlightZ = external_exports.object({
35584
35571
  kind: external_exports.literal("overlays:highlight"),
35585
- anchorId: AnchorIdZ,
35572
+ anchorId: AnchorIdZ2,
35586
35573
  style: HighlightStyleZ.optional(),
35587
35574
  duration: external_exports.number().optional(),
35588
35575
  label: external_exports.string().optional()
35589
35576
  }).extend(ActionActivationZ).strict();
35590
35577
  var PulseZ = external_exports.object({
35591
35578
  kind: external_exports.literal("overlays:pulse"),
35592
- anchorId: AnchorIdZ,
35579
+ anchorId: AnchorIdZ2,
35593
35580
  duration: external_exports.number().optional(),
35594
35581
  label: external_exports.string().optional()
35595
35582
  }).extend(ActionActivationZ).strict();
35596
35583
  var BadgeZ = external_exports.object({
35597
35584
  kind: external_exports.literal("overlays:badge"),
35598
- anchorId: AnchorIdZ,
35585
+ anchorId: AnchorIdZ2,
35599
35586
  content: external_exports.string(),
35600
35587
  position: BadgePositionZ.optional(),
35601
35588
  label: external_exports.string().optional()
35602
35589
  }).extend(ActionActivationZ).strict();
35603
35590
  var TooltipZ = external_exports.object({
35604
35591
  kind: external_exports.literal("overlays:tooltip"),
35605
- anchorId: AnchorIdZ,
35592
+ anchorId: AnchorIdZ2,
35606
35593
  content: TooltipContentZ,
35607
35594
  trigger: TooltipTriggerZ.optional(),
35608
35595
  placement: PlacementZ.optional(),
@@ -35628,7 +35615,7 @@ ${cssRules}
35628
35615
  }).extend(ActionActivationZ).strict();
35629
35616
  var ScrollToZ = external_exports.object({
35630
35617
  kind: external_exports.literal("navigation:scrollTo"),
35631
- anchorId: AnchorIdZ,
35618
+ anchorId: AnchorIdZ2,
35632
35619
  behavior: ScrollBehaviorZ.optional(),
35633
35620
  block: ScrollLogicalPositionZ.optional(),
35634
35621
  inline: ScrollLogicalPositionZ.optional(),
@@ -35692,6 +35679,153 @@ ${cssRules}
35692
35679
  { defName: "tour", schema: TourZ }
35693
35680
  ];
35694
35681
 
35682
+ // src/anchor/AnchorResolver.ts
35683
+ function createAnchorResolver(opts) {
35684
+ const root = opts?.root ?? (typeof document !== "undefined" ? document.body : null);
35685
+ const defaultTimeoutMs = opts?.defaultTimeoutMs ?? 5e3;
35686
+ const waiters = /* @__PURE__ */ new Map();
35687
+ const appearWatchers = /* @__PURE__ */ new Map();
35688
+ let observer2 = null;
35689
+ let destroyed = false;
35690
+ function resolve(selector) {
35691
+ if (!root) return null;
35692
+ try {
35693
+ return root.querySelector(selector);
35694
+ } catch {
35695
+ return null;
35696
+ }
35697
+ }
35698
+ function checkPending() {
35699
+ for (const [selector, set] of waiters) {
35700
+ const el = resolve(selector);
35701
+ if (el) {
35702
+ for (const w2 of set) {
35703
+ clearTimeout(w2.timer);
35704
+ w2.resolve(el);
35705
+ }
35706
+ waiters.delete(selector);
35707
+ }
35708
+ }
35709
+ for (const [selector, set] of appearWatchers) {
35710
+ const el = resolve(selector);
35711
+ if (el) {
35712
+ for (const watcher of set) {
35713
+ if (!watcher.cancelled) {
35714
+ watcher.cb(el);
35715
+ }
35716
+ }
35717
+ appearWatchers.delete(selector);
35718
+ }
35719
+ }
35720
+ if (waiters.size === 0 && appearWatchers.size === 0) {
35721
+ disconnectObserver();
35722
+ }
35723
+ }
35724
+ function ensureObserver() {
35725
+ if (observer2 || destroyed) return;
35726
+ if (typeof MutationObserver === "undefined" || !root) return;
35727
+ observer2 = new MutationObserver(() => {
35728
+ checkPending();
35729
+ });
35730
+ observer2.observe(root, { childList: true, subtree: true });
35731
+ }
35732
+ function disconnectObserver() {
35733
+ if (observer2) {
35734
+ observer2.disconnect();
35735
+ observer2 = null;
35736
+ }
35737
+ }
35738
+ function removeWaiter(selector, waiter) {
35739
+ const set = waiters.get(selector);
35740
+ if (set) {
35741
+ set.delete(waiter);
35742
+ if (set.size === 0) {
35743
+ waiters.delete(selector);
35744
+ }
35745
+ }
35746
+ if (waiters.size === 0 && appearWatchers.size === 0) {
35747
+ disconnectObserver();
35748
+ }
35749
+ }
35750
+ function waitFor(selector, timeoutMs) {
35751
+ if (destroyed) {
35752
+ return Promise.reject(new Error("AnchorResolver destroyed"));
35753
+ }
35754
+ const existing = resolve(selector);
35755
+ if (existing) return Promise.resolve(existing);
35756
+ const timeout = timeoutMs ?? defaultTimeoutMs;
35757
+ return new Promise((res, rej) => {
35758
+ const waiter = {
35759
+ resolve: res,
35760
+ reject: rej,
35761
+ timer: setTimeout(() => {
35762
+ removeWaiter(selector, waiter);
35763
+ rej(new Error(`waitFor("${selector}") timed out after ${timeout}ms`));
35764
+ }, timeout)
35765
+ };
35766
+ let set = waiters.get(selector);
35767
+ if (!set) {
35768
+ set = /* @__PURE__ */ new Set();
35769
+ waiters.set(selector, set);
35770
+ }
35771
+ set.add(waiter);
35772
+ ensureObserver();
35773
+ });
35774
+ }
35775
+ function onAppear(selector, cb) {
35776
+ if (destroyed) return () => {
35777
+ };
35778
+ const existing = resolve(selector);
35779
+ if (existing) {
35780
+ cb(existing);
35781
+ return () => {
35782
+ };
35783
+ }
35784
+ const watcher = { cb, cancelled: false };
35785
+ let set = appearWatchers.get(selector);
35786
+ if (!set) {
35787
+ set = /* @__PURE__ */ new Set();
35788
+ appearWatchers.set(selector, set);
35789
+ }
35790
+ set.add(watcher);
35791
+ ensureObserver();
35792
+ return () => {
35793
+ watcher.cancelled = true;
35794
+ const s2 = appearWatchers.get(selector);
35795
+ if (s2) {
35796
+ s2.delete(watcher);
35797
+ if (s2.size === 0) {
35798
+ appearWatchers.delete(selector);
35799
+ }
35800
+ }
35801
+ if (waiters.size === 0 && appearWatchers.size === 0) {
35802
+ disconnectObserver();
35803
+ }
35804
+ };
35805
+ }
35806
+ function pendingCount() {
35807
+ let count = 0;
35808
+ for (const set of waiters.values()) {
35809
+ count += set.size;
35810
+ }
35811
+ return count;
35812
+ }
35813
+ function destroy() {
35814
+ destroyed = true;
35815
+ disconnectObserver();
35816
+ const err = new Error("AnchorResolver destroyed");
35817
+ for (const set of waiters.values()) {
35818
+ for (const w2 of set) {
35819
+ clearTimeout(w2.timer);
35820
+ w2.reject(err);
35821
+ }
35822
+ }
35823
+ waiters.clear();
35824
+ appearWatchers.clear();
35825
+ }
35826
+ return { resolve, waitFor, onAppear, pendingCount, destroy };
35827
+ }
35828
+
35695
35829
  // src/context/ContextManager.ts
35696
35830
  function createDefaultContext() {
35697
35831
  const now = Date.now();
@@ -35982,7 +36116,8 @@ ${cssRules}
35982
36116
  return context.page.routeId === condition.routeId;
35983
36117
  }
35984
36118
  case "anchor_visible": {
35985
- const anchor = context.anchors?.find((a2) => a2.anchorId === condition.anchorId);
36119
+ const condSelector = typeof condition.anchorId === "string" ? condition.anchorId : condition.anchorId?.selector ?? "";
36120
+ const anchor = context.anchors?.find((a2) => a2.anchorId === condSelector);
35986
36121
  switch (condition.state) {
35987
36122
  case "visible":
35988
36123
  return anchor?.visible === true;
@@ -37653,20 +37788,11 @@ ${cssRules}
37653
37788
  const regex = new RegExp(`^${regexPattern}$`);
37654
37789
  return regex.test(pathname);
37655
37790
  }
37656
- function resolveAnchorById(anchorId) {
37657
- const { selector, route } = anchorId;
37791
+ function matchesAnchorRoute(anchorId) {
37658
37792
  const pathname = typeof window !== "undefined" ? window.location.pathname : "/";
37659
37793
  const normalizedPath = pathname.replace(/\/$/, "") || "/";
37660
- const routes = Array.isArray(route) ? route : [route];
37661
- const matches = routes.some((pattern) => matchRoutePattern(normalizedPath, pattern));
37662
- if (!matches) {
37663
- return null;
37664
- }
37665
- try {
37666
- return document.querySelector(selector);
37667
- } catch {
37668
- return null;
37669
- }
37794
+ const routes = Array.isArray(anchorId.route) ? anchorId.route : [anchorId.route];
37795
+ return routes.some((pattern) => matchRoutePattern(normalizedPath, pattern));
37670
37796
  }
37671
37797
  function createSmartCanvasRuntime(options = {}) {
37672
37798
  const { telemetry, sessionMetrics, routes, mode = "production", namespace } = options;
@@ -37694,7 +37820,19 @@ ${cssRules}
37694
37820
  accumulator
37695
37821
  });
37696
37822
  const overlayRoot = ensureOverlayRoot();
37697
- const anchorResolver = (anchorId) => resolveAnchorById(anchorId);
37823
+ const anchorResolverService = createAnchorResolver();
37824
+ const anchorResolver = (anchorId) => {
37825
+ if (!matchesAnchorRoute(anchorId)) return null;
37826
+ return anchorResolverService.resolve(anchorId.selector);
37827
+ };
37828
+ const waitForAnchor = async (anchorId, timeoutMs) => {
37829
+ if (!matchesAnchorRoute(anchorId)) return null;
37830
+ try {
37831
+ return await anchorResolverService.waitFor(anchorId.selector, timeoutMs);
37832
+ } catch {
37833
+ return null;
37834
+ }
37835
+ };
37698
37836
  const surfaces = createSurfaces({
37699
37837
  overlayRoot,
37700
37838
  eventBus: events,
@@ -37706,6 +37844,7 @@ ${cssRules}
37706
37844
  eventBus: events,
37707
37845
  surfaces,
37708
37846
  anchorResolver,
37847
+ waitForAnchor,
37709
37848
  executorRegistry: executors5,
37710
37849
  subscribeNavigation: (callback) => navigation2.subscribe(callback),
37711
37850
  runtime: {
@@ -37726,6 +37865,7 @@ ${cssRules}
37726
37865
  executors: executors5,
37727
37866
  apps,
37728
37867
  accumulator,
37868
+ anchorResolver: anchorResolverService,
37729
37869
  navigation: navigation2,
37730
37870
  version: RUNTIME_VERSION,
37731
37871
  mode,
@@ -37765,6 +37905,7 @@ ${cssRules}
37765
37905
  apps.unbind().catch((err) => {
37766
37906
  console.error("[Runtime] Error unbinding apps registry:", err);
37767
37907
  });
37908
+ anchorResolverService.destroy();
37768
37909
  accumulator.destroy();
37769
37910
  navigation2.destroy();
37770
37911
  context.destroy();
@@ -38362,7 +38503,7 @@ ${cssRules}
38362
38503
  console.log(
38363
38504
  "[Syntro Bootstrap] Actions in config:",
38364
38505
  config.actions.map(
38365
- (a2, i2) => `[${i2}] ${a2.kind}${a2.anchorId ? ` anchor="${a2.anchorId}"` : ""}${a2.label ? ` "${a2.label}"` : ""}`
38506
+ (a2, i2) => `[${i2}] ${a2.kind}${a2.anchorId ? ` anchor="${typeof a2.anchorId === "string" ? a2.anchorId : a2.anchorId.selector}"` : ""}${a2.label ? ` "${a2.label}"` : ""}`
38366
38507
  ).join(", ")
38367
38508
  );
38368
38509
  }
@@ -38430,7 +38571,7 @@ ${cssRules}
38430
38571
  }
38431
38572
 
38432
38573
  // src/index.ts
38433
- var RUNTIME_SDK_BUILD = true ? `${"2026-03-02T05:10:12.769Z"} (${"e499f8d074"})` : "dev";
38574
+ var RUNTIME_SDK_BUILD = true ? `${"2026-03-02T18:34:22.502Z"} (${"6c75590b5e"})` : "dev";
38434
38575
  if (typeof window !== "undefined") {
38435
38576
  console.log(`[Syntro Runtime] Build: ${RUNTIME_SDK_BUILD}`);
38436
38577
  const existing = window.SynOS;