veo-sdk 0.3.0 → 0.3.2

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.
@@ -89,7 +89,7 @@ type BuilderEvent = {
89
89
  } | {
90
90
  type: 'closed';
91
91
  };
92
- /** Comandos que el dashboard envía a la app del cliente. */
92
+ /** Comandos que el dashboard/panel envía a la app del cliente. */
93
93
  type BuilderCommand = {
94
94
  type: 'start-picker';
95
95
  maxAncestors?: number;
@@ -103,16 +103,34 @@ type BuilderCommand = {
103
103
  type: 'close-preview';
104
104
  } | {
105
105
  type: 'teardown';
106
+ } | {
107
+ type: 'panel-ready';
106
108
  };
107
109
 
110
+ /**
111
+ * Lado APP del puente builder. Corre dentro de la app del cliente (vía
112
+ * veo-builder.js). Si el contexto trae `?veoBuilder=<token>`, se conecta con el
113
+ * editor de Veo, atiende comandos y devuelve el elemento elegido.
114
+ *
115
+ * Dos transportes:
116
+ * - **iframe/popup** (`resolveTarget` = opener/parent): el dashboard es la
117
+ * ventana principal y embebe/abre la app; le hablamos a esa ventana.
118
+ * - **panel inyectado** (`ctx.panel`): la app es top-level (login real) y NOSOTROS
119
+ * inyectamos el panel del editor encima (iframe al dashboard); le hablamos a
120
+ * ese iframe. Es el modo sin adaptación por app.
121
+ *
122
+ * Seguridad: solo acepta mensajes cuyo `origin` coincida con el del dashboard
123
+ * (`veoBuilderOrigin` / `document.referrer`) y cuyo `token` coincida.
124
+ */
125
+
108
126
  interface BuilderModeHandle {
109
- /** Desconecta el puente y limpia picker/preview. */
127
+ /** Desconecta el puente y limpia picker/preview/panel. */
110
128
  teardown(): void;
111
129
  }
112
130
  /**
113
- * Inicializa el modo builder si la URL trae el token. Devuelve un handle, o
114
- * `null` si no estamos en modo builder (uso normal de la app) o no hay un
115
- * canal con el dashboard. Es seguro llamarla siempre.
131
+ * Inicializa el modo builder si hay contexto (URL o persistido). Devuelve un
132
+ * handle, o `null` si no estamos en modo builder o no hay canal con el editor.
133
+ * Es seguro llamarla siempre.
116
134
  */
117
135
  declare function initBuilderMode(): BuilderModeHandle | null;
118
136
 
package/dist/builder.d.ts CHANGED
@@ -89,7 +89,7 @@ type BuilderEvent = {
89
89
  } | {
90
90
  type: 'closed';
91
91
  };
92
- /** Comandos que el dashboard envía a la app del cliente. */
92
+ /** Comandos que el dashboard/panel envía a la app del cliente. */
93
93
  type BuilderCommand = {
94
94
  type: 'start-picker';
95
95
  maxAncestors?: number;
@@ -103,16 +103,34 @@ type BuilderCommand = {
103
103
  type: 'close-preview';
104
104
  } | {
105
105
  type: 'teardown';
106
+ } | {
107
+ type: 'panel-ready';
106
108
  };
107
109
 
110
+ /**
111
+ * Lado APP del puente builder. Corre dentro de la app del cliente (vía
112
+ * veo-builder.js). Si el contexto trae `?veoBuilder=<token>`, se conecta con el
113
+ * editor de Veo, atiende comandos y devuelve el elemento elegido.
114
+ *
115
+ * Dos transportes:
116
+ * - **iframe/popup** (`resolveTarget` = opener/parent): el dashboard es la
117
+ * ventana principal y embebe/abre la app; le hablamos a esa ventana.
118
+ * - **panel inyectado** (`ctx.panel`): la app es top-level (login real) y NOSOTROS
119
+ * inyectamos el panel del editor encima (iframe al dashboard); le hablamos a
120
+ * ese iframe. Es el modo sin adaptación por app.
121
+ *
122
+ * Seguridad: solo acepta mensajes cuyo `origin` coincida con el del dashboard
123
+ * (`veoBuilderOrigin` / `document.referrer`) y cuyo `token` coincida.
124
+ */
125
+
108
126
  interface BuilderModeHandle {
109
- /** Desconecta el puente y limpia picker/preview. */
127
+ /** Desconecta el puente y limpia picker/preview/panel. */
110
128
  teardown(): void;
111
129
  }
112
130
  /**
113
- * Inicializa el modo builder si la URL trae el token. Devuelve un handle, o
114
- * `null` si no estamos en modo builder (uso normal de la app) o no hay un
115
- * canal con el dashboard. Es seguro llamarla siempre.
131
+ * Inicializa el modo builder si hay contexto (URL o persistido). Devuelve un
132
+ * handle, o `null` si no estamos en modo builder o no hay canal con el editor.
133
+ * Es seguro llamarla siempre.
116
134
  */
117
135
  declare function initBuilderMode(): BuilderModeHandle | null;
118
136
 
package/dist/builder.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import './chunk-G5CKTGEG.mjs';
2
- import { initBuilderMode } from './chunk-66UQ474G.mjs';
3
- export { createBuilderSession, initBuilderMode, startElementPicker, stopElementPicker } from './chunk-66UQ474G.mjs';
4
- export { closeGuidePreview, previewGuide } from './chunk-CI7NWEH2.mjs';
5
- import './chunk-JIU5JLI3.mjs';
1
+ import './chunk-R4E3LIDB.mjs';
2
+ import { initBuilderMode } from './chunk-7FVIFPGF.mjs';
3
+ export { createBuilderSession, initBuilderMode, startElementPicker, stopElementPicker } from './chunk-7FVIFPGF.mjs';
4
+ export { closeGuidePreview, previewGuide } from './chunk-GHP7ZJCW.mjs';
5
+ import './chunk-PTG3BTJE.mjs';
6
6
 
7
7
  // src/builder.ts
8
8
  initBuilderMode();
@@ -1,9 +1,82 @@
1
- import { hasDocument, hasWindow, resolveBuilderToken, resolveBuilderOrigin, closeGuidePreview, clearBuilderToken, buildSelectorPath, filterHumanClasses, previewGuide } from './chunk-CI7NWEH2.mjs';
2
- import { BUILDER_TOKEN_PARAM, BUILDER_ORIGIN_PARAM } from './chunk-JIU5JLI3.mjs';
1
+ import { hasDocument, hasWindow, resolveBuilderContext, closeGuidePreview, clearBuilderToken, buildSelectorPath, filterHumanClasses, previewGuide } from './chunk-GHP7ZJCW.mjs';
2
+ import { BUILDER_TOKEN_PARAM, BUILDER_ORIGIN_PARAM } from './chunk-PTG3BTJE.mjs';
3
3
 
4
4
  // src/plugins/builder/bridge-protocol.ts
5
5
  var VEO_BUILDER_SOURCE = "veo-builder";
6
6
 
7
+ // src/plugins/builder/builder-panel.ts
8
+ var DEFAULT_PANEL_PATH = "/guides/design";
9
+ function injectBuilderPanel(opts) {
10
+ if (!hasWindow() || !hasDocument()) {
11
+ return { target: () => null, teardown: () => {
12
+ } };
13
+ }
14
+ const host = document.createElement("div");
15
+ host.setAttribute("data-veo-builder-panel", "");
16
+ const shadow = host.attachShadow({ mode: "open" });
17
+ const style = document.createElement("style");
18
+ style.textContent = PANEL_CSS;
19
+ const container = document.createElement("div");
20
+ container.className = "veo-panel";
21
+ const header = document.createElement("div");
22
+ header.className = "veo-panel-header";
23
+ const title = document.createElement("span");
24
+ title.className = "veo-panel-title";
25
+ title.textContent = "Veo \xB7 Editor";
26
+ const close = document.createElement("button");
27
+ close.className = "veo-panel-close";
28
+ close.type = "button";
29
+ close.setAttribute("aria-label", "Cerrar");
30
+ close.textContent = "\u2715";
31
+ close.addEventListener("click", () => opts.onClose());
32
+ header.append(title, close);
33
+ const iframe = document.createElement("iframe");
34
+ iframe.className = "veo-panel-frame";
35
+ iframe.title = "Editor de Veo";
36
+ iframe.src = buildPanelUrl(opts);
37
+ container.append(header, iframe);
38
+ shadow.append(style, container);
39
+ document.body.appendChild(host);
40
+ return {
41
+ target: () => iframe.contentWindow,
42
+ teardown: () => host.remove()
43
+ };
44
+ }
45
+ function buildPanelUrl(opts) {
46
+ const path = opts.panelPath ?? DEFAULT_PANEL_PATH;
47
+ const url = new URL(path, opts.dashboardOrigin);
48
+ url.searchParams.set("veoToken", opts.token);
49
+ url.searchParams.set("veoApp", opts.appOrigin);
50
+ if (opts.guide) url.searchParams.set("veoGuide", opts.guide);
51
+ return url.toString();
52
+ }
53
+ var PANEL_CSS = `
54
+ :host { all: initial; }
55
+ .veo-panel {
56
+ position: fixed; top: 0; right: 0; bottom: 0;
57
+ width: 420px; max-width: 100vw;
58
+ display: flex; flex-direction: column;
59
+ background: #fff;
60
+ box-shadow: -8px 0 30px rgba(0,0,0,0.18);
61
+ z-index: 2147483647;
62
+ font-family: system-ui, -apple-system, sans-serif;
63
+ }
64
+ .veo-panel-header {
65
+ flex: 0 0 auto;
66
+ display: flex; align-items: center; justify-content: space-between;
67
+ padding: 8px 12px;
68
+ background: #0f172a; color: #fff;
69
+ font-size: 13px; font-weight: 600;
70
+ }
71
+ .veo-panel-close {
72
+ border: 0; background: transparent; color: #fff;
73
+ font-size: 15px; cursor: pointer; line-height: 1;
74
+ padding: 4px 6px; border-radius: 6px;
75
+ }
76
+ .veo-panel-close:hover { background: rgba(255,255,255,0.15); }
77
+ .veo-panel-frame { flex: 1 1 auto; width: 100%; border: 0; background: #fff; }
78
+ `;
79
+
7
80
  // src/plugins/builder/element-picker.ts
8
81
  var PICKER_Z = 2147483646;
9
82
  var PICKER_HOST_ATTR = "data-veo-picker";
@@ -202,18 +275,23 @@ function stopElementPicker() {
202
275
  // src/plugins/builder/builder-mode.ts
203
276
  function initBuilderMode() {
204
277
  if (!hasWindow() || !hasDocument()) return null;
205
- const token = resolveBuilderToken();
206
- if (!token) return null;
207
- const dashboardOrigin = resolveDashboardOrigin();
278
+ const ctx = resolveBuilderContext();
279
+ if (!ctx) return null;
280
+ const token = ctx.token;
281
+ const dashboardOrigin = resolveDashboardOrigin(ctx.origin);
208
282
  if (!dashboardOrigin) return null;
209
- const target = resolveTarget();
210
- if (!target) return null;
211
283
  let picker = null;
284
+ let panel = null;
285
+ let staticTarget = null;
286
+ const getTarget = () => panel ? panel.target() : staticTarget;
212
287
  const post = (event) => {
213
- target.postMessage({ source: VEO_BUILDER_SOURCE, token, ...event }, dashboardOrigin);
288
+ getTarget()?.postMessage({ source: VEO_BUILDER_SOURCE, token, ...event }, dashboardOrigin);
214
289
  };
215
290
  const handleCommand = (cmd) => {
216
291
  switch (cmd.type) {
292
+ case "panel-ready":
293
+ post({ type: "ready" });
294
+ break;
217
295
  case "start-picker":
218
296
  picker?.stop();
219
297
  picker = startElementPicker({
@@ -257,13 +335,28 @@ function initBuilderMode() {
257
335
  picker?.stop();
258
336
  picker = null;
259
337
  closeGuidePreview();
260
- clearBuilderToken();
261
338
  post({ type: "closed" });
339
+ panel?.teardown();
340
+ panel = null;
341
+ clearBuilderToken();
262
342
  };
343
+ if (ctx.panel) {
344
+ panel = injectBuilderPanel({
345
+ dashboardOrigin,
346
+ token,
347
+ appOrigin: window.location.origin,
348
+ guide: ctx.guide,
349
+ panelPath: ctx.panelPath,
350
+ onClose: () => teardown()
351
+ });
352
+ } else {
353
+ staticTarget = resolveTarget();
354
+ if (!staticTarget) return null;
355
+ }
263
356
  const activate = () => {
264
357
  window.addEventListener("message", onMessage);
265
358
  window.addEventListener("pagehide", onPageHide);
266
- post({ type: "ready" });
359
+ if (!ctx.panel) post({ type: "ready" });
267
360
  };
268
361
  const cfg = window.__veoBuilder;
269
362
  if (cfg?.apiKey && cfg?.apiUrl) {
@@ -296,11 +389,10 @@ function resolveTarget() {
296
389
  if (window.parent && window.parent !== window) return window.parent;
297
390
  return null;
298
391
  }
299
- function resolveDashboardOrigin() {
300
- const stored = resolveBuilderOrigin();
301
- if (stored) {
392
+ function resolveDashboardOrigin(originHint) {
393
+ if (originHint) {
302
394
  try {
303
- return new URL(stored).origin;
395
+ return new URL(originHint).origin;
304
396
  } catch {
305
397
  return null;
306
398
  }
@@ -435,5 +527,5 @@ function noopSession() {
435
527
  }
436
528
 
437
529
  export { createBuilderSession, initBuilderMode, startElementPicker, stopElementPicker };
438
- //# sourceMappingURL=chunk-66UQ474G.mjs.map
439
- //# sourceMappingURL=chunk-66UQ474G.mjs.map
530
+ //# sourceMappingURL=chunk-7FVIFPGF.mjs.map
531
+ //# sourceMappingURL=chunk-7FVIFPGF.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugins/builder/bridge-protocol.ts","../src/plugins/builder/builder-panel.ts","../src/plugins/builder/element-picker.ts","../src/plugins/builder/builder-mode.ts","../src/plugins/builder/builder-session.ts"],"names":[],"mappings":"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","file":"chunk-7FVIFPGF.mjs","sourcesContent":["/**\n * Contrato de mensajes del puente builder (app del cliente ↔ dashboard).\n * Ambos lados validan `event.origin` y que `token` coincida antes de actuar.\n *\n * Flujo:\n * 1. El dashboard abre la app con `?veoBuilder=<token>&veoBuilderOrigin=<origen>`.\n * 2. La app (veo-builder.js) postea `ready` a la ventana que la abrió.\n * 3. El dashboard manda comandos (`start-picker`, `preview`, …).\n * 4. La app responde con eventos (`picked`, `pick-cancelled`, …).\n */\nimport type { PreviewGuideInput } from '../guides/guide-preview';\nimport type { PickedElement } from './element-picker';\n\nexport const VEO_BUILDER_SOURCE = 'veo-builder';\n// Los nombres de los query params viven en el core (`builder-token.ts`), única\n// fuente de verdad compartida con el loader y el gate del runtime de guías.\nexport { BUILDER_ORIGIN_PARAM, BUILDER_TOKEN_PARAM } from '../../core/builder-token';\n\n/** Eventos que la app del cliente envía al dashboard. */\nexport type BuilderEvent =\n | { type: 'ready' }\n | { type: 'picked'; payload: PickedElement }\n | { type: 'pick-cancelled' }\n | { type: 'closed' };\n\n/** Comandos que el dashboard/panel envía a la app del cliente. */\nexport type BuilderCommand =\n | { type: 'start-picker'; maxAncestors?: number; hint?: string }\n | { type: 'stop-picker' }\n | { type: 'preview'; guide: PreviewGuideInput }\n | { type: 'close-preview' }\n | { type: 'teardown' }\n // Modo panel inyectado: el panel avisa que cargó y está listo para recibir\n // eventos; la app responde con `ready`. Resuelve la carrera de que el iframe\n // del panel todavía no tenga su listener cuando la app postea `ready`.\n | { type: 'panel-ready' };\n\n/** Sobre común: todo mensaje del puente lleva `source` + `token`. */\nexport interface BuilderEnvelope {\n source: typeof VEO_BUILDER_SOURCE;\n token: string;\n}\n\nexport type BuilderEventMessage = BuilderEnvelope & BuilderEvent;\nexport type BuilderCommandMessage = BuilderEnvelope & BuilderCommand;\n","/**\n * Modo \"panel inyectado\" (editor en la pestaña de la app).\n *\n * Al revés del modo iframe/popup: acá **la app es la pestaña top-level** (donde\n * el usuario ya se logueó normal) y el editor de Veo se inyecta ENCIMA, como un\n * panel flotante (un iframe apuntando al dashboard). Así no hace falta ninguna\n * adaptación de la app (ni demo-user, ni framing, ni cookies): el login real\n * funciona porque nada está embebido.\n *\n * El panel corre en el origen del dashboard (tiene la sesión de Veo para guardar\n * guías) y habla con la app (su `window.parent`) por el mismo puente postMessage.\n * Este módulo solo INYECTA el iframe y expone su `contentWindow` como target.\n */\nimport { hasDocument, hasWindow } from '../../utils/safe-env';\n\n/** Path por defecto del panel del editor en el dashboard. */\nconst DEFAULT_PANEL_PATH = '/guides/design';\n\nexport interface BuilderPanelOptions {\n /** Origen del dashboard de Veo (donde vive el panel). */\n dashboardOrigin: string;\n /** Token de correlación del handshake. */\n token: string;\n /** Origen de la app (para que el panel valide los mensajes del parent). */\n appOrigin: string;\n /** Id de la guía en edición (opcional). */\n guide: string | null;\n /** Override del path del panel (default `/guides/design`). */\n panelPath: string | null;\n /** Se llama cuando el usuario cierra el panel (× del header). */\n onClose: () => void;\n}\n\nexport interface BuilderPanelHandle {\n /** Ventana destino de los mensajes: el `contentWindow` del iframe del panel. */\n target(): Window | null;\n /** Quita el panel del DOM. */\n teardown(): void;\n}\n\n/** Inyecta el panel del editor como sidebar flotante y devuelve un handle. */\nexport function injectBuilderPanel(opts: BuilderPanelOptions): BuilderPanelHandle {\n if (!hasWindow() || !hasDocument()) {\n return { target: () => null, teardown: () => {} };\n }\n\n const host = document.createElement('div');\n host.setAttribute('data-veo-builder-panel', '');\n const shadow = host.attachShadow({ mode: 'open' });\n\n const style = document.createElement('style');\n style.textContent = PANEL_CSS;\n\n const container = document.createElement('div');\n container.className = 'veo-panel';\n\n const header = document.createElement('div');\n header.className = 'veo-panel-header';\n const title = document.createElement('span');\n title.className = 'veo-panel-title';\n title.textContent = 'Veo · Editor';\n const close = document.createElement('button');\n close.className = 'veo-panel-close';\n close.type = 'button';\n close.setAttribute('aria-label', 'Cerrar');\n close.textContent = '✕';\n close.addEventListener('click', () => opts.onClose());\n header.append(title, close);\n\n const iframe = document.createElement('iframe');\n iframe.className = 'veo-panel-frame';\n iframe.title = 'Editor de Veo';\n iframe.src = buildPanelUrl(opts);\n\n container.append(header, iframe);\n shadow.append(style, container);\n document.body.appendChild(host);\n\n return {\n target: () => iframe.contentWindow,\n teardown: () => host.remove(),\n };\n}\n\nfunction buildPanelUrl(opts: BuilderPanelOptions): string {\n const path = opts.panelPath ?? DEFAULT_PANEL_PATH;\n const url = new URL(path, opts.dashboardOrigin);\n url.searchParams.set('veoToken', opts.token);\n url.searchParams.set('veoApp', opts.appOrigin);\n if (opts.guide) url.searchParams.set('veoGuide', opts.guide);\n return url.toString();\n}\n\nconst PANEL_CSS = `\n:host { all: initial; }\n.veo-panel {\n position: fixed; top: 0; right: 0; bottom: 0;\n width: 420px; max-width: 100vw;\n display: flex; flex-direction: column;\n background: #fff;\n box-shadow: -8px 0 30px rgba(0,0,0,0.18);\n z-index: 2147483647;\n font-family: system-ui, -apple-system, sans-serif;\n}\n.veo-panel-header {\n flex: 0 0 auto;\n display: flex; align-items: center; justify-content: space-between;\n padding: 8px 12px;\n background: #0f172a; color: #fff;\n font-size: 13px; font-weight: 600;\n}\n.veo-panel-close {\n border: 0; background: transparent; color: #fff;\n font-size: 15px; cursor: pointer; line-height: 1;\n padding: 4px 6px; border-radius: 6px;\n}\n.veo-panel-close:hover { background: rgba(255,255,255,0.15); }\n.veo-panel-frame { flex: 1 1 auto; width: 100%; border: 0; background: #fff; }\n`;\n","/**\n * Element picker — el \"inspeccionar\" del navegador, pero del SDK. Corre\n * DENTRO de la app del cliente (no en el dashboard: son orígenes distintos\n * y el dashboard no puede leer el DOM de la app). Resalta el elemento bajo\n * el cursor, muestra su selector + dimensiones, y al hacer click captura un\n * selector CSS estable reutilizando `buildSelectorPath` del autocapture.\n *\n * Es la base del builder no-code: el dashboard abre la app del cliente en\n * modo builder, el usuario \"pincha\" un elemento y el selector resultante se\n * usa como ancla de un tooltip/walkthrough. El puente con el dashboard\n * (postMessage) es la fase siguiente; aquí exponemos el primitivo\n * `startElementPicker(onPick)`.\n *\n * No usa `innerHTML` — todo por `textContent`/DOM, igual que los renderers.\n */\n\nimport { hasDocument } from '../../utils/safe-env';\nimport { buildSelectorPath, filterHumanClasses } from '../autocapture/selector-builder';\n\n/** z-index por encima de las guías (2147483640) para tapar también una preview. */\nconst PICKER_Z = 2147483646;\nconst PICKER_HOST_ATTR = 'data-veo-picker';\nconst DEFAULT_MAX_ANCESTORS = 5;\n\n/** Datos del elemento elegido que se entregan al caller. */\nexport interface PickedElement {\n /** Selector CSS estable con ancestros (lo que se guarda como ancla). */\n selector: string;\n /** Selector corto solo del elemento (tag + id/atributo/clases). */\n shortSelector: string;\n tag: string;\n id: string | null;\n classes: string[];\n text: string;\n rect: { x: number; y: number; width: number; height: number };\n}\n\nexport interface ElementPickerOptions {\n /** Llamado al hacer click en un elemento. El picker se cierra tras esto. */\n onPick: (picked: PickedElement) => void;\n /** Llamado al cancelar (Esc). El picker se cierra. */\n onCancel?: () => void;\n /** Niveles de ancestros del selector. Default 5 (igual que autocapture). */\n maxAncestors?: number;\n /** Texto del banner superior. Default en español. */\n hint?: string;\n}\n\nexport interface ElementPickerHandle {\n /** Cierra el picker sin elegir nada. Idempotente. */\n stop(): void;\n}\n\nconst PICKER_STYLES = `\n:host { all: initial; }\n.veo-pick-box {\n position: fixed;\n z-index: ${PICKER_Z};\n pointer-events: none;\n box-sizing: border-box;\n background: rgba(99, 102, 241, 0.22);\n border: 1px dashed rgba(99, 102, 241, 0.95);\n border-radius: 2px;\n transition: top 60ms ease-out, left 60ms ease-out, width 60ms ease-out, height 60ms ease-out;\n}\n.veo-pick-label {\n position: fixed;\n z-index: ${PICKER_Z};\n pointer-events: none;\n max-width: 360px;\n background: #1e1b4b;\n color: #e0e7ff;\n font: 12px/1.45 ui-monospace, SFMono-Regular, Menlo, monospace;\n padding: 6px 9px;\n border-radius: 6px;\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);\n}\n.veo-pick-label .veo-pick-sel { color: #c7d2fe; word-break: break-all; }\n.veo-pick-label .veo-pick-dim { color: #a5b4fc; margin-top: 3px; }\n.veo-pick-hint {\n position: fixed;\n top: 12px;\n left: 50%;\n transform: translateX(-50%);\n z-index: ${PICKER_Z};\n pointer-events: none;\n background: #4338ca;\n color: #fff;\n font: 13px/1 -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n padding: 8px 14px;\n border-radius: 999px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);\n}\n`;\n\n/**\n * Controla un picker activo. Singleton a nivel de módulo: empezar otro\n * cierra el anterior. Los listeners van en fase de captura para poder\n * cancelar el click ANTES de que la app del cliente reaccione.\n */\nclass ElementPicker {\n private host: HTMLElement | null = null;\n private box: HTMLElement | null = null;\n private label: HTMLElement | null = null;\n private current: Element | null = null;\n private maxAncestors = DEFAULT_MAX_ANCESTORS;\n private onPick: ((p: PickedElement) => void) | null = null;\n private onCancel: (() => void) | null = null;\n\n start(options: ElementPickerOptions): void {\n this.stop(); // solo un picker a la vez\n\n this.maxAncestors = options.maxAncestors ?? DEFAULT_MAX_ANCESTORS;\n this.onPick = options.onPick;\n this.onCancel = options.onCancel ?? null;\n\n const host = document.createElement('div');\n host.setAttribute(PICKER_HOST_ATTR, '');\n const shadow = host.attachShadow({ mode: 'open' });\n\n const style = document.createElement('style');\n style.textContent = PICKER_STYLES;\n\n this.box = document.createElement('div');\n this.box.className = 'veo-pick-box';\n this.box.style.display = 'none';\n\n this.label = document.createElement('div');\n this.label.className = 'veo-pick-label';\n this.label.style.display = 'none';\n\n const hint = document.createElement('div');\n hint.className = 'veo-pick-hint';\n hint.textContent = options.hint ?? 'Seleccioná un elemento · Esc para cancelar';\n\n shadow.append(style, this.box, this.label, hint);\n document.body.appendChild(host);\n this.host = host;\n\n document.addEventListener('mousemove', this.onMove, true);\n document.addEventListener('click', this.onClick, true);\n document.addEventListener('mousedown', this.swallow, true);\n document.addEventListener('mouseup', this.swallow, true);\n document.addEventListener('keydown', this.onKey, true);\n window.addEventListener('scroll', this.reposition, true);\n window.addEventListener('resize', this.reposition);\n }\n\n stop(): void {\n document.removeEventListener('mousemove', this.onMove, true);\n document.removeEventListener('click', this.onClick, true);\n document.removeEventListener('mousedown', this.swallow, true);\n document.removeEventListener('mouseup', this.swallow, true);\n document.removeEventListener('keydown', this.onKey, true);\n window.removeEventListener('scroll', this.reposition, true);\n window.removeEventListener('resize', this.reposition);\n\n if (this.host?.parentNode) this.host.parentNode.removeChild(this.host);\n this.host = null;\n this.box = null;\n this.label = null;\n this.current = null;\n this.onPick = null;\n this.onCancel = null;\n }\n\n /** ¿Es un nodo de nuestro propio overlay? (no debe ser seleccionable). */\n private isOwn(target: EventTarget | null): boolean {\n return target instanceof Node && this.host !== null && this.host.contains(target);\n }\n\n private onMove = (event: MouseEvent): void => {\n const target = event.target;\n if (!(target instanceof Element) || this.isOwn(target)) return;\n this.current = target;\n this.draw(target);\n };\n\n private onClick = (event: MouseEvent): void => {\n const target = this.current ?? (event.target instanceof Element ? event.target : null);\n if (!target || this.isOwn(target)) return;\n\n // Evitar que la app reaccione al click de selección.\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n\n const picked = this.describe(target);\n const cb = this.onPick;\n this.stop();\n cb?.(picked);\n };\n\n private onKey = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n event.stopPropagation();\n const cb = this.onCancel;\n this.stop();\n cb?.();\n };\n\n /** Traga mousedown/mouseup durante el picking (evita focus/active de la app). */\n private swallow = (event: MouseEvent): void => {\n if (this.isOwn(event.target)) return;\n event.preventDefault();\n event.stopPropagation();\n };\n\n private reposition = (): void => {\n if (this.current) this.draw(this.current);\n };\n\n /** Dibuja el recuadro de resalte y la etiqueta sobre el elemento dado. */\n private draw(element: Element): void {\n if (!this.box || !this.label) return;\n const rect = element.getBoundingClientRect();\n\n this.box.style.display = 'block';\n this.box.style.top = `${rect.top}px`;\n this.box.style.left = `${rect.left}px`;\n this.box.style.width = `${rect.width}px`;\n this.box.style.height = `${rect.height}px`;\n\n const shortSel = buildSelectorPath(element, 0);\n this.label.textContent = '';\n const sel = document.createElement('div');\n sel.className = 'veo-pick-sel';\n sel.textContent = shortSel;\n const dim = document.createElement('div');\n dim.className = 'veo-pick-dim';\n dim.textContent = `${Math.round(rect.width)} × ${Math.round(rect.height)}`;\n this.label.append(sel, dim);\n\n // Etiqueta debajo del recuadro; si no hay espacio, arriba.\n this.label.style.display = 'block';\n const LABEL_H = 48;\n const placeAbove = rect.bottom + 8 + LABEL_H > window.innerHeight;\n this.label.style.top = placeAbove\n ? `${Math.max(8, rect.top - LABEL_H - 8)}px`\n : `${rect.bottom + 8}px`;\n this.label.style.left = `${Math.max(8, rect.left)}px`;\n }\n\n private describe(element: Element): PickedElement {\n const rect = element.getBoundingClientRect();\n return {\n selector: buildSelectorPath(element, this.maxAncestors),\n shortSelector: buildSelectorPath(element, 0),\n tag: element.tagName.toLowerCase(),\n id: element.id || null,\n classes: filterHumanClasses(element),\n text: (element.textContent ?? '').trim().slice(0, 120),\n rect: {\n x: Math.round(rect.left),\n y: Math.round(rect.top),\n width: Math.round(rect.width),\n height: Math.round(rect.height),\n },\n };\n }\n}\n\nlet activePicker: ElementPicker | null = null;\n\n/**\n * Inicia el modo de selección de elementos (inspector). Resalta lo que está\n * bajo el cursor y, al hacer click, entrega un selector CSS estable.\n * Devuelve un handle con `stop()`. Iniciar otro picker cierra el anterior.\n *\n * @example\n * ```ts\n * import { startElementPicker } from '@veo/sdk';\n *\n * const picker = startElementPicker({\n * onPick: ({ selector }) => console.log('elegido:', selector),\n * onCancel: () => console.log('cancelado'),\n * });\n * // picker.stop() para abortar manualmente.\n * ```\n */\nexport function startElementPicker(options: ElementPickerOptions): ElementPickerHandle {\n if (!hasDocument()) {\n return { stop: () => {} };\n }\n if (!activePicker) activePicker = new ElementPicker();\n activePicker.start(options);\n return { stop: () => activePicker?.stop() };\n}\n\n/** Cierra el picker activo, si lo hay. Idempotente. */\nexport function stopElementPicker(): void {\n activePicker?.stop();\n}\n","/**\n * Lado APP del puente builder. Corre dentro de la app del cliente (vía\n * veo-builder.js). Si el contexto trae `?veoBuilder=<token>`, se conecta con el\n * editor de Veo, atiende comandos y devuelve el elemento elegido.\n *\n * Dos transportes:\n * - **iframe/popup** (`resolveTarget` = opener/parent): el dashboard es la\n * ventana principal y embebe/abre la app; le hablamos a esa ventana.\n * - **panel inyectado** (`ctx.panel`): la app es top-level (login real) y NOSOTROS\n * inyectamos el panel del editor encima (iframe al dashboard); le hablamos a\n * ese iframe. Es el modo sin adaptación por app.\n *\n * Seguridad: solo acepta mensajes cuyo `origin` coincida con el del dashboard\n * (`veoBuilderOrigin` / `document.referrer`) y cuyo `token` coincida.\n */\nimport {\n type BuilderClientContext,\n clearBuilderToken,\n resolveBuilderContext,\n} from '../../core/builder-token';\nimport { hasDocument, hasWindow } from '../../utils/safe-env';\nimport { closeGuidePreview, previewGuide } from '../guides/guide-preview';\nimport { type BuilderCommand, type BuilderEvent, VEO_BUILDER_SOURCE } from './bridge-protocol';\nimport { type BuilderPanelHandle, injectBuilderPanel } from './builder-panel';\nimport { type ElementPickerHandle, startElementPicker } from './element-picker';\n\nexport interface BuilderModeHandle {\n /** Desconecta el puente y limpia picker/preview/panel. */\n teardown(): void;\n}\n\n/**\n * Inicializa el modo builder si hay contexto (URL o persistido). Devuelve un\n * handle, o `null` si no estamos en modo builder o no hay canal con el editor.\n * Es seguro llamarla siempre.\n */\nexport function initBuilderMode(): BuilderModeHandle | null {\n if (!hasWindow() || !hasDocument()) return null;\n\n // Contexto de la URL o de sessionStorage: sobrevive al redirect del guard de\n // auth (que suele tirar el query string) y a un login en la misma pestaña.\n const ctx = resolveBuilderContext();\n if (!ctx) return null;\n\n const token = ctx.token;\n const dashboardOrigin = resolveDashboardOrigin(ctx.origin);\n if (!dashboardOrigin) return null;\n\n let picker: ElementPickerHandle | null = null;\n let panel: BuilderPanelHandle | null = null;\n let staticTarget: Window | null = null;\n const getTarget = (): Window | null => (panel ? panel.target() : staticTarget);\n\n const post = (event: BuilderEvent): void => {\n getTarget()?.postMessage({ source: VEO_BUILDER_SOURCE, token, ...event }, dashboardOrigin);\n };\n\n const handleCommand = (cmd: BuilderCommand): void => {\n switch (cmd.type) {\n case 'panel-ready':\n // El panel cargó y ya escucha → recién ahora le mandamos `ready`.\n post({ type: 'ready' });\n break;\n case 'start-picker':\n picker?.stop();\n picker = startElementPicker({\n onPick: (payload) => {\n picker = null;\n post({ type: 'picked', payload });\n },\n onCancel: () => {\n picker = null;\n post({ type: 'pick-cancelled' });\n },\n ...(cmd.maxAncestors !== undefined ? { maxAncestors: cmd.maxAncestors } : {}),\n ...(cmd.hint !== undefined ? { hint: cmd.hint } : {}),\n });\n break;\n case 'stop-picker':\n picker?.stop();\n picker = null;\n break;\n case 'preview':\n if (cmd.guide) void previewGuide(cmd.guide).ready;\n break;\n case 'close-preview':\n closeGuidePreview();\n break;\n case 'teardown':\n teardown();\n break;\n }\n };\n\n const onMessage = (event: MessageEvent): void => {\n if (event.origin !== dashboardOrigin) return;\n const data = event.data as { source?: unknown; token?: unknown } | null;\n if (!data || data.source !== VEO_BUILDER_SOURCE || data.token !== token) return;\n handleCommand(data as BuilderCommand);\n };\n\n const onPageHide = (): void => post({ type: 'closed' });\n\n const teardown = (): void => {\n window.removeEventListener('message', onMessage);\n window.removeEventListener('pagehide', onPageHide);\n picker?.stop();\n picker = null;\n closeGuidePreview();\n post({ type: 'closed' }); // avisar al editor ANTES de sacar el panel\n panel?.teardown();\n panel = null;\n clearBuilderToken(); // salir del modo builder: no re-activar en la próxima carga\n };\n\n // Transporte: panel inyectado (app top-level) o iframe/popup (embebida).\n if (ctx.panel) {\n panel = injectBuilderPanel({\n dashboardOrigin,\n token,\n appOrigin: window.location.origin,\n guide: ctx.guide,\n panelPath: ctx.panelPath,\n onClose: () => teardown(),\n });\n } else {\n staticTarget = resolveTarget();\n if (!staticTarget) return null;\n }\n\n const activate = (): void => {\n window.addEventListener('message', onMessage);\n window.addEventListener('pagehide', onPageHide);\n // Panel: esperamos el `panel-ready` del iframe para postear `ready` (todavía\n // puede no tener su listener). iframe/popup: el opener ya escucha → posteamos ya.\n if (!ctx.panel) post({ type: 'ready' });\n };\n\n // Verificación del token contra el backend (firmado + scopeado por workspace)\n // ANTES de activar. Si `init()` dejó la config (integración real) verificamos;\n // si el backend dice explícitamente que NO es válido, no activamos. Si no hay\n // config (demo) o el backend no responde, activamos best-effort.\n const cfg = (window as unknown as { __veoBuilder?: { apiKey?: string; apiUrl?: string } })\n .__veoBuilder;\n if (cfg?.apiKey && cfg?.apiUrl) {\n void verifyBuilderToken(cfg.apiUrl, cfg.apiKey, token).then((ok) => {\n if (ok) activate();\n else if (window.console) console.warn('[veo] token de builder inválido — modo no activado');\n });\n } else {\n activate();\n }\n\n return { teardown };\n}\n\n/**\n * Verifica el token con el backend. Solo devuelve `false` (no activar) cuando el\n * backend responde explícitamente `{valid:false}` (token forjado/expirado/de\n * otro workspace). Ante 404/red caída/errores transitorios devuelve `true`\n * (best-effort) para no brickear el modo builder.\n */\nasync function verifyBuilderToken(apiUrl: string, apiKey: string, token: string): Promise<boolean> {\n try {\n const url = `${apiUrl.replace(/\\/+$/, '')}/v1/builder/verify`;\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-Api-Key': apiKey },\n body: JSON.stringify({ token }),\n });\n if (!res.ok) return true; // no pudimos verificar → best-effort\n const data = (await res.json().catch(() => null)) as { valid?: unknown } | null;\n return data?.valid !== false;\n } catch {\n return true; // red caída / sin backend → best-effort\n }\n}\n\n/** Ventana con la que hablar en modo iframe/popup: el opener o el parent. */\nfunction resolveTarget(): Window | null {\n if (window.opener && window.opener !== window) return window.opener as Window;\n if (window.parent && window.parent !== window) return window.parent;\n return null;\n}\n\nfunction resolveDashboardOrigin(originHint: string | null): string | null {\n // Origen de la URL o persistido en el primer arranque (antes del redirect).\n if (originHint) {\n try {\n return new URL(originHint).origin;\n } catch {\n return null;\n }\n }\n // Fallback: el referrer. Poco fiable tras un redirect same-origin (apunta a la\n // propia app), por eso el origen persistido va primero.\n if (hasDocument() && document.referrer) {\n try {\n return new URL(document.referrer).origin;\n } catch {\n return null;\n }\n }\n return null;\n}\n\n// Tipo re-exportado para consumidores que tipan el contexto.\nexport type { BuilderClientContext };\n","/**\n * Lado DASHBOARD del puente builder. Abre la app del cliente en un popup,\n * en modo builder, y expone una API para pedirle que seleccione un elemento\n * o previsualice una guía. Pensado para importarse en el dashboard\n * (`import { createBuilderSession } from '@veo/sdk/builder'`).\n *\n * Seguridad: solo procesa mensajes cuyo `origin` sea el de la app y cuyo\n * `token` coincida con el de esta sesión.\n */\nimport { hasWindow } from '../../utils/safe-env';\nimport type { PreviewGuideInput } from '../guides/guide-preview';\nimport {\n BUILDER_ORIGIN_PARAM,\n BUILDER_TOKEN_PARAM,\n type BuilderCommand,\n VEO_BUILDER_SOURCE,\n} from './bridge-protocol';\nimport type { PickedElement } from './element-picker';\n\nexport interface BuilderSessionOptions {\n /** URL de la app del cliente a abrir en modo builder. */\n appUrl: string;\n /** Token de la sesión (idealmente emitido/firmado por el backend). */\n token: string;\n /** Origen al que la app debe responder. Default: `location.origin`. */\n dashboardOrigin?: string;\n /** La app está lista y escuchando comandos. */\n onReady?: () => void;\n /** El usuario eligió un elemento. */\n onPicked?: (picked: PickedElement) => void;\n /** El usuario canceló la selección (Esc). */\n onCancelled?: () => void;\n /** La app cerró el modo builder (o el popup se cerró). */\n onClosed?: () => void;\n /**\n * Si se pasa, la app se embebe en este `<iframe>` (modo estudio in-app) en\n * lugar de abrirse en un popup. El lado app ya habla con `window.parent`,\n * así que el puente funciona igual. La sesión setea el `src` del iframe.\n */\n frame?: HTMLIFrameElement;\n /** Nombre de la ventana popup. Default: `veo-builder`. */\n windowName?: string;\n /** Features del popup. Default: ventana de ~1280×860. */\n windowFeatures?: string;\n}\n\nexport interface BuilderSession {\n /** Pide a la app que entre en modo selección de elemento. */\n startPicker(options?: { maxAncestors?: number; hint?: string }): void;\n /** Cancela la selección en curso. */\n stopPicker(): void;\n /** Pide a la app que previsualice una guía. */\n preview(guide: PreviewGuideInput): void;\n /** Cierra la preview activa en la app. */\n closePreview(): void;\n /** Cierra el popup y desconecta el puente. */\n close(): void;\n}\n\nconst DEFAULT_FEATURES = 'popup,width=1280,height=860';\nconst POPUP_POLL_MS = 600;\n\nexport function createBuilderSession(options: BuilderSessionOptions): BuilderSession {\n if (!hasWindow()) return noopSession();\n\n const dashboardOrigin = options.dashboardOrigin ?? window.location.origin;\n const appOrigin = safeOrigin(options.appUrl);\n const url = buildAppUrl(options.appUrl, options.token, dashboardOrigin);\n\n const frame = options.frame ?? null;\n const useFrame = frame !== null;\n\n let popup: Window | null = null;\n if (useFrame) {\n // biome-ignore lint/style/noNonNullAssertion: useFrame garantiza frame\n frame!.src = url;\n } else {\n popup = window.open(\n url,\n options.windowName ?? 'veo-builder',\n options.windowFeatures ?? DEFAULT_FEATURES,\n );\n }\n\n /** Ventana destino de los comandos: el popup o el contentWindow del iframe. */\n const targetWindow = (): Window | null => (useFrame ? (frame?.contentWindow ?? null) : popup);\n\n const post = (command: BuilderCommand): void => {\n const w = targetWindow();\n if (!w) return;\n if (!useFrame && popup?.closed) return;\n w.postMessage(\n { source: VEO_BUILDER_SOURCE, token: options.token, ...command },\n appOrigin ?? '*',\n );\n };\n\n let pollTimer: ReturnType<typeof setInterval> | undefined;\n\n const cleanup = (): void => {\n window.removeEventListener('message', onMessage);\n if (pollTimer !== undefined) {\n clearInterval(pollTimer);\n pollTimer = undefined;\n }\n };\n\n const onMessage = (event: MessageEvent): void => {\n if (appOrigin && event.origin !== appOrigin) return;\n const data = event.data as {\n source?: unknown;\n token?: unknown;\n type?: unknown;\n payload?: unknown;\n } | null;\n if (!data || data.source !== VEO_BUILDER_SOURCE || data.token !== options.token) return;\n\n switch (data.type) {\n case 'ready':\n options.onReady?.();\n break;\n case 'picked':\n if (data.payload) options.onPicked?.(data.payload as PickedElement);\n break;\n case 'pick-cancelled':\n options.onCancelled?.();\n break;\n case 'closed':\n cleanup();\n options.onClosed?.();\n break;\n }\n };\n\n window.addEventListener('message', onMessage);\n\n // Detectar cierre manual del popup (el usuario cierra la ventana). En modo\n // iframe el ciclo de vida lo controla el dashboard (no hay nada que pollear).\n if (!useFrame) {\n pollTimer = setInterval(() => {\n if (popup?.closed) {\n cleanup();\n options.onClosed?.();\n }\n }, POPUP_POLL_MS);\n }\n\n return {\n startPicker: (o) =>\n post({\n type: 'start-picker',\n ...(o?.maxAncestors !== undefined ? { maxAncestors: o.maxAncestors } : {}),\n ...(o?.hint !== undefined ? { hint: o.hint } : {}),\n }),\n stopPicker: () => post({ type: 'stop-picker' }),\n preview: (guide) => post({ type: 'preview', guide }),\n closePreview: () => post({ type: 'close-preview' }),\n close: () => {\n post({ type: 'teardown' });\n if (useFrame) {\n if (frame) frame.src = 'about:blank';\n } else if (popup && !popup.closed) {\n popup.close();\n }\n cleanup();\n },\n };\n}\n\nfunction buildAppUrl(appUrl: string, token: string, dashboardOrigin: string): string {\n try {\n const u = new URL(appUrl, window.location.href);\n u.searchParams.set(BUILDER_TOKEN_PARAM, token);\n u.searchParams.set(BUILDER_ORIGIN_PARAM, dashboardOrigin);\n return u.toString();\n } catch {\n return appUrl;\n }\n}\n\nfunction safeOrigin(url: string): string | null {\n try {\n return new URL(url, window.location.href).origin;\n } catch {\n return null;\n }\n}\n\nfunction noopSession(): BuilderSession {\n return {\n startPicker: () => {},\n stopPicker: () => {},\n preview: () => {},\n closePreview: () => {},\n close: () => {},\n };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { BUILDER_TOKEN_PARAM, BUILDER_ORIGIN_PARAM } from './chunk-JIU5JLI3.mjs';
1
+ import { BUILDER_TOKEN_PARAM, BUILDER_PANEL_PATH_PARAM, BUILDER_GUIDE_PARAM, BUILDER_PANEL_PARAM, BUILDER_ORIGIN_PARAM } from './chunk-PTG3BTJE.mjs';
2
2
  import { computePosition, offset, flip, shift, arrow } from '@floating-ui/dom';
3
3
 
4
4
  // src/utils/safe-env.ts
@@ -24,8 +24,7 @@ function hasNavigatorSendBeacon() {
24
24
  }
25
25
 
26
26
  // src/core/builder-token.ts
27
- var TOKEN_KEY = "veo:builder_token";
28
- var ORIGIN_KEY = "veo:builder_origin";
27
+ var CTX_KEY = "veo:builder_ctx";
29
28
  function session() {
30
29
  try {
31
30
  return window.sessionStorage;
@@ -40,45 +39,41 @@ function urlParams() {
40
39
  return null;
41
40
  }
42
41
  }
43
- function resolveBuilderToken() {
42
+ function resolveBuilderContext() {
44
43
  if (!hasWindow()) return null;
45
44
  const params = urlParams();
46
45
  const fromUrl = params?.get(BUILDER_TOKEN_PARAM);
47
46
  if (fromUrl) {
48
- const store = session();
47
+ const ctx = {
48
+ token: fromUrl,
49
+ origin: params?.get(BUILDER_ORIGIN_PARAM) ?? null,
50
+ panel: params?.get(BUILDER_PANEL_PARAM) === "1",
51
+ guide: params?.get(BUILDER_GUIDE_PARAM) ?? null,
52
+ panelPath: params?.get(BUILDER_PANEL_PATH_PARAM) ?? null
53
+ };
49
54
  try {
50
- store?.setItem(TOKEN_KEY, fromUrl);
51
- const origin = params?.get(BUILDER_ORIGIN_PARAM);
52
- if (origin) store?.setItem(ORIGIN_KEY, origin);
55
+ session()?.setItem(CTX_KEY, JSON.stringify(ctx));
53
56
  } catch {
54
57
  }
55
- return fromUrl;
58
+ return ctx;
56
59
  }
57
60
  try {
58
- return session()?.getItem(TOKEN_KEY) ?? null;
61
+ const raw = session()?.getItem(CTX_KEY);
62
+ return raw ? JSON.parse(raw) : null;
59
63
  } catch {
60
64
  return null;
61
65
  }
62
66
  }
63
- function resolveBuilderOrigin() {
64
- if (!hasWindow()) return null;
65
- const fromUrl = urlParams()?.get(BUILDER_ORIGIN_PARAM);
66
- if (fromUrl) return fromUrl;
67
- try {
68
- return session()?.getItem(ORIGIN_KEY) ?? null;
69
- } catch {
70
- return null;
71
- }
67
+ function resolveBuilderToken() {
68
+ return resolveBuilderContext()?.token ?? null;
72
69
  }
73
70
  function isBuilderMode() {
74
- return resolveBuilderToken() !== null;
71
+ return resolveBuilderContext() !== null;
75
72
  }
76
73
  function clearBuilderToken() {
77
74
  if (!hasWindow()) return;
78
75
  try {
79
- const store = session();
80
- store?.removeItem(TOKEN_KEY);
81
- store?.removeItem(ORIGIN_KEY);
76
+ session()?.removeItem(CTX_KEY);
82
77
  } catch {
83
78
  }
84
79
  }
@@ -1747,6 +1742,6 @@ function buildSelectorPath(element, maxAncestors = 5) {
1747
1742
  return parts.join(" > ");
1748
1743
  }
1749
1744
 
1750
- export { ALWAYS_BLOCK_SELECTORS, BannerRenderer, CustomRenderer, DEFAULT_AUTOCAPTURE_CONFIG, DEFAULT_TRACKER_BATCH_SIZE, DEFAULT_TRACKER_FLUSH_INTERVAL_MS, DEFAULT_TRACKER_MAX_RETRIES, FREQUENCY_CACHE_KEY_PREFIX, FREQUENCY_CACHE_MAX_ENTRIES, FREQUENCY_CACHE_TTL_MS, FormRenderer, InlineCustomRenderer, InlineFormRenderer, InlineRenderer, MAX_ANCESTORS, ModalRenderer, PRIORITY_ATTRIBUTES, SENSITIVE_ATTRIBUTES, TooltipRenderer, WALKTHROUGH_ABANDONMENT_TIMEOUT_MS, WALKTHROUGH_STATE_KEY_PREFIX, WalkthroughRenderer, buildSelectorPath, clearBuilderToken, closeGuidePreview, filterHumanClasses, hasDocument, hasLocalStorage, hasNavigatorSendBeacon, hasWindow, isBuilderMode, previewGuide, resolveBuilderOrigin, resolveBuilderToken, uuidv7 };
1751
- //# sourceMappingURL=chunk-CI7NWEH2.mjs.map
1752
- //# sourceMappingURL=chunk-CI7NWEH2.mjs.map
1745
+ export { ALWAYS_BLOCK_SELECTORS, BannerRenderer, CustomRenderer, DEFAULT_AUTOCAPTURE_CONFIG, DEFAULT_TRACKER_BATCH_SIZE, DEFAULT_TRACKER_FLUSH_INTERVAL_MS, DEFAULT_TRACKER_MAX_RETRIES, FREQUENCY_CACHE_KEY_PREFIX, FREQUENCY_CACHE_MAX_ENTRIES, FREQUENCY_CACHE_TTL_MS, FormRenderer, InlineCustomRenderer, InlineFormRenderer, InlineRenderer, MAX_ANCESTORS, ModalRenderer, PRIORITY_ATTRIBUTES, SENSITIVE_ATTRIBUTES, TooltipRenderer, WALKTHROUGH_ABANDONMENT_TIMEOUT_MS, WALKTHROUGH_STATE_KEY_PREFIX, WalkthroughRenderer, buildSelectorPath, clearBuilderToken, closeGuidePreview, filterHumanClasses, hasDocument, hasLocalStorage, hasNavigatorSendBeacon, hasWindow, isBuilderMode, previewGuide, resolveBuilderContext, resolveBuilderToken, uuidv7 };
1746
+ //# sourceMappingURL=chunk-GHP7ZJCW.mjs.map
1747
+ //# sourceMappingURL=chunk-GHP7ZJCW.mjs.map