glitchgrab 1.58.1 → 1.58.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.
package/dist/server.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { l as ReportType, k as ReportSeverity, j as ReportResult } from './types-DfVtKZcp.mjs';
1
+ import { l as ReportType, k as ReportSeverity, j as ReportResult } from './types-BpTLWJ1y.mjs';
2
2
  import 'react';
3
3
 
4
4
  /** Who to attribute the report to. A server has no signed-in user, so this is the job or service. */
@@ -382,6 +382,14 @@ interface BookingSettings {
382
382
  * and it keeps what is stored. The answers come back on {@link Booking.answers}.
383
383
  */
384
384
  questions: BookingQuestion[];
385
+ /**
386
+ * Questions saved as a draft and not live yet — the dialog and the WhatsApp
387
+ * chat still ask {@link questions}. Preview them with
388
+ * `useGlitchgrab().openBookingPreview()`, make them live with
389
+ * {@link publishBookingQuestions}. `null` = no draft; `[]` = a draft that
390
+ * asks nothing.
391
+ */
392
+ draftQuestions: BookingQuestion[] | null;
385
393
  /**
386
394
  * Text a code to the prospect's phone before the demo is confirmed. `false`
387
395
  * books the slot the moment the form is sent — one step fewer, but a
@@ -410,8 +418,14 @@ type BookingQuestionInput = Omit<BookingQuestion, "id" | "required"> & {
410
418
  required?: boolean;
411
419
  };
412
420
  /** What {@link updateBookingSettings} accepts — any subset of the settings. */
413
- type BookingSettingsChanges = Partial<Omit<BookingSettings, "questions">> & {
421
+ type BookingSettingsChanges = Partial<Omit<BookingSettings, "questions" | "draftQuestions">> & {
414
422
  questions?: BookingQuestionInput[];
423
+ /**
424
+ * With `questions`: save them as a draft instead — the live dialog and chat
425
+ * are unchanged until {@link publishBookingQuestions}. Left out, `questions`
426
+ * go live at once (and any draft is dropped), as before.
427
+ */
428
+ draft?: boolean;
415
429
  };
416
430
  /** One answer a prospect gave, with the question as it was worded when they booked. */
417
431
  interface BookingAnswer {
@@ -459,6 +473,19 @@ declare function getBookingSettings(options?: CallsOptions): Promise<BookingSett
459
473
  * comes back as one.
460
474
  */
461
475
  declare function updateBookingSettings(changes: BookingSettingsChanges, options?: CallsOptions): Promise<BookingSettingsResult>;
476
+ /**
477
+ * Make the draft questions live — the booking dialog and the WhatsApp chat ask
478
+ * them from now on. `error` when there is no draft to publish.
479
+ *
480
+ * ```ts
481
+ * await updateBookingSettings({ questions, draft: true }); // live dialog unchanged
482
+ * // …preview with useGlitchgrab().openBookingPreview() on your admin page…
483
+ * await publishBookingQuestions();
484
+ * ```
485
+ */
486
+ declare function publishBookingQuestions(options?: CallsOptions): Promise<BookingSettingsResult>;
487
+ /** Throw the draft questions away; the live ones are untouched. */
488
+ declare function discardBookingQuestionsDraft(options?: CallsOptions): Promise<BookingSettingsResult>;
462
489
  /** One booked demo. Times are ISO strings in UTC; `timezone` is what the prospect picked in. */
463
490
  interface Booking {
464
491
  id: string;
@@ -597,4 +624,4 @@ interface ListLeadsOptions extends CallsOptions {
597
624
  */
598
625
  declare function listLeads(options?: ListLeadsOptions): Promise<Lead[]>;
599
626
 
600
- export { type Booking, type BookingAnswer, type BookingClientNotice, type BookingMutationResult, type BookingNotifyRecipient, type BookingQuestion, type BookingQuestionInput, type BookingSettings, type BookingSettingsChanges, type BookingSettingsResult, type BookingSettingsState, type BookingWorkingHours, type Call, type CallAudio, type CallListItem, type CallMoment, type CallParticipant, type CallsOptions, type CaptureServerErrorsOptions, type DeleteCallResult, type GetCallOptions, type Guide, type GuideReadOptions, type GuideSummary, type Lead, type ListBookingsOptions, type ListCallsOptions, type ListLeadsOptions, ReportResult, ReportSeverity, ReportType, type ServerReportOptions, type ServerReporterConfig, type ServerReporterIdentity, type SignSessionOptions, cancelBooking, captureServerErrors, configureServerReporter, deleteCall, escapeJsonForScript, getBookingSettings, getCall, getGuide, listBookings, listCalls, listGuides, listLeads, reportServerError, rescheduleBooking, resetServerReporter, signSession, updateBookingSettings };
627
+ export { type Booking, type BookingAnswer, type BookingClientNotice, type BookingMutationResult, type BookingNotifyRecipient, type BookingQuestion, type BookingQuestionInput, type BookingSettings, type BookingSettingsChanges, type BookingSettingsResult, type BookingSettingsState, type BookingWorkingHours, type Call, type CallAudio, type CallListItem, type CallMoment, type CallParticipant, type CallsOptions, type CaptureServerErrorsOptions, type DeleteCallResult, type GetCallOptions, type Guide, type GuideReadOptions, type GuideSummary, type Lead, type ListBookingsOptions, type ListCallsOptions, type ListLeadsOptions, ReportResult, ReportSeverity, ReportType, type ServerReportOptions, type ServerReporterConfig, type ServerReporterIdentity, type SignSessionOptions, cancelBooking, captureServerErrors, configureServerReporter, deleteCall, discardBookingQuestionsDraft, escapeJsonForScript, getBookingSettings, getCall, getGuide, listBookings, listCalls, listGuides, listLeads, publishBookingQuestions, reportServerError, rescheduleBooking, resetServerReporter, signSession, updateBookingSettings };
package/dist/server.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { l as ReportType, k as ReportSeverity, j as ReportResult } from './types-DfVtKZcp.js';
1
+ import { l as ReportType, k as ReportSeverity, j as ReportResult } from './types-BpTLWJ1y.js';
2
2
  import 'react';
3
3
 
4
4
  /** Who to attribute the report to. A server has no signed-in user, so this is the job or service. */
@@ -382,6 +382,14 @@ interface BookingSettings {
382
382
  * and it keeps what is stored. The answers come back on {@link Booking.answers}.
383
383
  */
384
384
  questions: BookingQuestion[];
385
+ /**
386
+ * Questions saved as a draft and not live yet — the dialog and the WhatsApp
387
+ * chat still ask {@link questions}. Preview them with
388
+ * `useGlitchgrab().openBookingPreview()`, make them live with
389
+ * {@link publishBookingQuestions}. `null` = no draft; `[]` = a draft that
390
+ * asks nothing.
391
+ */
392
+ draftQuestions: BookingQuestion[] | null;
385
393
  /**
386
394
  * Text a code to the prospect's phone before the demo is confirmed. `false`
387
395
  * books the slot the moment the form is sent — one step fewer, but a
@@ -410,8 +418,14 @@ type BookingQuestionInput = Omit<BookingQuestion, "id" | "required"> & {
410
418
  required?: boolean;
411
419
  };
412
420
  /** What {@link updateBookingSettings} accepts — any subset of the settings. */
413
- type BookingSettingsChanges = Partial<Omit<BookingSettings, "questions">> & {
421
+ type BookingSettingsChanges = Partial<Omit<BookingSettings, "questions" | "draftQuestions">> & {
414
422
  questions?: BookingQuestionInput[];
423
+ /**
424
+ * With `questions`: save them as a draft instead — the live dialog and chat
425
+ * are unchanged until {@link publishBookingQuestions}. Left out, `questions`
426
+ * go live at once (and any draft is dropped), as before.
427
+ */
428
+ draft?: boolean;
415
429
  };
416
430
  /** One answer a prospect gave, with the question as it was worded when they booked. */
417
431
  interface BookingAnswer {
@@ -459,6 +473,19 @@ declare function getBookingSettings(options?: CallsOptions): Promise<BookingSett
459
473
  * comes back as one.
460
474
  */
461
475
  declare function updateBookingSettings(changes: BookingSettingsChanges, options?: CallsOptions): Promise<BookingSettingsResult>;
476
+ /**
477
+ * Make the draft questions live — the booking dialog and the WhatsApp chat ask
478
+ * them from now on. `error` when there is no draft to publish.
479
+ *
480
+ * ```ts
481
+ * await updateBookingSettings({ questions, draft: true }); // live dialog unchanged
482
+ * // …preview with useGlitchgrab().openBookingPreview() on your admin page…
483
+ * await publishBookingQuestions();
484
+ * ```
485
+ */
486
+ declare function publishBookingQuestions(options?: CallsOptions): Promise<BookingSettingsResult>;
487
+ /** Throw the draft questions away; the live ones are untouched. */
488
+ declare function discardBookingQuestionsDraft(options?: CallsOptions): Promise<BookingSettingsResult>;
462
489
  /** One booked demo. Times are ISO strings in UTC; `timezone` is what the prospect picked in. */
463
490
  interface Booking {
464
491
  id: string;
@@ -597,4 +624,4 @@ interface ListLeadsOptions extends CallsOptions {
597
624
  */
598
625
  declare function listLeads(options?: ListLeadsOptions): Promise<Lead[]>;
599
626
 
600
- export { type Booking, type BookingAnswer, type BookingClientNotice, type BookingMutationResult, type BookingNotifyRecipient, type BookingQuestion, type BookingQuestionInput, type BookingSettings, type BookingSettingsChanges, type BookingSettingsResult, type BookingSettingsState, type BookingWorkingHours, type Call, type CallAudio, type CallListItem, type CallMoment, type CallParticipant, type CallsOptions, type CaptureServerErrorsOptions, type DeleteCallResult, type GetCallOptions, type Guide, type GuideReadOptions, type GuideSummary, type Lead, type ListBookingsOptions, type ListCallsOptions, type ListLeadsOptions, ReportResult, ReportSeverity, ReportType, type ServerReportOptions, type ServerReporterConfig, type ServerReporterIdentity, type SignSessionOptions, cancelBooking, captureServerErrors, configureServerReporter, deleteCall, escapeJsonForScript, getBookingSettings, getCall, getGuide, listBookings, listCalls, listGuides, listLeads, reportServerError, rescheduleBooking, resetServerReporter, signSession, updateBookingSettings };
627
+ export { type Booking, type BookingAnswer, type BookingClientNotice, type BookingMutationResult, type BookingNotifyRecipient, type BookingQuestion, type BookingQuestionInput, type BookingSettings, type BookingSettingsChanges, type BookingSettingsResult, type BookingSettingsState, type BookingWorkingHours, type Call, type CallAudio, type CallListItem, type CallMoment, type CallParticipant, type CallsOptions, type CaptureServerErrorsOptions, type DeleteCallResult, type GetCallOptions, type Guide, type GuideReadOptions, type GuideSummary, type Lead, type ListBookingsOptions, type ListCallsOptions, type ListLeadsOptions, ReportResult, ReportSeverity, ReportType, type ServerReportOptions, type ServerReporterConfig, type ServerReporterIdentity, type SignSessionOptions, cancelBooking, captureServerErrors, configureServerReporter, deleteCall, discardBookingQuestionsDraft, escapeJsonForScript, getBookingSettings, getCall, getGuide, listBookings, listCalls, listGuides, listLeads, publishBookingQuestions, reportServerError, rescheduleBooking, resetServerReporter, signSession, updateBookingSettings };
package/dist/server.js CHANGED
@@ -24,6 +24,7 @@ __export(server_exports, {
24
24
  captureServerErrors: () => captureServerErrors,
25
25
  configureServerReporter: () => configureServerReporter,
26
26
  deleteCall: () => deleteCall,
27
+ discardBookingQuestionsDraft: () => discardBookingQuestionsDraft,
27
28
  escapeJsonForScript: () => escapeJsonForScript,
28
29
  getBookingSettings: () => getBookingSettings,
29
30
  getCall: () => getCall,
@@ -32,6 +33,7 @@ __export(server_exports, {
32
33
  listCalls: () => listCalls,
33
34
  listGuides: () => listGuides,
34
35
  listLeads: () => listLeads,
36
+ publishBookingQuestions: () => publishBookingQuestions,
35
37
  reportServerError: () => reportServerError,
36
38
  rescheduleBooking: () => rescheduleBooking,
37
39
  resetServerReporter: () => resetServerReporter,
@@ -48,6 +50,9 @@ var pageLoadedAt = Date.now();
48
50
  var DEFAULT_BASE_URL = "https://glitchgrab.dev";
49
51
  var MAX_RETRIES = 3;
50
52
  var RETRY_BASE_MS = 500;
53
+ function reportAttemptTimeoutMs(bodyLength) {
54
+ return 1e4 + Math.ceil(bodyLength / 1e5) * 1e3;
55
+ }
51
56
  async function sendReport(payload, baseUrl) {
52
57
  var _a;
53
58
  try {
@@ -58,13 +63,18 @@ async function sendReport(payload, baseUrl) {
58
63
  Authorization: `Bearer ${payload.token}`
59
64
  };
60
65
  const useKeepalive = body.length < 6e4;
66
+ const timeoutMs = reportAttemptTimeoutMs(body.length);
61
67
  for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
68
+ const isLast = attempt === MAX_RETRIES - 1;
69
+ const controller = !isLast && typeof AbortController === "function" ? new AbortController() : null;
70
+ const timer = controller ? setTimeout(() => controller.abort(), timeoutMs) : null;
62
71
  try {
63
72
  const response = await fetch(url, {
64
73
  method: "POST",
65
74
  headers,
66
75
  body,
67
- ...useKeepalive ? { keepalive: true } : {}
76
+ ...useKeepalive ? { keepalive: true } : {},
77
+ ...controller ? { signal: controller.signal } : {}
68
78
  });
69
79
  if (response.ok) {
70
80
  const envelope = await response.json();
@@ -74,6 +84,8 @@ async function sendReport(payload, baseUrl) {
74
84
  return null;
75
85
  }
76
86
  } catch (e) {
87
+ } finally {
88
+ if (timer) clearTimeout(timer);
77
89
  }
78
90
  if (attempt < MAX_RETRIES - 1) {
79
91
  await new Promise(
@@ -466,8 +478,20 @@ async function deleteCall(id, options = {}) {
466
478
  }
467
479
  }
468
480
  var WEEKDAY = /^[1-7]$/;
481
+ function readQuestionList(value) {
482
+ if (!Array.isArray(value)) return null;
483
+ return value.filter(isRecord).map((row) => {
484
+ var _a, _b;
485
+ return {
486
+ id: (_a = stringOrNull(row.id)) != null ? _a : "",
487
+ label: (_b = stringOrNull(row.label)) != null ? _b : "",
488
+ options: Array.isArray(row.options) ? row.options.filter((option) => typeof option === "string") : [],
489
+ required: row.required !== false
490
+ };
491
+ }).filter((row) => row.id !== "" && row.label !== "");
492
+ }
469
493
  function readBookingSettingsState(value) {
470
- var _a, _b, _c, _d;
494
+ var _a, _b, _c, _d, _e;
471
495
  if (!isRecord(value) || !isRecord(value.settings)) return null;
472
496
  const s = value.settings;
473
497
  const hours = {};
@@ -501,15 +525,9 @@ function readBookingSettingsState(value) {
501
525
  phone: (_b2 = stringOrNull(row.phone)) != null ? _b2 : ""
502
526
  };
503
527
  }).filter((row) => row.phone !== "") : [],
504
- questions: Array.isArray(s.questions) ? s.questions.filter(isRecord).map((row) => {
505
- var _a2, _b2;
506
- return {
507
- id: (_a2 = stringOrNull(row.id)) != null ? _a2 : "",
508
- label: (_b2 = stringOrNull(row.label)) != null ? _b2 : "",
509
- options: Array.isArray(row.options) ? row.options.filter((option) => typeof option === "string") : [],
510
- required: row.required !== false
511
- };
512
- }).filter((row) => row.id !== "" && row.label !== "") : [],
528
+ questions: (_e = readQuestionList(s.questions)) != null ? _e : [],
529
+ // A server from before drafts sends no key: no draft.
530
+ draftQuestions: readQuestionList(s.draftQuestions),
513
531
  // Missing means a server from before the switch, which always asked.
514
532
  requireOtp: s.requireOtp !== false
515
533
  },
@@ -528,13 +546,16 @@ async function getBookingSettings(options = {}) {
528
546
  return { ok: false, error: "Could not read booking settings" };
529
547
  }
530
548
  }
531
- async function updateBookingSettings(changes, options = {}) {
549
+ function updateBookingSettings(changes, options = {}) {
550
+ return putBookingSettings(changes != null ? changes : {}, options);
551
+ }
552
+ async function putBookingSettings(body, options) {
532
553
  try {
533
554
  const key = callsKey(options);
534
555
  if (!key) return { ok: false, error: NO_KEY_ERROR };
535
556
  const { data, error } = await callSdkApi("/api/v1/sdk/booking-settings", key, options, {
536
557
  method: "PUT",
537
- body: changes != null ? changes : {},
558
+ body,
538
559
  cache: "no-store"
539
560
  });
540
561
  const state = error === null ? readBookingSettingsState(data) : null;
@@ -543,6 +564,12 @@ async function updateBookingSettings(changes, options = {}) {
543
564
  return { ok: false, error: "Could not save booking settings" };
544
565
  }
545
566
  }
567
+ function publishBookingQuestions(options = {}) {
568
+ return putBookingSettings({ publishDraft: true }, options);
569
+ }
570
+ function discardBookingQuestionsDraft(options = {}) {
571
+ return putBookingSettings({ discardDraft: true }, options);
572
+ }
546
573
  function readBooking(value) {
547
574
  var _a, _b, _c, _d, _e, _f, _g;
548
575
  if (!isRecord(value) || typeof value.id !== "string") return null;
@@ -691,6 +718,7 @@ async function listLeads(options = {}) {
691
718
  captureServerErrors,
692
719
  configureServerReporter,
693
720
  deleteCall,
721
+ discardBookingQuestionsDraft,
694
722
  escapeJsonForScript,
695
723
  getBookingSettings,
696
724
  getCall,
@@ -699,6 +727,7 @@ async function listLeads(options = {}) {
699
727
  listCalls,
700
728
  listGuides,
701
729
  listLeads,
730
+ publishBookingQuestions,
702
731
  reportServerError,
703
732
  rescheduleBooking,
704
733
  resetServerReporter,