veo-sdk 0.5.34 → 0.6.0

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.
@@ -1,5 +1,5 @@
1
- import { P as PreviewGuideInput } from './guide-preview-DbEZdGBV.cjs';
2
- export { a as PreviewHandle, b as PreviewResult, c as closeGuidePreview, p as previewGuide } from './guide-preview-DbEZdGBV.cjs';
1
+ import { P as PreviewGuideInput } from './guide-preview-DylsEhrg.cjs';
2
+ export { a as PreviewHandle, b as PreviewResult, c as closeGuidePreview, p as previewGuide } from './guide-preview-DylsEhrg.cjs';
3
3
 
4
4
  /** Dónde soltó el autor un bloque nuevo. */
5
5
  interface BlockDropPayload {
@@ -136,8 +136,14 @@ interface EditorChromeState {
136
136
  presentation: 'floating' | 'inline';
137
137
  }>;
138
138
  activeStep: number;
139
- /** Qué muestra el panel: ajustes de activación o el paso activo. */
140
- section: 'activation' | 'step' | 'badge' | 'target';
139
+ /**
140
+ * Qué muestra el panel. `step`, `block`, `add-block`, `row` y `structure`
141
+ * son vistas del paso activo (la fila de pasos lo marca); las pestañas del
142
+ * contenedor se «encienden» solo con `step` (contenedor) y `structure`.
143
+ */
144
+ section: 'activation' | 'step' | 'badge' | 'target' | 'block' | 'add-block' | 'row' | 'structure';
145
+ /** Editando un bloque del paso: su nombre («Encuesta Texto abierto») para el título del panel. */
146
+ blockLabel?: string | null;
141
147
  saving: boolean;
142
148
  dirty: boolean;
143
149
  /**
@@ -173,6 +179,21 @@ type PreviewStatus = {
173
179
  devices: 'desktop' | 'mobile';
174
180
  };
175
181
  /** Acciones que el usuario dispara en el chrome (barras) y el panel ejecuta. */
182
+ /** Bloque de la preview: paso + id local del panel (`StepBlock.editorId`). */
183
+ interface BlockRef {
184
+ stepIndex: number;
185
+ blockId: string;
186
+ }
187
+ type BlockToolbarAction = 'edit' | 'duplicate' | 'remove'
188
+ /** Mover: arriba/abajo dentro de su columna, izquierda/derecha entre columnas de su fila. */
189
+ | 'move-up' | 'move-down' | 'move-left' | 'move-right';
190
+ /** Barra de la FILA (hover o fila del bloque seleccionado): editar / duplicar / eliminar. */
191
+ type RowToolbarAction = 'edit' | 'duplicate' | 'remove';
192
+ /** Pestañas sobre el CONTENEDOR (hover): editar el paso o abrir la estructura de filas. */
193
+ type CardToolbarAction = 'edit-container' | 'edit-rows';
194
+ type BlockLayoutAction = 'row-before' | 'row-after' | 'col-before' | 'col-after'
195
+ /** Bloque apilado en la MISMA celda (fila+columna), antes/después del bloque. */
196
+ | 'stack-before' | 'stack-after';
176
197
  type ChromeAction = {
177
198
  action: 'select-activation';
178
199
  } | {
@@ -180,6 +201,14 @@ type ChromeAction = {
180
201
  index: number;
181
202
  } | {
182
203
  action: 'add-step';
204
+ }
205
+ /** Hover sobre la tarjeta de un paso: duplicar (se inserta después) o eliminar. */
206
+ | {
207
+ action: 'duplicate-step';
208
+ index: number;
209
+ } | {
210
+ action: 'remove-step';
211
+ index: number;
183
212
  } | {
184
213
  action: 'save';
185
214
  exit: boolean;
@@ -213,6 +242,47 @@ type BuilderEvent = {
213
242
  } | {
214
243
  type: 'block-dropped';
215
244
  payload: BlockDropPayload;
245
+ }
246
+ /** Clic simple (sin arrastre) sobre la tarjeta de la preview: el panel abre «Agregar bloque». */
247
+ | {
248
+ type: 'card-clicked';
249
+ payload: {
250
+ stepIndex: number;
251
+ };
252
+ }
253
+ /** Clic sobre un bloque de la preview: se selecciona en la app y el panel abre su editor. */
254
+ | {
255
+ type: 'block-clicked';
256
+ payload: BlockRef;
257
+ }
258
+ /** Barra del bloque seleccionado: editar / duplicar / eliminar. */
259
+ | {
260
+ type: 'block-action';
261
+ payload: BlockRef & {
262
+ action: BlockToolbarAction;
263
+ };
264
+ }
265
+ /** «+» en los bordes del bloque seleccionado: agregar fila arriba/abajo o columna izq/der. */
266
+ | {
267
+ type: 'block-layout';
268
+ payload: BlockRef & {
269
+ action: BlockLayoutAction;
270
+ };
271
+ }
272
+ /** Barra de una fila: `blockId` = primer bloque de la fila (la fila no tiene id propio). */
273
+ | {
274
+ type: 'row-action';
275
+ payload: BlockRef & {
276
+ action: RowToolbarAction;
277
+ };
278
+ }
279
+ /** Pestañas del contenedor (hover sobre la tarjeta): editar contenedor / editar filas. */
280
+ | {
281
+ type: 'card-action';
282
+ payload: {
283
+ stepIndex: number;
284
+ action: CardToolbarAction;
285
+ };
216
286
  } | {
217
287
  type: 'preview-status';
218
288
  payload: PreviewStatus;
@@ -240,6 +310,16 @@ type BuilderCommand = {
240
310
  label?: string;
241
311
  } | {
242
312
  type: 'close-preview';
313
+ }
314
+ /** El panel selecciona (o deselecciona con null) un bloque en la app. */
315
+ | {
316
+ type: 'select-block';
317
+ blockId: string | null;
318
+ }
319
+ /** El panel edita una fila: se marca en la app (por el id de un bloque de esa fila). */
320
+ | {
321
+ type: 'select-row';
322
+ blockId: string | null;
243
323
  } | {
244
324
  type: 'teardown';
245
325
  } | {
@@ -248,6 +328,14 @@ type BuilderCommand = {
248
328
  } | {
249
329
  type: 'panel-visibility';
250
330
  visible: boolean;
331
+ }
332
+ /** Tamaño compacto del panel (alto = contenido); `null` restaura el tamaño previo. */
333
+ | {
334
+ type: 'panel-size';
335
+ size: {
336
+ width: number;
337
+ height: number;
338
+ } | null;
251
339
  } | {
252
340
  type: 'panel-ready';
253
341
  };
package/dist/builder.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as PreviewGuideInput } from './guide-preview-DbEZdGBV.js';
2
- export { a as PreviewHandle, b as PreviewResult, c as closeGuidePreview, p as previewGuide } from './guide-preview-DbEZdGBV.js';
1
+ import { P as PreviewGuideInput } from './guide-preview-DylsEhrg.js';
2
+ export { a as PreviewHandle, b as PreviewResult, c as closeGuidePreview, p as previewGuide } from './guide-preview-DylsEhrg.js';
3
3
 
4
4
  /** Dónde soltó el autor un bloque nuevo. */
5
5
  interface BlockDropPayload {
@@ -136,8 +136,14 @@ interface EditorChromeState {
136
136
  presentation: 'floating' | 'inline';
137
137
  }>;
138
138
  activeStep: number;
139
- /** Qué muestra el panel: ajustes de activación o el paso activo. */
140
- section: 'activation' | 'step' | 'badge' | 'target';
139
+ /**
140
+ * Qué muestra el panel. `step`, `block`, `add-block`, `row` y `structure`
141
+ * son vistas del paso activo (la fila de pasos lo marca); las pestañas del
142
+ * contenedor se «encienden» solo con `step` (contenedor) y `structure`.
143
+ */
144
+ section: 'activation' | 'step' | 'badge' | 'target' | 'block' | 'add-block' | 'row' | 'structure';
145
+ /** Editando un bloque del paso: su nombre («Encuesta Texto abierto») para el título del panel. */
146
+ blockLabel?: string | null;
141
147
  saving: boolean;
142
148
  dirty: boolean;
143
149
  /**
@@ -173,6 +179,21 @@ type PreviewStatus = {
173
179
  devices: 'desktop' | 'mobile';
174
180
  };
175
181
  /** Acciones que el usuario dispara en el chrome (barras) y el panel ejecuta. */
182
+ /** Bloque de la preview: paso + id local del panel (`StepBlock.editorId`). */
183
+ interface BlockRef {
184
+ stepIndex: number;
185
+ blockId: string;
186
+ }
187
+ type BlockToolbarAction = 'edit' | 'duplicate' | 'remove'
188
+ /** Mover: arriba/abajo dentro de su columna, izquierda/derecha entre columnas de su fila. */
189
+ | 'move-up' | 'move-down' | 'move-left' | 'move-right';
190
+ /** Barra de la FILA (hover o fila del bloque seleccionado): editar / duplicar / eliminar. */
191
+ type RowToolbarAction = 'edit' | 'duplicate' | 'remove';
192
+ /** Pestañas sobre el CONTENEDOR (hover): editar el paso o abrir la estructura de filas. */
193
+ type CardToolbarAction = 'edit-container' | 'edit-rows';
194
+ type BlockLayoutAction = 'row-before' | 'row-after' | 'col-before' | 'col-after'
195
+ /** Bloque apilado en la MISMA celda (fila+columna), antes/después del bloque. */
196
+ | 'stack-before' | 'stack-after';
176
197
  type ChromeAction = {
177
198
  action: 'select-activation';
178
199
  } | {
@@ -180,6 +201,14 @@ type ChromeAction = {
180
201
  index: number;
181
202
  } | {
182
203
  action: 'add-step';
204
+ }
205
+ /** Hover sobre la tarjeta de un paso: duplicar (se inserta después) o eliminar. */
206
+ | {
207
+ action: 'duplicate-step';
208
+ index: number;
209
+ } | {
210
+ action: 'remove-step';
211
+ index: number;
183
212
  } | {
184
213
  action: 'save';
185
214
  exit: boolean;
@@ -213,6 +242,47 @@ type BuilderEvent = {
213
242
  } | {
214
243
  type: 'block-dropped';
215
244
  payload: BlockDropPayload;
245
+ }
246
+ /** Clic simple (sin arrastre) sobre la tarjeta de la preview: el panel abre «Agregar bloque». */
247
+ | {
248
+ type: 'card-clicked';
249
+ payload: {
250
+ stepIndex: number;
251
+ };
252
+ }
253
+ /** Clic sobre un bloque de la preview: se selecciona en la app y el panel abre su editor. */
254
+ | {
255
+ type: 'block-clicked';
256
+ payload: BlockRef;
257
+ }
258
+ /** Barra del bloque seleccionado: editar / duplicar / eliminar. */
259
+ | {
260
+ type: 'block-action';
261
+ payload: BlockRef & {
262
+ action: BlockToolbarAction;
263
+ };
264
+ }
265
+ /** «+» en los bordes del bloque seleccionado: agregar fila arriba/abajo o columna izq/der. */
266
+ | {
267
+ type: 'block-layout';
268
+ payload: BlockRef & {
269
+ action: BlockLayoutAction;
270
+ };
271
+ }
272
+ /** Barra de una fila: `blockId` = primer bloque de la fila (la fila no tiene id propio). */
273
+ | {
274
+ type: 'row-action';
275
+ payload: BlockRef & {
276
+ action: RowToolbarAction;
277
+ };
278
+ }
279
+ /** Pestañas del contenedor (hover sobre la tarjeta): editar contenedor / editar filas. */
280
+ | {
281
+ type: 'card-action';
282
+ payload: {
283
+ stepIndex: number;
284
+ action: CardToolbarAction;
285
+ };
216
286
  } | {
217
287
  type: 'preview-status';
218
288
  payload: PreviewStatus;
@@ -240,6 +310,16 @@ type BuilderCommand = {
240
310
  label?: string;
241
311
  } | {
242
312
  type: 'close-preview';
313
+ }
314
+ /** El panel selecciona (o deselecciona con null) un bloque en la app. */
315
+ | {
316
+ type: 'select-block';
317
+ blockId: string | null;
318
+ }
319
+ /** El panel edita una fila: se marca en la app (por el id de un bloque de esa fila). */
320
+ | {
321
+ type: 'select-row';
322
+ blockId: string | null;
243
323
  } | {
244
324
  type: 'teardown';
245
325
  } | {
@@ -248,6 +328,14 @@ type BuilderCommand = {
248
328
  } | {
249
329
  type: 'panel-visibility';
250
330
  visible: boolean;
331
+ }
332
+ /** Tamaño compacto del panel (alto = contenido); `null` restaura el tamaño previo. */
333
+ | {
334
+ type: 'panel-size';
335
+ size: {
336
+ width: number;
337
+ height: number;
338
+ } | null;
251
339
  } | {
252
340
  type: 'panel-ready';
253
341
  };
package/dist/builder.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import './chunk-HAAT6XVN.mjs';
2
- import { initBuilderMode } from './chunk-IZXJA55N.mjs';
3
- export { createBuilderSession, initBuilderMode, startElementPicker, stopElementPicker } from './chunk-IZXJA55N.mjs';
4
- export { closeGuidePreview, previewGuide } from './chunk-W4R4XCWL.mjs';
1
+ import './chunk-GMXQMZ4X.mjs';
2
+ import { initBuilderMode } from './chunk-N4VFMZFA.mjs';
3
+ export { createBuilderSession, initBuilderMode, startElementPicker, stopElementPicker } from './chunk-N4VFMZFA.mjs';
4
+ export { closeGuidePreview, previewGuide } from './chunk-O6USA4TU.mjs';
5
5
  import './chunk-PTG3BTJE.mjs';
6
6
 
7
7
  // src/builder.ts
@@ -1,4 +1,4 @@
1
- import { hasDocument, hasWindow, isAutomaticActivation, activationDelayMs, clearPreviewToken, DEFAULT_TRACKER_MAX_RETRIES, DEFAULT_TRACKER_BATCH_SIZE, DEFAULT_TRACKER_FLUSH_INTERVAL_MS, isDeviceAllowed, stepMatchesPage, CompositeRenderer, ModalRenderer, BannerRenderer, WalkthroughRenderer, BadgeRenderer, InlineFormRenderer, FormRenderer, InlineCustomRenderer, InlineRenderer, CustomRenderer, TooltipRenderer, previewGuide, FREQUENCY_CACHE_KEY_PREFIX, FREQUENCY_CACHE_TTL_MS, FREQUENCY_CACHE_MAX_ENTRIES, WALKTHROUGH_STATE_KEY_PREFIX, WALKTHROUGH_ABANDONMENT_TIMEOUT_MS } from './chunk-W4R4XCWL.mjs';
1
+ import { hasDocument, hasWindow, isAutomaticActivation, activationDelayMs, clearPreviewToken, DEFAULT_TRACKER_MAX_RETRIES, DEFAULT_TRACKER_BATCH_SIZE, DEFAULT_TRACKER_FLUSH_INTERVAL_MS, isDeviceAllowed, isSnoozed, stepMatchesPage, CompositeRenderer, ModalRenderer, BannerRenderer, WalkthroughRenderer, BadgeRenderer, InlineFormRenderer, FormRenderer, InlineCustomRenderer, InlineRenderer, CustomRenderer, TooltipRenderer, previewGuide, FREQUENCY_CACHE_KEY_PREFIX, FREQUENCY_CACHE_TTL_MS, FREQUENCY_CACHE_MAX_ENTRIES, WALKTHROUGH_STATE_KEY_PREFIX, WALKTHROUGH_ABANDONMENT_TIMEOUT_MS } from './chunk-O6USA4TU.mjs';
2
2
 
3
3
  // src/plugins/plugin.ts
4
4
  function definePlugin(plugin) {
@@ -26,7 +26,7 @@ async function runPreviewMode(opts) {
26
26
  } catch (err) {
27
27
  if (opts.debug) console.warn("[veo] preview-resolve fall\xF3:", err);
28
28
  }
29
- const submitToBackend = async (answers) => {
29
+ const submitToBackend = async (answers, meta) => {
30
30
  if (!guide) return false;
31
31
  const veo = window.veo;
32
32
  const endUserId = veo?.getEndUserId?.() ?? veo?.getAnonymousId?.() ?? null;
@@ -35,7 +35,12 @@ async function runPreviewMode(opts) {
35
35
  const res = await fetch(`${opts.apiUrl}/v1/guides/${guide.guideId}/form-response`, {
36
36
  method: "POST",
37
37
  headers: { "Content-Type": "application/json", "X-Api-Key": opts.apiKey },
38
- body: JSON.stringify({ endUserId, answers })
38
+ body: JSON.stringify({
39
+ endUserId,
40
+ answers,
41
+ ...meta ? { stepPosition: meta.stepIndex } : {},
42
+ ...meta?.pollId ? { pollId: meta.pollId } : {}
43
+ })
39
44
  });
40
45
  return res.ok;
41
46
  } catch {
@@ -750,6 +755,12 @@ var GuidesController = class {
750
755
  * en cada `checkGuides` con {@link pruneComposite}.
751
756
  */
752
757
  this.activeComposite = /* @__PURE__ */ new Map();
758
+ /**
759
+ * Progreso de esta sesión, por guía: pasos vistos y completado, según las
760
+ * interacciones que ESTE SDK emitió (aunque el lote aún no haya viajado al
761
+ * backend). Se mezcla con la respuesta del backend en `fetchProgress`.
762
+ */
763
+ this.sessionProgress = /* @__PURE__ */ new Map();
753
764
  this.debug = config.debug === true;
754
765
  this.apiUrl = config.apiUrl;
755
766
  this.apiKey = config.apiKey;
@@ -836,6 +847,10 @@ var GuidesController = class {
836
847
  if (this.debug) console.log(`[veo] guides: filtered locally guideId=${guide.guideId}`);
837
848
  return;
838
849
  }
850
+ if (!opts.byUser && isSnoozed(guide.guideId)) {
851
+ if (this.debug) console.log(`[veo] guides: snoozed guideId=${guide.guideId}`);
852
+ return;
853
+ }
839
854
  if (!opts.byUser && this.isHeldByRepeat(guide)) {
840
855
  if (this.debug) console.log(`[veo] guides: held by repeat guideId=${guide.guideId}`);
841
856
  return;
@@ -1111,6 +1126,17 @@ ${pageUrl}`;
1111
1126
  const goToStep = (target) => {
1112
1127
  cleanup();
1113
1128
  if (target < 0 || target >= steps.length) return;
1129
+ const endUserId = this.client.getEndUserId();
1130
+ if (endUserId) {
1131
+ this.enqueueInteraction(
1132
+ guide.guideId,
1133
+ endUserId,
1134
+ sessionId,
1135
+ pageUrl,
1136
+ target > idx ? "step_advanced" : "step_back",
1137
+ target
1138
+ );
1139
+ }
1114
1140
  const step = steps[target];
1115
1141
  if (step && stepMatchesPage(step.pageLocation, pageUrl)) {
1116
1142
  this.renderCompositeStep(guide, target, sessionId, pageUrl, badgeOpen);
@@ -1135,10 +1161,15 @@ ${pageUrl}`;
1135
1161
  onInteraction: (e) => this.handleInteraction(guide, sessionId, pageUrl, e),
1136
1162
  onClose: cleanup,
1137
1163
  onTrack: (name, props) => this.client.track(name, props),
1138
- onFormSubmit: (answers) => this.submitFormResponse(guide.guideId, answers),
1164
+ onFormSubmit: (answers, meta) => this.submitFormResponse(guide.guideId, answers, meta),
1139
1165
  onOpenGuide: (targetGuideId) => {
1140
1166
  void this.openGuideById(targetGuideId, sessionId, pageUrl);
1141
1167
  },
1168
+ // Lista de tareas: progreso del usuario y abrir una guía en su paso.
1169
+ fetchProgress: (ids) => this.fetchProgress(ids),
1170
+ onOpenGuideAt: (targetGuideId, stepIndex) => {
1171
+ void this.openGuideById(targetGuideId, sessionId, pageUrl, stepIndex);
1172
+ },
1142
1173
  // Badge: cuando el MOTOR muestra la guía (automático, elemento objetivo
1143
1174
  // o encadenada), el contenido se abre solo; el marcador queda para
1144
1175
  // volver a verla. Solo `manual` deja el tooltip cerrado.
@@ -1166,7 +1197,7 @@ ${pageUrl}`;
1166
1197
  const onTrack = (eventName, properties) => {
1167
1198
  this.client.track(eventName, properties);
1168
1199
  };
1169
- const onFormSubmit = (answers) => this.submitFormResponse(guide.guideId, answers);
1200
+ const onFormSubmit = (answers, meta) => this.submitFormResponse(guide.guideId, answers, meta);
1170
1201
  const onOpenGuide = (targetGuideId) => {
1171
1202
  void this.openGuideById(targetGuideId, sessionId, pageUrl);
1172
1203
  };
@@ -1186,7 +1217,7 @@ ${pageUrl}`;
1186
1217
  * un botón); respeta el dedupe de guías activas y el flujo normal de
1187
1218
  * tracking. 404/red → no-op (la guía destino pudo borrarse).
1188
1219
  */
1189
- async openGuideById(guideId, sessionId, pageUrl) {
1220
+ async openGuideById(guideId, sessionId, pageUrl, startStep) {
1190
1221
  if (this.activeByGuideId.has(guideId)) return;
1191
1222
  const guide = await this.resolver.fetchById(guideId);
1192
1223
  if (!guide) {
@@ -1194,6 +1225,15 @@ ${pageUrl}`;
1194
1225
  return;
1195
1226
  }
1196
1227
  const endUserId = this.client.getEndUserId() ?? this.client.getAnonymousId();
1228
+ if (guide.guideType === "composite" && typeof startStep === "number") {
1229
+ const total = guide.guideSteps.length;
1230
+ const idx = Math.max(0, Math.min(total - 1, Math.floor(startStep)));
1231
+ this.enqueueInteractionOnce(guide.guideId, endUserId, sessionId, pageUrl, "shown", 0);
1232
+ if (idx > 0)
1233
+ this.enqueueInteraction(guide.guideId, endUserId, sessionId, pageUrl, "step_advanced", idx);
1234
+ this.renderCompositeStep(guide, idx, sessionId, pageUrl);
1235
+ return;
1236
+ }
1197
1237
  if (guide.guideType === "walkthrough" && guide.guideSteps.length > 1) {
1198
1238
  if (!this.walkthroughState.hasActive()) {
1199
1239
  await this.startWalkthrough(guide, endUserId, sessionId, pageUrl);
@@ -1404,6 +1444,7 @@ ${pageUrl}`;
1404
1444
  console.warn("[veo] guides: interaction without endUserId \u2014 skipping enqueue");
1405
1445
  return;
1406
1446
  }
1447
+ this.noteProgress(guide.guideId, event.action, event.stepIndex);
1407
1448
  this.trackerQueue.enqueue({
1408
1449
  guideId: guide.guideId,
1409
1450
  payload: {
@@ -1423,6 +1464,7 @@ ${pageUrl}`;
1423
1464
  * una navegación distinta) y deduplicarlas perdería datos.
1424
1465
  */
1425
1466
  enqueueInteraction(guideId, endUserId, sessionId, pageUrl, action, stepIndex) {
1467
+ this.noteProgress(guideId, action, stepIndex);
1426
1468
  this.trackerQueue.enqueue({
1427
1469
  guideId,
1428
1470
  payload: {
@@ -1435,6 +1477,45 @@ ${pageUrl}`;
1435
1477
  }
1436
1478
  });
1437
1479
  }
1480
+ noteProgress(guideId, action, stepIndex) {
1481
+ if (action !== "shown" && action !== "step_advanced" && action !== "step_back" && action !== "completed") {
1482
+ return;
1483
+ }
1484
+ const cur = this.sessionProgress.get(guideId) ?? { maxStep: -1, completed: false };
1485
+ this.sessionProgress.set(guideId, {
1486
+ maxStep: Math.max(cur.maxStep, stepIndex),
1487
+ completed: cur.completed || action === "completed"
1488
+ });
1489
+ }
1490
+ /**
1491
+ * Progreso del usuario en varias guías (bloque «Lista de tareas»): lo pide
1492
+ * al backend y lo eleva con lo visto en esta sesión (nunca lo baja).
1493
+ */
1494
+ async fetchProgress(guideIds) {
1495
+ const endUserId = this.client.getEndUserId() ?? this.client.getAnonymousId();
1496
+ let rows = [];
1497
+ try {
1498
+ const params = new URLSearchParams({ endUserId, guideIds: guideIds.join(",") });
1499
+ const res = await fetch(`${this.apiUrl}/v1/guides/progress?${params}`, {
1500
+ headers: { "X-Api-Key": this.apiKey }
1501
+ });
1502
+ if (res.ok) rows = (await res.json()).items ?? [];
1503
+ else if (this.debug) console.warn("[veo] guides/progress respondi\xF3", res.status);
1504
+ } catch (err) {
1505
+ if (this.debug) console.warn("[veo] guides/progress fall\xF3:", err);
1506
+ }
1507
+ return rows.map((r) => {
1508
+ const local = this.sessionProgress.get(r.guideId);
1509
+ if (!local) return r;
1510
+ const seen = Math.min(r.totalSteps, local.maxStep + 1);
1511
+ const completed = r.completed || local.completed || seen >= r.totalSteps;
1512
+ return {
1513
+ ...r,
1514
+ currentStep: completed ? r.totalSteps : Math.max(r.currentStep, seen),
1515
+ completed
1516
+ };
1517
+ });
1518
+ }
1438
1519
  /**
1439
1520
  * Encola con dedup por sesión del SDK. Para `shown` del primer step:
1440
1521
  * no queremos re-emitirlo si el usuario navega entre dos páginas que
@@ -1479,13 +1560,19 @@ ${pageUrl}`;
1479
1560
  * propiedades del usuario. Usa el endUserId actual (o el anónimo si aún no
1480
1561
  * hubo identify — el backend pre-crea la fila igual que identify).
1481
1562
  */
1482
- async submitFormResponse(guideId, answers) {
1563
+ async submitFormResponse(guideId, answers, meta) {
1483
1564
  const endUserId = this.client.getEndUserId() ?? this.client.getAnonymousId();
1484
1565
  try {
1485
1566
  const res = await fetch(`${this.apiUrl}/v1/guides/${guideId}/form-response`, {
1486
1567
  method: "POST",
1487
1568
  headers: { "Content-Type": "application/json", "X-Api-Key": this.apiKey },
1488
- body: JSON.stringify({ endUserId, answers })
1569
+ body: JSON.stringify({
1570
+ endUserId,
1571
+ answers,
1572
+ sessionId: this.client.getSessionId(),
1573
+ ...meta ? { stepPosition: meta.stepIndex } : {},
1574
+ ...meta?.pollId ? { pollId: meta.pollId } : {}
1575
+ })
1489
1576
  });
1490
1577
  if (!res.ok && this.debug) {
1491
1578
  console.warn("[veo] form-response respondi\xF3", res.status);
@@ -1529,5 +1616,5 @@ function guidesPlugin(config) {
1529
1616
  }
1530
1617
 
1531
1618
  export { definePlugin, guidesPlugin, runPreviewMode };
1532
- //# sourceMappingURL=chunk-HAAT6XVN.mjs.map
1533
- //# sourceMappingURL=chunk-HAAT6XVN.mjs.map
1619
+ //# sourceMappingURL=chunk-GMXQMZ4X.mjs.map
1620
+ //# sourceMappingURL=chunk-GMXQMZ4X.mjs.map