@syntrologie/runtime-sdk 2.4.0-canary.17 → 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-VIGV46CB.js → chunk-LRN3K2VD.js} +284 -102
  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 +320 -179
  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-VIGV46CB.js.map +0 -7
  36. /package/dist/{chunk-LZLDT5DA.js.map → chunk-LR5AA5SE.js.map} +0 -0
@@ -3,7 +3,7 @@ import {
3
3
  __privateGet,
4
4
  __privateSet,
5
5
  __publicField
6
- } from "./chunk-4NYS7GAW.js";
6
+ } from "./chunk-P5G4KT2U.js";
7
7
 
8
8
  // ../adaptives/adaptive-content/dist/reconciliation-guard.js
9
9
  function guardAgainstReconciliation(container, anchor, reinsertFn, opts) {
@@ -124,9 +124,12 @@ function sanitizeHtml(html) {
124
124
 
125
125
  // ../adaptives/adaptive-content/dist/runtime.js
126
126
  var executeInsertHtml = async (action, context) => {
127
- const anchorEl = context.resolveAnchor(action.anchorId);
127
+ let anchorEl = context.resolveAnchor(action.anchorId);
128
+ if (!anchorEl && context.waitForAnchor) {
129
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
130
+ }
128
131
  if (!anchorEl) {
129
- console.error(`[adaptive-content] Anchor not found for insertHtml, skipping: ${action.anchorId.selector}`);
132
+ console.warn(`[adaptive-content] Anchor not found after waiting: ${action.anchorId.selector}`);
130
133
  return { cleanup: () => {
131
134
  } };
132
135
  }
@@ -201,9 +204,12 @@ var executeInsertHtml = async (action, context) => {
201
204
  };
202
205
  var executeSetText = async (action, context) => {
203
206
  var _a2;
204
- const anchorEl = context.resolveAnchor(action.anchorId);
207
+ let anchorEl = context.resolveAnchor(action.anchorId);
208
+ if (!anchorEl && context.waitForAnchor) {
209
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
210
+ }
205
211
  if (!anchorEl) {
206
- console.error(`[adaptive-content] Anchor not found for setText, skipping: ${action.anchorId.selector}`);
212
+ console.warn(`[adaptive-content] Anchor not found after waiting: ${action.anchorId.selector}`);
207
213
  return { cleanup: () => {
208
214
  } };
209
215
  }
@@ -226,9 +232,12 @@ var executeSetText = async (action, context) => {
226
232
  };
227
233
  };
228
234
  var executeSetAttr = async (action, context) => {
229
- const anchorEl = context.resolveAnchor(action.anchorId);
235
+ let anchorEl = context.resolveAnchor(action.anchorId);
236
+ if (!anchorEl && context.waitForAnchor) {
237
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
238
+ }
230
239
  if (!anchorEl) {
231
- console.error(`[adaptive-content] Anchor not found for setAttr, skipping: ${action.anchorId.selector}`);
240
+ console.warn(`[adaptive-content] Anchor not found after waiting: ${action.anchorId.selector}`);
232
241
  return { cleanup: () => {
233
242
  } };
234
243
  }
@@ -268,9 +277,12 @@ var executeSetAttr = async (action, context) => {
268
277
  };
269
278
  };
270
279
  var executeAddClass = async (action, context) => {
271
- const anchorEl = context.resolveAnchor(action.anchorId);
280
+ let anchorEl = context.resolveAnchor(action.anchorId);
281
+ if (!anchorEl && context.waitForAnchor) {
282
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
283
+ }
272
284
  if (!anchorEl) {
273
- console.error(`[adaptive-content] Anchor not found for addClass, skipping: ${action.anchorId.selector}`);
285
+ console.warn(`[adaptive-content] Anchor not found after waiting: ${action.anchorId.selector}`);
274
286
  return { cleanup: () => {
275
287
  } };
276
288
  }
@@ -291,9 +303,12 @@ var executeAddClass = async (action, context) => {
291
303
  };
292
304
  };
293
305
  var executeRemoveClass = async (action, context) => {
294
- const anchorEl = context.resolveAnchor(action.anchorId);
306
+ let anchorEl = context.resolveAnchor(action.anchorId);
307
+ if (!anchorEl && context.waitForAnchor) {
308
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
309
+ }
295
310
  if (!anchorEl) {
296
- console.error(`[adaptive-content] Anchor not found for removeClass, skipping: ${action.anchorId.selector}`);
311
+ console.warn(`[adaptive-content] Anchor not found after waiting: ${action.anchorId.selector}`);
297
312
  return { cleanup: () => {
298
313
  } };
299
314
  }
@@ -314,9 +329,12 @@ var executeRemoveClass = async (action, context) => {
314
329
  };
315
330
  };
316
331
  var executeSetStyle = async (action, context) => {
317
- const anchorEl = context.resolveAnchor(action.anchorId);
332
+ let anchorEl = context.resolveAnchor(action.anchorId);
333
+ if (!anchorEl && context.waitForAnchor) {
334
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
335
+ }
318
336
  if (!anchorEl) {
319
- console.error(`[adaptive-content] Anchor not found for setStyle, skipping: ${action.anchorId.selector}`);
337
+ console.warn(`[adaptive-content] Anchor not found after waiting: ${action.anchorId.selector}`);
320
338
  return { cleanup: () => {
321
339
  } };
322
340
  }
@@ -2348,9 +2366,12 @@ var WorkflowMountableWidget = {
2348
2366
  // ../adaptives/adaptive-overlays/dist/runtime.js
2349
2367
  var executeHighlight = async (action, context) => {
2350
2368
  var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2351
- const anchorEl = context.resolveAnchor(action.anchorId);
2369
+ let anchorEl = context.resolveAnchor(action.anchorId);
2370
+ if (!anchorEl && context.waitForAnchor) {
2371
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
2372
+ }
2352
2373
  if (!anchorEl) {
2353
- console.error(`[adaptive-overlays] Anchor not found for highlight, skipping: ${action.anchorId.selector}`);
2374
+ console.warn(`[adaptive-overlays] Anchor not found after waiting: ${action.anchorId.selector}`);
2354
2375
  return { cleanup: () => {
2355
2376
  } };
2356
2377
  }
@@ -2376,9 +2397,12 @@ var executeHighlight = async (action, context) => {
2376
2397
  };
2377
2398
  var executePulse = async (action, context) => {
2378
2399
  var _a2;
2379
- const anchorEl = context.resolveAnchor(action.anchorId);
2400
+ let anchorEl = context.resolveAnchor(action.anchorId);
2401
+ if (!anchorEl && context.waitForAnchor) {
2402
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
2403
+ }
2380
2404
  if (!anchorEl) {
2381
- console.error(`[adaptive-overlays] Anchor not found for pulse, skipping: ${action.anchorId.selector}`);
2405
+ console.warn(`[adaptive-overlays] Anchor not found after waiting: ${action.anchorId.selector}`);
2382
2406
  return { cleanup: () => {
2383
2407
  } };
2384
2408
  }
@@ -2421,9 +2445,12 @@ var executePulse = async (action, context) => {
2421
2445
  };
2422
2446
  var executeBadge = async (action, context) => {
2423
2447
  var _a2;
2424
- const anchorEl = context.resolveAnchor(action.anchorId);
2448
+ let anchorEl = context.resolveAnchor(action.anchorId);
2449
+ if (!anchorEl && context.waitForAnchor) {
2450
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
2451
+ }
2425
2452
  if (!anchorEl) {
2426
- console.error(`[adaptive-overlays] Anchor not found for badge, skipping: ${action.anchorId.selector}`);
2453
+ console.warn(`[adaptive-overlays] Anchor not found after waiting: ${action.anchorId.selector}`);
2427
2454
  return { cleanup: () => {
2428
2455
  } };
2429
2456
  }
@@ -2486,9 +2513,12 @@ var executeBadge = async (action, context) => {
2486
2513
  };
2487
2514
  var executeTooltip = async (action, context) => {
2488
2515
  var _a2, _b, _c, _d;
2489
- const anchorEl = context.resolveAnchor(action.anchorId);
2516
+ let anchorEl = context.resolveAnchor(action.anchorId);
2517
+ if (!anchorEl && context.waitForAnchor) {
2518
+ anchorEl = await context.waitForAnchor(action.anchorId, 3e3);
2519
+ }
2490
2520
  if (!anchorEl) {
2491
- console.error(`[adaptive-overlays] Anchor not found for tooltip, skipping: ${action.anchorId.selector}`);
2521
+ console.warn(`[adaptive-overlays] Anchor not found after waiting: ${action.anchorId.selector}`);
2492
2522
  return { cleanup: () => {
2493
2523
  } };
2494
2524
  }
@@ -3193,7 +3223,7 @@ function getAntiFlickerSnippet(config = {}) {
3193
3223
  }
3194
3224
 
3195
3225
  // src/version.ts
3196
- var SDK_VERSION = "2.4.0-canary.17";
3226
+ var SDK_VERSION = "2.4.0-canary.19";
3197
3227
 
3198
3228
  // src/types.ts
3199
3229
  var SDK_SCHEMA_VERSION = "2.0";
@@ -3434,58 +3464,68 @@ var createCanvasConfigFetcher = ({
3434
3464
  };
3435
3465
 
3436
3466
  // src/events/registerConfigPredicates.ts
3467
+ var ELEMENT_CHAIN_FIELDS = /* @__PURE__ */ new Set(["tag_name", "$el_text"]);
3468
+ function isElementChainField(key) {
3469
+ return ELEMENT_CHAIN_FIELDS.has(key) || key.startsWith("attr__");
3470
+ }
3471
+ function checkMatchOp(op, value) {
3472
+ if (op.equals !== void 0) {
3473
+ return value === op.equals;
3474
+ }
3475
+ if (op.contains !== void 0) {
3476
+ return typeof value === "string" && value.includes(op.contains);
3477
+ }
3478
+ return false;
3479
+ }
3480
+ function buildPredicate(counter) {
3481
+ const { events: eventNames, match } = counter;
3482
+ return (event) => {
3483
+ var _a2, _b;
3484
+ if (!eventNames.includes(event.name)) return false;
3485
+ if (match) {
3486
+ for (const [key, op] of Object.entries(match)) {
3487
+ if (isElementChainField(key)) {
3488
+ const elements = (_a2 = event.props) == null ? void 0 : _a2.elements;
3489
+ if (!elements) return false;
3490
+ const anyMatch = elements.some((el) => checkMatchOp(op, el[key]));
3491
+ if (!anyMatch) return false;
3492
+ } else {
3493
+ if (!checkMatchOp(op, (_b = event.props) == null ? void 0 : _b[key])) return false;
3494
+ }
3495
+ }
3496
+ }
3497
+ return true;
3498
+ };
3499
+ }
3500
+ function registerFromTriggerWhen(triggerWhen, accumulator) {
3501
+ for (const rule of triggerWhen.rules) {
3502
+ for (const cond of rule.conditions) {
3503
+ if (cond.type === "event_count" && cond.key) {
3504
+ const counter = cond.counter;
3505
+ const predicate = counter ? buildPredicate(counter) : () => true;
3506
+ accumulator.register(cond.key, predicate);
3507
+ }
3508
+ }
3509
+ }
3510
+ }
3437
3511
  function registerConfigPredicates(tiles, accumulator, actions) {
3438
- var _a2;
3512
+ var _a2, _b;
3439
3513
  for (const tile of tiles) {
3440
3514
  const props = tile.props;
3441
3515
  if (!props) continue;
3442
- const scope = props.scope;
3443
- if (!(scope == null ? void 0 : scope.events)) continue;
3444
3516
  const tileActions = props.actions;
3445
3517
  if (!tileActions) continue;
3446
- const keys = /* @__PURE__ */ new Set();
3447
3518
  for (const action of tileActions) {
3448
3519
  if (((_a2 = action.triggerWhen) == null ? void 0 : _a2.type) === "rules") {
3449
- for (const rule of action.triggerWhen.rules) {
3450
- for (const cond of rule.conditions) {
3451
- if (cond.type === "event_count" && cond.key) {
3452
- keys.add(cond.key);
3453
- }
3454
- }
3455
- }
3520
+ registerFromTriggerWhen(action.triggerWhen, accumulator);
3456
3521
  }
3457
3522
  }
3458
- if (keys.size === 0) continue;
3459
- const { events: eventNames, urlContains, props: propFilters } = scope;
3460
- for (const key of keys) {
3461
- accumulator.register(key, (event) => {
3462
- var _a3, _b, _c;
3463
- if (!eventNames.includes(event.name)) return false;
3464
- if (urlContains) {
3465
- const pathname = String((_b = (_a3 = event.props) == null ? void 0 : _a3.pathname) != null ? _b : "");
3466
- if (!pathname.includes(urlContains)) return false;
3467
- }
3468
- if (propFilters) {
3469
- for (const [k, v] of Object.entries(propFilters)) {
3470
- if (((_c = event.props) == null ? void 0 : _c[k]) !== v) return false;
3471
- }
3472
- }
3473
- return true;
3474
- });
3475
- }
3476
3523
  }
3477
3524
  if (actions) {
3478
3525
  for (const rawAction of actions) {
3479
3526
  const action = rawAction;
3480
- const triggerWhen = action.triggerWhen;
3481
- if ((triggerWhen == null ? void 0 : triggerWhen.type) === "rules") {
3482
- for (const rule of triggerWhen.rules) {
3483
- for (const cond of rule.conditions) {
3484
- if (cond.type === "event_count" && cond.key) {
3485
- accumulator.register(cond.key, () => true);
3486
- }
3487
- }
3488
- }
3527
+ if (((_b = action.triggerWhen) == null ? void 0 : _b.type) === "rules") {
3528
+ registerFromTriggerWhen(action.triggerWhen, accumulator);
3489
3529
  }
3490
3530
  }
3491
3531
  }
@@ -5316,7 +5356,6 @@ function SmartCanvasAppInner({
5316
5356
  let cancelled = false;
5317
5357
  const run = async () => {
5318
5358
  if (batchHandleRef.current) {
5319
- console.log("[SmartCanvasApp] Reverting previous action batch before re-apply");
5320
5359
  try {
5321
5360
  await batchHandleRef.current.revertAll();
5322
5361
  } catch (err) {
@@ -5326,28 +5365,16 @@ function SmartCanvasAppInner({
5326
5365
  }
5327
5366
  if (cancelled) return;
5328
5367
  if (configState.actions.length > 0) {
5329
- console.log(
5330
- `[SmartCanvasApp] Applying ${configState.actions.length} action(s):`,
5331
- configState.actions.map(
5332
- (a, i) => `[${i}] ${a.kind}${a.anchorId ? ` anchor="${a.anchorId}"` : ""}${a.label ? ` "${a.label}"` : ""}`
5333
- ).join(", ")
5334
- );
5335
5368
  try {
5336
5369
  const handle = await runtime3.actions.applyBatch(configState.actions);
5337
5370
  if (cancelled) {
5338
5371
  await handle.revertAll();
5339
5372
  } else {
5340
5373
  batchHandleRef.current = handle;
5341
- console.log("[SmartCanvasApp] Action batch applied successfully");
5342
5374
  }
5343
5375
  } catch (err) {
5344
5376
  if (!cancelled) {
5345
- console.error(
5346
- "[SmartCanvasApp] Failed to apply actions:",
5347
- err,
5348
- "\nActions that failed:",
5349
- JSON.stringify(configState.actions, null, 2)
5350
- );
5377
+ console.error("[SmartCanvasApp] Failed to apply actions:", err);
5351
5378
  }
5352
5379
  }
5353
5380
  }
@@ -5356,9 +5383,6 @@ function SmartCanvasAppInner({
5356
5383
  return () => {
5357
5384
  cancelled = true;
5358
5385
  if (batchHandleRef.current) {
5359
- console.log(
5360
- "[SmartCanvasApp] Cleanup: reverting action batch (actions changed or unmount)"
5361
- );
5362
5386
  batchHandleRef.current.revertAll().catch((err) => {
5363
5387
  console.error("[SmartCanvasApp] Failed to revert actions on cleanup:", err);
5364
5388
  });
@@ -5448,7 +5472,7 @@ var SmartCanvasElement = class extends HTMLElement {
5448
5472
  Object.assign(__privateGet(this, _overlayContainer).style, {
5449
5473
  position: "fixed",
5450
5474
  inset: "0",
5451
- zIndex: "2147483647",
5475
+ zIndex: "2147483645",
5452
5476
  pointerEvents: "none"
5453
5477
  });
5454
5478
  __privateGet(this, _shadow).appendChild(__privateGet(this, _overlayContainer));
@@ -5759,7 +5783,7 @@ function ensureOverlayRoot() {
5759
5783
  Object.assign(overlayRootEl.style, {
5760
5784
  position: "fixed",
5761
5785
  inset: "0",
5762
- zIndex: "2147483647",
5786
+ zIndex: "2147483645",
5763
5787
  pointerEvents: "none"
5764
5788
  });
5765
5789
  document.body.appendChild(overlayRootEl);
@@ -6082,7 +6106,7 @@ var createSmartCanvas = async (config = {}) => {
6082
6106
  console.log(
6083
6107
  "[SmartCanvas] Actions to apply:",
6084
6108
  canvasConfig.actions.map(
6085
- (a, i) => `[${i}] ${a.kind}${a.anchorId ? ` anchor="${a.anchorId}"` : ""}${a.label ? ` "${a.label}"` : ""}`
6109
+ (a, i) => `[${i}] ${a.kind}${a.anchorId ? ` anchor="${typeof a.anchorId === "string" ? a.anchorId : a.anchorId.selector}"` : ""}${a.label ? ` "${a.label}"` : ""}`
6086
6110
  ).join(", ")
6087
6111
  );
6088
6112
  }
@@ -7580,6 +7604,7 @@ function createActionEngine(options) {
7580
7604
  eventBus,
7581
7605
  surfaces,
7582
7606
  anchorResolver,
7607
+ waitForAnchor,
7583
7608
  adaptiveId,
7584
7609
  executorRegistry: executorRegistry2 = executorRegistry,
7585
7610
  subscribeNavigation,
@@ -7599,6 +7624,7 @@ function createActionEngine(options) {
7599
7624
  return {
7600
7625
  overlayRoot,
7601
7626
  resolveAnchor: anchorResolver,
7627
+ waitForAnchor,
7602
7628
  generateId,
7603
7629
  publishEvent,
7604
7630
  adaptiveId,
@@ -7858,7 +7884,7 @@ function createActionEngine(options) {
7858
7884
  errorMessages,
7859
7885
  "\nActions:",
7860
7886
  actions.map(
7861
- (a, i) => ` [${i}] ${a.kind} ${a.anchorId ? `anchor="${a.anchorId}"` : ""} ${a.label ? `label="${a.label}"` : ""}`
7887
+ (a, i) => ` [${i}] ${a.kind} ${a.anchorId ? `anchor="${typeof a.anchorId === "string" ? a.anchorId : a.anchorId.selector}"` : ""} ${a.label ? `label="${a.label}"` : ""}`
7862
7888
  ).join("\n")
7863
7889
  );
7864
7890
  throw new Error(`Batch validation failed: ${errorMessages}`);
@@ -7946,6 +7972,154 @@ function createActionEngine(options) {
7946
7972
  };
7947
7973
  }
7948
7974
 
7975
+ // src/anchor/AnchorResolver.ts
7976
+ function createAnchorResolver(opts) {
7977
+ var _a2, _b;
7978
+ const root = (_a2 = opts == null ? void 0 : opts.root) != null ? _a2 : typeof document !== "undefined" ? document.body : null;
7979
+ const defaultTimeoutMs = (_b = opts == null ? void 0 : opts.defaultTimeoutMs) != null ? _b : 5e3;
7980
+ const waiters = /* @__PURE__ */ new Map();
7981
+ const appearWatchers = /* @__PURE__ */ new Map();
7982
+ let observer = null;
7983
+ let destroyed = false;
7984
+ function resolve(selector) {
7985
+ if (!root) return null;
7986
+ try {
7987
+ return root.querySelector(selector);
7988
+ } catch {
7989
+ return null;
7990
+ }
7991
+ }
7992
+ function checkPending() {
7993
+ for (const [selector, set] of waiters) {
7994
+ const el = resolve(selector);
7995
+ if (el) {
7996
+ for (const w of set) {
7997
+ clearTimeout(w.timer);
7998
+ w.resolve(el);
7999
+ }
8000
+ waiters.delete(selector);
8001
+ }
8002
+ }
8003
+ for (const [selector, set] of appearWatchers) {
8004
+ const el = resolve(selector);
8005
+ if (el) {
8006
+ for (const watcher of set) {
8007
+ if (!watcher.cancelled) {
8008
+ watcher.cb(el);
8009
+ }
8010
+ }
8011
+ appearWatchers.delete(selector);
8012
+ }
8013
+ }
8014
+ if (waiters.size === 0 && appearWatchers.size === 0) {
8015
+ disconnectObserver();
8016
+ }
8017
+ }
8018
+ function ensureObserver() {
8019
+ if (observer || destroyed) return;
8020
+ if (typeof MutationObserver === "undefined" || !root) return;
8021
+ observer = new MutationObserver(() => {
8022
+ checkPending();
8023
+ });
8024
+ observer.observe(root, { childList: true, subtree: true });
8025
+ }
8026
+ function disconnectObserver() {
8027
+ if (observer) {
8028
+ observer.disconnect();
8029
+ observer = null;
8030
+ }
8031
+ }
8032
+ function removeWaiter(selector, waiter) {
8033
+ const set = waiters.get(selector);
8034
+ if (set) {
8035
+ set.delete(waiter);
8036
+ if (set.size === 0) {
8037
+ waiters.delete(selector);
8038
+ }
8039
+ }
8040
+ if (waiters.size === 0 && appearWatchers.size === 0) {
8041
+ disconnectObserver();
8042
+ }
8043
+ }
8044
+ function waitFor(selector, timeoutMs) {
8045
+ if (destroyed) {
8046
+ return Promise.reject(new Error("AnchorResolver destroyed"));
8047
+ }
8048
+ const existing = resolve(selector);
8049
+ if (existing) return Promise.resolve(existing);
8050
+ const timeout = timeoutMs != null ? timeoutMs : defaultTimeoutMs;
8051
+ return new Promise((res, rej) => {
8052
+ const waiter = {
8053
+ resolve: res,
8054
+ reject: rej,
8055
+ timer: setTimeout(() => {
8056
+ removeWaiter(selector, waiter);
8057
+ rej(new Error(`waitFor("${selector}") timed out after ${timeout}ms`));
8058
+ }, timeout)
8059
+ };
8060
+ let set = waiters.get(selector);
8061
+ if (!set) {
8062
+ set = /* @__PURE__ */ new Set();
8063
+ waiters.set(selector, set);
8064
+ }
8065
+ set.add(waiter);
8066
+ ensureObserver();
8067
+ });
8068
+ }
8069
+ function onAppear(selector, cb) {
8070
+ if (destroyed) return () => {
8071
+ };
8072
+ const existing = resolve(selector);
8073
+ if (existing) {
8074
+ cb(existing);
8075
+ return () => {
8076
+ };
8077
+ }
8078
+ const watcher = { cb, cancelled: false };
8079
+ let set = appearWatchers.get(selector);
8080
+ if (!set) {
8081
+ set = /* @__PURE__ */ new Set();
8082
+ appearWatchers.set(selector, set);
8083
+ }
8084
+ set.add(watcher);
8085
+ ensureObserver();
8086
+ return () => {
8087
+ watcher.cancelled = true;
8088
+ const s = appearWatchers.get(selector);
8089
+ if (s) {
8090
+ s.delete(watcher);
8091
+ if (s.size === 0) {
8092
+ appearWatchers.delete(selector);
8093
+ }
8094
+ }
8095
+ if (waiters.size === 0 && appearWatchers.size === 0) {
8096
+ disconnectObserver();
8097
+ }
8098
+ };
8099
+ }
8100
+ function pendingCount() {
8101
+ let count = 0;
8102
+ for (const set of waiters.values()) {
8103
+ count += set.size;
8104
+ }
8105
+ return count;
8106
+ }
8107
+ function destroy() {
8108
+ destroyed = true;
8109
+ disconnectObserver();
8110
+ const err = new Error("AnchorResolver destroyed");
8111
+ for (const set of waiters.values()) {
8112
+ for (const w of set) {
8113
+ clearTimeout(w.timer);
8114
+ w.reject(err);
8115
+ }
8116
+ }
8117
+ waiters.clear();
8118
+ appearWatchers.clear();
8119
+ }
8120
+ return { resolve, waitFor, onAppear, pendingCount, destroy };
8121
+ }
8122
+
7949
8123
  // src/context/ContextManager.ts
7950
8124
  function createDefaultContext() {
7951
8125
  const now = Date.now();
@@ -8177,7 +8351,7 @@ function createContextManager(options = {}) {
8177
8351
 
8178
8352
  // src/decisions/strategies/rules.ts
8179
8353
  function evaluateCondition(condition, evalContext) {
8180
- var _a2, _b, _c, _d, _e;
8354
+ var _a2, _b, _c, _d, _e, _f, _g;
8181
8355
  const { context, state, events } = evalContext;
8182
8356
  switch (condition.type) {
8183
8357
  case "page_url": {
@@ -8191,7 +8365,8 @@ function evaluateCondition(condition, evalContext) {
8191
8365
  return context.page.routeId === condition.routeId;
8192
8366
  }
8193
8367
  case "anchor_visible": {
8194
- const anchor = (_a2 = context.anchors) == null ? void 0 : _a2.find((a) => a.anchorId === condition.anchorId);
8368
+ const condSelector = typeof condition.anchorId === "string" ? condition.anchorId : (_b = (_a2 = condition.anchorId) == null ? void 0 : _a2.selector) != null ? _b : "";
8369
+ const anchor = (_c = context.anchors) == null ? void 0 : _c.find((a) => a.anchorId === condSelector);
8195
8370
  switch (condition.state) {
8196
8371
  case "visible":
8197
8372
  return (anchor == null ? void 0 : anchor.visible) === true;
@@ -8205,7 +8380,7 @@ function evaluateCondition(condition, evalContext) {
8205
8380
  }
8206
8381
  case "event_occurred": {
8207
8382
  if (!events) return false;
8208
- const withinMs = (_b = condition.withinMs) != null ? _b : 6e4;
8383
+ const withinMs = (_d = condition.withinMs) != null ? _d : 6e4;
8209
8384
  return events.hasRecentEvent(condition.eventName, withinMs);
8210
8385
  }
8211
8386
  case "state_equals": {
@@ -8240,17 +8415,17 @@ function evaluateCondition(condition, evalContext) {
8240
8415
  }
8241
8416
  }
8242
8417
  case "dismissed": {
8243
- if (!state) return (_c = condition.inverted) != null ? _c : false;
8418
+ if (!state) return (_e = condition.inverted) != null ? _e : false;
8244
8419
  const isDismissed = state.isDismissed(condition.key);
8245
8420
  return condition.inverted ? !isDismissed : isDismissed;
8246
8421
  }
8247
8422
  case "cooldown_active": {
8248
- if (!state) return (_d = condition.inverted) != null ? _d : false;
8423
+ if (!state) return (_f = condition.inverted) != null ? _f : false;
8249
8424
  const isActive = state.isCooldownActive(condition.key);
8250
8425
  return condition.inverted ? !isActive : isActive;
8251
8426
  }
8252
8427
  case "frequency_limit": {
8253
- if (!state) return (_e = condition.inverted) != null ? _e : false;
8428
+ if (!state) return (_g = condition.inverted) != null ? _g : false;
8254
8429
  const count = state.getFrequencyCount(condition.key);
8255
8430
  const limitReached = count >= condition.limit;
8256
8431
  return condition.inverted ? !limitReached : limitReached;
@@ -9861,20 +10036,11 @@ function matchRoutePattern(pathname, pattern) {
9861
10036
  const regex = new RegExp(`^${regexPattern}$`);
9862
10037
  return regex.test(pathname);
9863
10038
  }
9864
- function resolveAnchorById(anchorId) {
9865
- const { selector, route } = anchorId;
10039
+ function matchesAnchorRoute(anchorId) {
9866
10040
  const pathname = typeof window !== "undefined" ? window.location.pathname : "/";
9867
10041
  const normalizedPath = pathname.replace(/\/$/, "") || "/";
9868
- const routes = Array.isArray(route) ? route : [route];
9869
- const matches = routes.some((pattern) => matchRoutePattern(normalizedPath, pattern));
9870
- if (!matches) {
9871
- return null;
9872
- }
9873
- try {
9874
- return document.querySelector(selector);
9875
- } catch {
9876
- return null;
9877
- }
10042
+ const routes = Array.isArray(anchorId.route) ? anchorId.route : [anchorId.route];
10043
+ return routes.some((pattern) => matchRoutePattern(normalizedPath, pattern));
9878
10044
  }
9879
10045
  function createSmartCanvasRuntime(options = {}) {
9880
10046
  var _a2, _b, _c, _d;
@@ -9903,7 +10069,19 @@ function createSmartCanvasRuntime(options = {}) {
9903
10069
  accumulator
9904
10070
  });
9905
10071
  const overlayRoot = ensureOverlayRoot();
9906
- const anchorResolver = (anchorId) => resolveAnchorById(anchorId);
10072
+ const anchorResolverService = createAnchorResolver();
10073
+ const anchorResolver = (anchorId) => {
10074
+ if (!matchesAnchorRoute(anchorId)) return null;
10075
+ return anchorResolverService.resolve(anchorId.selector);
10076
+ };
10077
+ const waitForAnchor = async (anchorId, timeoutMs) => {
10078
+ if (!matchesAnchorRoute(anchorId)) return null;
10079
+ try {
10080
+ return await anchorResolverService.waitFor(anchorId.selector, timeoutMs);
10081
+ } catch {
10082
+ return null;
10083
+ }
10084
+ };
9907
10085
  const surfaces = createSurfaces({
9908
10086
  overlayRoot,
9909
10087
  eventBus: events,
@@ -9915,6 +10093,7 @@ function createSmartCanvasRuntime(options = {}) {
9915
10093
  eventBus: events,
9916
10094
  surfaces,
9917
10095
  anchorResolver,
10096
+ waitForAnchor,
9918
10097
  executorRegistry: executors3,
9919
10098
  subscribeNavigation: (callback) => navigation.subscribe(callback),
9920
10099
  runtime: {
@@ -9935,6 +10114,7 @@ function createSmartCanvasRuntime(options = {}) {
9935
10114
  executors: executors3,
9936
10115
  apps,
9937
10116
  accumulator,
10117
+ anchorResolver: anchorResolverService,
9938
10118
  navigation,
9939
10119
  version: RUNTIME_VERSION,
9940
10120
  mode,
@@ -9974,6 +10154,7 @@ function createSmartCanvasRuntime(options = {}) {
9974
10154
  apps.unbind().catch((err) => {
9975
10155
  console.error("[Runtime] Error unbinding apps registry:", err);
9976
10156
  });
10157
+ anchorResolverService.destroy();
9977
10158
  accumulator.destroy();
9978
10159
  navigation.destroy();
9979
10160
  context.destroy();
@@ -10564,7 +10745,7 @@ async function init(options) {
10564
10745
  console.log(
10565
10746
  "[Syntro Bootstrap] Actions in config:",
10566
10747
  config.actions.map(
10567
- (a, i) => `[${i}] ${a.kind}${a.anchorId ? ` anchor="${a.anchorId}"` : ""}${a.label ? ` "${a.label}"` : ""}`
10748
+ (a, i) => `[${i}] ${a.kind}${a.anchorId ? ` anchor="${typeof a.anchorId === "string" ? a.anchorId : a.anchorId.selector}"` : ""}${a.label ? ` "${a.label}"` : ""}`
10568
10749
  ).join(", ")
10569
10750
  );
10570
10751
  }
@@ -10696,6 +10877,7 @@ export {
10696
10877
  validateAction,
10697
10878
  validateActions,
10698
10879
  createActionEngine,
10880
+ createAnchorResolver,
10699
10881
  ContextManager,
10700
10882
  createContextManager,
10701
10883
  evaluateCondition,
@@ -10734,4 +10916,4 @@ export {
10734
10916
  encodeToken,
10735
10917
  Syntro
10736
10918
  };
10737
- //# sourceMappingURL=chunk-VIGV46CB.js.map
10919
+ //# sourceMappingURL=chunk-LRN3K2VD.js.map