glitchgrab 1.58.0 → 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,20 @@ 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;
393
+ /**
394
+ * Text a code to the prospect's phone before the demo is confirmed. `false`
395
+ * books the slot the moment the form is sent — one step fewer, but a
396
+ * mistyped number still books. Defaults to `true`.
397
+ */
398
+ requireOtp: boolean;
385
399
  }
386
400
  /** One question asked before a demo is booked. The prospect taps one of `options`. */
387
401
  interface BookingQuestion {
@@ -404,8 +418,14 @@ type BookingQuestionInput = Omit<BookingQuestion, "id" | "required"> & {
404
418
  required?: boolean;
405
419
  };
406
420
  /** What {@link updateBookingSettings} accepts — any subset of the settings. */
407
- type BookingSettingsChanges = Partial<Omit<BookingSettings, "questions">> & {
421
+ type BookingSettingsChanges = Partial<Omit<BookingSettings, "questions" | "draftQuestions">> & {
408
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;
409
429
  };
410
430
  /** One answer a prospect gave, with the question as it was worded when they booked. */
411
431
  interface BookingAnswer {
@@ -453,6 +473,19 @@ declare function getBookingSettings(options?: CallsOptions): Promise<BookingSett
453
473
  * comes back as one.
454
474
  */
455
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>;
456
489
  /** One booked demo. Times are ISO strings in UTC; `timezone` is what the prospect picked in. */
457
490
  interface Booking {
458
491
  id: string;
@@ -591,4 +624,4 @@ interface ListLeadsOptions extends CallsOptions {
591
624
  */
592
625
  declare function listLeads(options?: ListLeadsOptions): Promise<Lead[]>;
593
626
 
594
- 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,20 @@ 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;
393
+ /**
394
+ * Text a code to the prospect's phone before the demo is confirmed. `false`
395
+ * books the slot the moment the form is sent — one step fewer, but a
396
+ * mistyped number still books. Defaults to `true`.
397
+ */
398
+ requireOtp: boolean;
385
399
  }
386
400
  /** One question asked before a demo is booked. The prospect taps one of `options`. */
387
401
  interface BookingQuestion {
@@ -404,8 +418,14 @@ type BookingQuestionInput = Omit<BookingQuestion, "id" | "required"> & {
404
418
  required?: boolean;
405
419
  };
406
420
  /** What {@link updateBookingSettings} accepts — any subset of the settings. */
407
- type BookingSettingsChanges = Partial<Omit<BookingSettings, "questions">> & {
421
+ type BookingSettingsChanges = Partial<Omit<BookingSettings, "questions" | "draftQuestions">> & {
408
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;
409
429
  };
410
430
  /** One answer a prospect gave, with the question as it was worded when they booked. */
411
431
  interface BookingAnswer {
@@ -453,6 +473,19 @@ declare function getBookingSettings(options?: CallsOptions): Promise<BookingSett
453
473
  * comes back as one.
454
474
  */
455
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>;
456
489
  /** One booked demo. Times are ISO strings in UTC; `timezone` is what the prospect picked in. */
457
490
  interface Booking {
458
491
  id: string;
@@ -591,4 +624,4 @@ interface ListLeadsOptions extends CallsOptions {
591
624
  */
592
625
  declare function listLeads(options?: ListLeadsOptions): Promise<Lead[]>;
593
626
 
594
- 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,11 @@ 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),
531
+ // Missing means a server from before the switch, which always asked.
532
+ requireOtp: s.requireOtp !== false
513
533
  },
514
534
  saved: value.saved === true,
515
535
  calendarConnected: value.calendarConnected === true
@@ -526,13 +546,16 @@ async function getBookingSettings(options = {}) {
526
546
  return { ok: false, error: "Could not read booking settings" };
527
547
  }
528
548
  }
529
- async function updateBookingSettings(changes, options = {}) {
549
+ function updateBookingSettings(changes, options = {}) {
550
+ return putBookingSettings(changes != null ? changes : {}, options);
551
+ }
552
+ async function putBookingSettings(body, options) {
530
553
  try {
531
554
  const key = callsKey(options);
532
555
  if (!key) return { ok: false, error: NO_KEY_ERROR };
533
556
  const { data, error } = await callSdkApi("/api/v1/sdk/booking-settings", key, options, {
534
557
  method: "PUT",
535
- body: changes != null ? changes : {},
558
+ body,
536
559
  cache: "no-store"
537
560
  });
538
561
  const state = error === null ? readBookingSettingsState(data) : null;
@@ -541,6 +564,12 @@ async function updateBookingSettings(changes, options = {}) {
541
564
  return { ok: false, error: "Could not save booking settings" };
542
565
  }
543
566
  }
567
+ function publishBookingQuestions(options = {}) {
568
+ return putBookingSettings({ publishDraft: true }, options);
569
+ }
570
+ function discardBookingQuestionsDraft(options = {}) {
571
+ return putBookingSettings({ discardDraft: true }, options);
572
+ }
544
573
  function readBooking(value) {
545
574
  var _a, _b, _c, _d, _e, _f, _g;
546
575
  if (!isRecord(value) || typeof value.id !== "string") return null;
@@ -689,6 +718,7 @@ async function listLeads(options = {}) {
689
718
  captureServerErrors,
690
719
  configureServerReporter,
691
720
  deleteCall,
721
+ discardBookingQuestionsDraft,
692
722
  escapeJsonForScript,
693
723
  getBookingSettings,
694
724
  getCall,
@@ -697,6 +727,7 @@ async function listLeads(options = {}) {
697
727
  listCalls,
698
728
  listGuides,
699
729
  listLeads,
730
+ publishBookingQuestions,
700
731
  reportServerError,
701
732
  rescheduleBooking,
702
733
  resetServerReporter,