@flamingo-stack/openframe-frontend-core 0.0.672 → 0.0.673-2406.7239.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/dist/{chunk-YNGAJGYB.cjs → chunk-6LWIJJJ6.cjs} +410 -6
  2. package/dist/{chunk-3PVOF3IB.js.map → chunk-6LWIJJJ6.cjs.map} +1 -1
  3. package/dist/{chunk-XLJNYTUW.cjs → chunk-6YSDCC3J.cjs} +56 -55
  4. package/dist/chunk-6YSDCC3J.cjs.map +1 -0
  5. package/dist/{chunk-GV7R2NTS.cjs → chunk-76DQOFZG.cjs} +23 -23
  6. package/dist/{chunk-GV7R2NTS.cjs.map → chunk-76DQOFZG.cjs.map} +1 -1
  7. package/dist/{chunk-UUOBCUHW.cjs → chunk-7ALCRUZ3.cjs} +3 -3
  8. package/dist/{chunk-UUOBCUHW.cjs.map → chunk-7ALCRUZ3.cjs.map} +1 -1
  9. package/dist/{chunk-PWPYCJ33.js → chunk-7RQZ2FTF.js} +2 -2
  10. package/dist/{chunk-XDTU23P4.js → chunk-ALSCESHG.js} +2 -2
  11. package/dist/{chunk-HVEX4BSC.cjs → chunk-AUQ4UITE.cjs} +60 -45
  12. package/dist/chunk-AUQ4UITE.cjs.map +1 -0
  13. package/dist/{chunk-CBCETEB4.cjs → chunk-E6B34U5Q.cjs} +6 -6
  14. package/dist/{chunk-CBCETEB4.cjs.map → chunk-E6B34U5Q.cjs.map} +1 -1
  15. package/dist/{chunk-H54F476P.cjs → chunk-FK3VSQ35.cjs} +3 -3
  16. package/dist/{chunk-H54F476P.cjs.map → chunk-FK3VSQ35.cjs.map} +1 -1
  17. package/dist/{chunk-HOEVEB7N.cjs → chunk-GCOVKIE7.cjs} +40 -29
  18. package/dist/chunk-GCOVKIE7.cjs.map +1 -0
  19. package/dist/{chunk-42OVTTOM.js → chunk-GIYAUKCY.js} +18 -3
  20. package/dist/{chunk-42OVTTOM.js.map → chunk-GIYAUKCY.js.map} +1 -1
  21. package/dist/{chunk-TQPKNG2E.js → chunk-INVZNRWB.js} +3 -3
  22. package/dist/{chunk-ZRIVCLPR.js → chunk-JD5TKRCU.js} +1 -1
  23. package/dist/chunk-JD5TKRCU.js.map +1 -0
  24. package/dist/{chunk-IBGHJLNT.js → chunk-JF4ZQZZJ.js} +2 -2
  25. package/dist/{chunk-SNWAN52K.cjs → chunk-JJDPSYBV.cjs} +3 -3
  26. package/dist/{chunk-SNWAN52K.cjs.map → chunk-JJDPSYBV.cjs.map} +1 -1
  27. package/dist/{chunk-D55IENZJ.cjs → chunk-LCMT2GZK.cjs} +1 -1
  28. package/dist/chunk-LCMT2GZK.cjs.map +1 -0
  29. package/dist/{chunk-AL4I5HHB.js → chunk-MMDGSGVE.js} +4 -4
  30. package/dist/{chunk-O5PYXQ6H.js → chunk-N3Q4FMMB.js} +3 -3
  31. package/dist/{chunk-RD3I5PBB.cjs → chunk-NUVRMZW5.cjs} +15 -15
  32. package/dist/{chunk-RD3I5PBB.cjs.map → chunk-NUVRMZW5.cjs.map} +1 -1
  33. package/dist/{chunk-T3KXCOB2.js → chunk-OIE6GKS3.js} +2 -2
  34. package/dist/{chunk-TFSGYKWG.js → chunk-OZL6FSB2.js} +28 -17
  35. package/dist/chunk-OZL6FSB2.js.map +1 -0
  36. package/dist/{chunk-NETIHUEY.cjs → chunk-P2A3KAYW.cjs} +10 -10
  37. package/dist/{chunk-NETIHUEY.cjs.map → chunk-P2A3KAYW.cjs.map} +1 -1
  38. package/dist/{chunk-6S2KLT7O.js → chunk-Q4KRZOQR.js} +4 -4
  39. package/dist/{chunk-BODMICIH.cjs → chunk-S7W7MTBM.cjs} +40 -40
  40. package/dist/{chunk-BODMICIH.cjs.map → chunk-S7W7MTBM.cjs.map} +1 -1
  41. package/dist/{chunk-3PVOF3IB.js → chunk-SGK4Q2W2.js} +407 -3
  42. package/dist/chunk-SGK4Q2W2.js.map +1 -0
  43. package/dist/{chunk-VZRVQEMT.cjs → chunk-SYTDEWZJ.cjs} +7 -7
  44. package/dist/{chunk-VZRVQEMT.cjs.map → chunk-SYTDEWZJ.cjs.map} +1 -1
  45. package/dist/{chunk-Z6E45TJM.js → chunk-TDCIGINK.js} +5 -5
  46. package/dist/{chunk-UOQRNZIB.cjs → chunk-TQATQ4CX.cjs} +17 -17
  47. package/dist/{chunk-UOQRNZIB.cjs.map → chunk-TQATQ4CX.cjs.map} +1 -1
  48. package/dist/{chunk-PSL2WBEO.cjs → chunk-TT6O7BUZ.cjs} +33 -33
  49. package/dist/{chunk-PSL2WBEO.cjs.map → chunk-TT6O7BUZ.cjs.map} +1 -1
  50. package/dist/{chunk-JREG4T6K.cjs → chunk-U7BJC4WF.cjs} +3 -3
  51. package/dist/{chunk-JREG4T6K.cjs.map → chunk-U7BJC4WF.cjs.map} +1 -1
  52. package/dist/{chunk-EKABOXNB.js → chunk-UIKMPCHW.js} +2 -2
  53. package/dist/{chunk-7KM34VWL.js → chunk-XMJT3QZ2.js} +3 -3
  54. package/dist/{chunk-4AZWVS7F.js → chunk-XSOL5ISO.js} +7 -6
  55. package/dist/{chunk-4AZWVS7F.js.map → chunk-XSOL5ISO.js.map} +1 -1
  56. package/dist/{chunk-KSBDARII.js → chunk-Y2ASYQ3P.js} +5 -5
  57. package/dist/components/case-studies/index.cjs +17 -14
  58. package/dist/components/case-studies/index.cjs.map +1 -1
  59. package/dist/components/case-studies/index.js +8 -5
  60. package/dist/components/case-studies/index.js.map +1 -1
  61. package/dist/components/case-studies/share-experience-section.d.ts.map +1 -1
  62. package/dist/components/contact/contact-form.d.ts +7 -1
  63. package/dist/components/contact/contact-form.d.ts.map +1 -1
  64. package/dist/components/contact/index.cjs +5 -5
  65. package/dist/components/contact/index.js +4 -4
  66. package/dist/components/docs/index.cjs +8 -8
  67. package/dist/components/docs/index.js +7 -7
  68. package/dist/components/embeds/index.cjs +5 -5
  69. package/dist/components/embeds/index.js +4 -4
  70. package/dist/components/faq/index.cjs +5 -5
  71. package/dist/components/faq/index.js +4 -4
  72. package/dist/components/features/index.cjs +4 -4
  73. package/dist/components/features/index.js +3 -3
  74. package/dist/components/features/waitlist-form.d.ts +7 -2
  75. package/dist/components/features/waitlist-form.d.ts.map +1 -1
  76. package/dist/components/help-center-pages/index.cjs +54 -52
  77. package/dist/components/help-center-pages/index.cjs.map +1 -1
  78. package/dist/components/help-center-pages/index.js +17 -15
  79. package/dist/components/help-center-pages/index.js.map +1 -1
  80. package/dist/components/help-center-pages/trust-center-sections.d.ts.map +1 -1
  81. package/dist/components/index.cjs +35 -35
  82. package/dist/components/index.js +14 -14
  83. package/dist/components/meeting-scheduler/booking-form.d.ts +7 -1
  84. package/dist/components/meeting-scheduler/booking-form.d.ts.map +1 -1
  85. package/dist/components/meeting-scheduler/index.cjs +53 -31
  86. package/dist/components/meeting-scheduler/index.cjs.map +1 -1
  87. package/dist/components/meeting-scheduler/index.d.ts +5 -1
  88. package/dist/components/meeting-scheduler/index.d.ts.map +1 -1
  89. package/dist/components/meeting-scheduler/index.js +31 -9
  90. package/dist/components/meeting-scheduler/index.js.map +1 -1
  91. package/dist/components/navigation/index.cjs +7 -7
  92. package/dist/components/navigation/index.js +6 -6
  93. package/dist/components/onboarding-guides/index.cjs +7 -7
  94. package/dist/components/onboarding-guides/index.js +6 -6
  95. package/dist/components/tickets/help-center-create-form.d.ts.map +1 -1
  96. package/dist/components/tickets/index.cjs +8 -8
  97. package/dist/components/tickets/index.js +7 -7
  98. package/dist/components/ui/index.cjs +4 -4
  99. package/dist/components/ui/index.js +3 -3
  100. package/dist/contexts/endpoints-runtime-context.d.ts +5 -0
  101. package/dist/contexts/endpoints-runtime-context.d.ts.map +1 -1
  102. package/dist/contexts/index.cjs +2 -2
  103. package/dist/contexts/index.js +1 -1
  104. package/dist/hooks/index.cjs +9 -3
  105. package/dist/hooks/index.cjs.map +1 -1
  106. package/dist/hooks/index.d.ts +2 -0
  107. package/dist/hooks/index.d.ts.map +1 -1
  108. package/dist/hooks/index.js +8 -2
  109. package/dist/hooks/use-form-rescue.d.ts +43 -0
  110. package/dist/hooks/use-form-rescue.d.ts.map +1 -0
  111. package/dist/hooks/use-rescued-form.d.ts +28 -0
  112. package/dist/hooks/use-rescued-form.d.ts.map +1 -0
  113. package/dist/index.cjs +60 -8
  114. package/dist/index.cjs.map +1 -1
  115. package/dist/index.js +59 -7
  116. package/dist/index.js.map +1 -1
  117. package/dist/utils/form-rescue.cjs +142 -0
  118. package/dist/utils/form-rescue.cjs.map +1 -0
  119. package/dist/utils/form-rescue.d.ts +133 -0
  120. package/dist/utils/form-rescue.d.ts.map +1 -0
  121. package/dist/utils/form-rescue.js +118 -0
  122. package/dist/utils/form-rescue.js.map +1 -0
  123. package/dist/utils/index.cjs +138 -0
  124. package/dist/utils/index.cjs.map +1 -1
  125. package/dist/utils/index.d.ts +1 -0
  126. package/dist/utils/index.d.ts.map +1 -1
  127. package/dist/utils/index.js +116 -1
  128. package/dist/utils/index.js.map +1 -1
  129. package/package.json +7 -1
  130. package/src/components/case-studies/share-experience-section.tsx +2 -0
  131. package/src/components/contact/contact-form.tsx +33 -12
  132. package/src/components/features/waitlist-form.tsx +27 -2
  133. package/src/components/help-center-pages/trust-center-sections.tsx +2 -0
  134. package/src/components/meeting-scheduler/booking-form.tsx +30 -2
  135. package/src/components/meeting-scheduler/index.tsx +10 -1
  136. package/src/components/tickets/help-center-create-form.tsx +2 -0
  137. package/src/contexts/endpoints-runtime-context.tsx +5 -0
  138. package/src/hooks/__tests__/use-form-rescue.test.tsx +189 -0
  139. package/src/hooks/__tests__/use-rescued-form.test.tsx +91 -0
  140. package/src/hooks/index.ts +4 -0
  141. package/src/hooks/use-form-rescue.ts +330 -0
  142. package/src/hooks/use-rescued-form.ts +71 -0
  143. package/src/utils/__tests__/form-rescue.test.ts +124 -0
  144. package/src/utils/form-rescue.ts +237 -0
  145. package/src/utils/index.ts +5 -0
  146. package/dist/chunk-D55IENZJ.cjs.map +0 -1
  147. package/dist/chunk-HOEVEB7N.cjs.map +0 -1
  148. package/dist/chunk-HVEX4BSC.cjs.map +0 -1
  149. package/dist/chunk-TFSGYKWG.js.map +0 -1
  150. package/dist/chunk-XLJNYTUW.cjs.map +0 -1
  151. package/dist/chunk-YNGAJGYB.cjs.map +0 -1
  152. package/dist/chunk-ZRIVCLPR.js.map +0 -1
  153. /package/dist/{chunk-PWPYCJ33.js.map → chunk-7RQZ2FTF.js.map} +0 -0
  154. /package/dist/{chunk-XDTU23P4.js.map → chunk-ALSCESHG.js.map} +0 -0
  155. /package/dist/{chunk-TQPKNG2E.js.map → chunk-INVZNRWB.js.map} +0 -0
  156. /package/dist/{chunk-IBGHJLNT.js.map → chunk-JF4ZQZZJ.js.map} +0 -0
  157. /package/dist/{chunk-AL4I5HHB.js.map → chunk-MMDGSGVE.js.map} +0 -0
  158. /package/dist/{chunk-O5PYXQ6H.js.map → chunk-N3Q4FMMB.js.map} +0 -0
  159. /package/dist/{chunk-T3KXCOB2.js.map → chunk-OIE6GKS3.js.map} +0 -0
  160. /package/dist/{chunk-6S2KLT7O.js.map → chunk-Q4KRZOQR.js.map} +0 -0
  161. /package/dist/{chunk-Z6E45TJM.js.map → chunk-TDCIGINK.js.map} +0 -0
  162. /package/dist/{chunk-EKABOXNB.js.map → chunk-UIKMPCHW.js.map} +0 -0
  163. /package/dist/{chunk-7KM34VWL.js.map → chunk-XMJT3QZ2.js.map} +0 -0
  164. /package/dist/{chunk-KSBDARII.js.map → chunk-Y2ASYQ3P.js.map} +0 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
 
4
4
 
5
- var _chunkD55IENZJcjs = require('./chunk-D55IENZJ.cjs');
5
+ var _chunkLCMT2GZKcjs = require('./chunk-LCMT2GZK.cjs');
6
6
 
7
7
 
8
8
 
@@ -1393,7 +1393,7 @@ function useContactSubmission(options = {}) {
1393
1393
  const { userId, successRedirectUrl, successToastMessage, onSuccess } = options;
1394
1394
  const { toast: toast2 } = useToast();
1395
1395
  const router = _chunkSADRZ4YIcjs.useRouter.call(void 0, );
1396
- const { contactUrl } = _chunkD55IENZJcjs.useRequiredEndpointsRuntime.call(void 0, );
1396
+ const { contactUrl } = _chunkLCMT2GZKcjs.useRequiredEndpointsRuntime.call(void 0, );
1397
1397
  const [isSubmitting, setIsSubmitting] = _react.useState.call(void 0, false);
1398
1398
  const [isSuccess, setIsSuccess] = _react.useState.call(void 0, false);
1399
1399
  const submit = _react.useCallback.call(void 0,
@@ -2776,7 +2776,7 @@ async function validateAndConsumeAccessCode(email, code, endpoints) {
2776
2776
 
2777
2777
  // src/hooks/use-access-code-integration.ts
2778
2778
  function useAccessCodeIntegration() {
2779
- const runtime = _chunkD55IENZJcjs.useRequiredEndpointsRuntime.call(void 0, );
2779
+ const runtime = _chunkLCMT2GZKcjs.useRequiredEndpointsRuntime.call(void 0, );
2780
2780
  const endpoints = runtime.accessCode;
2781
2781
  const [isValidating, setIsValidating] = _react2.default.useState(false);
2782
2782
  const [isConsuming, setIsConsuming] = _react2.default.useState(false);
@@ -2905,7 +2905,7 @@ async function revalidateMirror(mirrorPath) {
2905
2905
  }
2906
2906
  }
2907
2907
  function useClaudeMirrorSrc(url) {
2908
- const endpoints = _chunkD55IENZJcjs.useEndpointsRuntime.call(void 0, );
2908
+ const endpoints = _chunkLCMT2GZKcjs.useEndpointsRuntime.call(void 0, );
2909
2909
  const mirrorPath = toClaudeMirrorPath(url, _optionalChain([endpoints, 'optionalAccess', _54 => _54.storageViewBaseUrl]));
2910
2910
  const [resolved, setResolved] = _react.useState.call(void 0, null);
2911
2911
  const state = resolved && resolved.key === mirrorPath ? resolved.value : { src: null, status: mirrorPath ? "probing" : "absent" };
@@ -3059,6 +3059,410 @@ function useHumanitySignals() {
3059
3059
  return { honeypotInputProps: { ref, name: HONEYPOT_FIELD }, getSignals, resetSignals };
3060
3060
  }
3061
3061
 
3062
+ // src/hooks/use-form-rescue.ts
3063
+
3064
+
3065
+ // src/utils/form-rescue.ts
3066
+ var FORM_ID_PATTERN = /^[a-z][a-z0-9_]{1,47}$/;
3067
+ var definitions = /* @__PURE__ */ new Map();
3068
+ function defineRescueForm(definition) {
3069
+ if (!FORM_ID_PATTERN.test(definition.id)) throw new Error(`[form-rescue] invalid form id "${definition.id}"`);
3070
+ const existing = definitions.get(definition.id);
3071
+ if (existing) {
3072
+ if (existing.label !== definition.label) {
3073
+ throw new Error(`[form-rescue] form id "${definition.id}" is already defined as "${existing.label}"`);
3074
+ }
3075
+ return existing;
3076
+ }
3077
+ const frozen = Object.freeze({ id: definition.id, label: definition.label });
3078
+ definitions.set(frozen.id, frozen);
3079
+ return frozen;
3080
+ }
3081
+ function getRescueForm(id) {
3082
+ return typeof id === "string" ? _nullishCoalesce(definitions.get(id), () => ( null)) : null;
3083
+ }
3084
+ function listRescueForms() {
3085
+ return [...definitions.values()];
3086
+ }
3087
+ var RESCUE_FORMS = {
3088
+ contact: defineRescueForm({ id: "contact", label: "Contact form" }),
3089
+ caseStudyPitch: defineRescueForm({ id: "case_study_pitch", label: "Case study pitch" }),
3090
+ dataRoomRequest: defineRescueForm({ id: "data_room_request", label: "Data room request" }),
3091
+ trustCenterRequest: defineRescueForm({ id: "trust_center_request", label: "Trust Center document request" }),
3092
+ meetingBooking: defineRescueForm({ id: "meeting_booking", label: "Meeting booking" }),
3093
+ waitlist: defineRescueForm({ id: "waitlist", label: "Waitlist" })
3094
+ };
3095
+ var FORM_RESCUE_VALUE_FIELDS = [
3096
+ "email",
3097
+ "name",
3098
+ "firstName",
3099
+ "lastName",
3100
+ "company",
3101
+ "jobtitle",
3102
+ "companySize",
3103
+ "linkedin_url"
3104
+ ];
3105
+ var EXCLUDED_FIELD_PATTERN = /pass(word|code)?|card|cvv|cvc|ssn|social.?security|iban|bank|routing|token|secret|otp|pin$/i;
3106
+ function isExcludedRescueField(name) {
3107
+ return EXCLUDED_FIELD_PATTERN.test(name);
3108
+ }
3109
+ var FORM_RESCUE_MAX_VALUE_CHARS = 200;
3110
+ var FORM_RESCUE_DEBOUNCE_MS = 1500;
3111
+ var FORM_RESCUE_MAX_FIELDS = 40;
3112
+ var FORM_RESCUE_ATTEMPT_FIELD = "form_attempt_id";
3113
+ var FORM_RESCUE_RESUME_FIELD = "form_resume_token";
3114
+ var FORM_RESCUE_SUBMIT_KEYS = [FORM_RESCUE_ATTEMPT_FIELD, FORM_RESCUE_RESUME_FIELD];
3115
+ var FORM_RESCUE_RESUME_PARAM = "resume";
3116
+ var FORM_DRAFT_STATUSES = ["started", "rescuable", "rescued", "submitted"];
3117
+ var FORM_RESCUE_SKIP_REASONS = {
3118
+ finishedElsewhere: "finished_elsewhere",
3119
+ alreadyRescued: "already_rescued",
3120
+ internal: "internal_email"
3121
+ };
3122
+ var EMAIL_PATTERN = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/;
3123
+ function isRescueEmail(value) {
3124
+ return typeof value === "string" && value.length <= FORM_RESCUE_MAX_VALUE_CHARS && EMAIL_PATTERN.test(value.trim());
3125
+ }
3126
+ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
3127
+ function isFormAttemptId(value) {
3128
+ return typeof value === "string" && UUID_PATTERN.test(value);
3129
+ }
3130
+ function isFilled(value) {
3131
+ if (value == null) return false;
3132
+ if (typeof value === "string") return value.trim().length > 0;
3133
+ if (typeof value === "boolean") return value;
3134
+ if (Array.isArray(value)) return value.length > 0;
3135
+ if (typeof value === "object") return Object.values(value).some(isFilled);
3136
+ return true;
3137
+ }
3138
+ function sanitizeRescueValues(values) {
3139
+ const out = {};
3140
+ if (!values || typeof values !== "object") return out;
3141
+ for (const key of FORM_RESCUE_VALUE_FIELDS) {
3142
+ if (isExcludedRescueField(key)) continue;
3143
+ const raw = values[key];
3144
+ if (typeof raw !== "string") continue;
3145
+ const trimmed = raw.trim().slice(0, FORM_RESCUE_MAX_VALUE_CHARS);
3146
+ if (trimmed) out[key] = trimmed;
3147
+ }
3148
+ return out;
3149
+ }
3150
+ function filledRescueFields(values, fieldNames) {
3151
+ return fieldNames.filter((name) => !isExcludedRescueField(name) && isFilled(values[name])).slice(0, FORM_RESCUE_MAX_FIELDS);
3152
+ }
3153
+ function rescueCompletionPct(filledCount, totalCount) {
3154
+ if (totalCount <= 0) return 0;
3155
+ return Math.max(0, Math.min(100, Math.round(filledCount / totalCount * 100)));
3156
+ }
3157
+ function sanitizeRescueFieldName(value) {
3158
+ if (typeof value !== "string") return null;
3159
+ const trimmed = value.trim();
3160
+ return /^[A-Za-z0-9_.-]{1,64}$/.test(trimmed) && !isExcludedRescueField(trimmed) ? trimmed : null;
3161
+ }
3162
+ var FORM_RESCUE_EVENTS = {
3163
+ started: "form_started",
3164
+ progress: "form_progress",
3165
+ leadCaptured: "form_lead_captured",
3166
+ abandoned: "form_abandoned",
3167
+ submitted: "form_submitted",
3168
+ rescued: "form_rescued",
3169
+ resumed: "form_resumed"
3170
+ };
3171
+ function captureFormRescueEvent(event, properties) {
3172
+ try {
3173
+ if (typeof window === "undefined") return;
3174
+ const ph = window.posthog;
3175
+ if (typeof _optionalChain([ph, 'optionalAccess', _64 => _64.capture]) === "function") ph.capture(event, properties);
3176
+ } catch (e9) {
3177
+ }
3178
+ }
3179
+
3180
+ // src/hooks/use-form-rescue.ts
3181
+ var LOCAL_DRAFT_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
3182
+ var STORAGE_PREFIX = "form-rescue:v1:";
3183
+ var UTM_KEYS = ["source", "medium", "campaign", "content", "term"];
3184
+ function newAttemptId() {
3185
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
3186
+ const bytes = new Uint8Array(16);
3187
+ crypto.getRandomValues(bytes);
3188
+ bytes[6] = bytes[6] & 15 | 64;
3189
+ bytes[8] = bytes[8] & 63 | 128;
3190
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
3191
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
3192
+ }
3193
+ function readLocalDraft(formId) {
3194
+ try {
3195
+ const raw = window.localStorage.getItem(STORAGE_PREFIX + formId);
3196
+ if (!raw) return null;
3197
+ const parsed = JSON.parse(raw);
3198
+ if (!isFormAttemptId(parsed.attemptId) || typeof parsed.savedAt !== "number") return null;
3199
+ if (Date.now() - parsed.savedAt > LOCAL_DRAFT_TTL_MS) return null;
3200
+ return { attemptId: parsed.attemptId, values: sanitizeRescueValues(parsed.values), savedAt: parsed.savedAt };
3201
+ } catch (e10) {
3202
+ return null;
3203
+ }
3204
+ }
3205
+ function writeLocalDraft(formId, draft) {
3206
+ try {
3207
+ window.localStorage.setItem(STORAGE_PREFIX + formId, JSON.stringify(draft));
3208
+ } catch (e11) {
3209
+ }
3210
+ }
3211
+ function clearLocalDraft(formId) {
3212
+ try {
3213
+ window.localStorage.removeItem(STORAGE_PREFIX + formId);
3214
+ } catch (e12) {
3215
+ }
3216
+ }
3217
+ function completeFormRescue(form, attemptId) {
3218
+ if (!form || typeof window === "undefined") return;
3219
+ const local = readLocalDraft(form.id);
3220
+ captureFormRescueEvent(FORM_RESCUE_EVENTS.submitted, {
3221
+ form_id: form.id,
3222
+ attempt_id: isFormAttemptId(attemptId) ? attemptId : _nullishCoalesce(_optionalChain([local, 'optionalAccess', _65 => _65.attemptId]), () => ( null))
3223
+ });
3224
+ clearLocalDraft(form.id);
3225
+ }
3226
+ function readUtm() {
3227
+ try {
3228
+ const params = new URLSearchParams(window.location.search);
3229
+ const utm = {};
3230
+ for (const key of UTM_KEYS) {
3231
+ const value = params.get(`utm_${key}`);
3232
+ if (value) utm[key] = value.slice(0, 200);
3233
+ }
3234
+ return Object.keys(utm).length ? utm : void 0;
3235
+ } catch (e13) {
3236
+ return void 0;
3237
+ }
3238
+ }
3239
+ function useFormRescue({ form, fieldNames, onRestore, getSignals }) {
3240
+ const draftsUrl = _optionalChain([_chunkLCMT2GZKcjs.useEndpointsRuntime.call(void 0, ), 'optionalAccess', _66 => _66.formDraftsUrl]);
3241
+ const formId = _nullishCoalesce(_optionalChain([form, 'optionalAccess', _67 => _67.id]), () => ( null));
3242
+ const attemptIdRef = _react.useRef.call(void 0, null);
3243
+ const resumeTokenRef = _react.useRef.call(void 0, null);
3244
+ const latestRef = _react.useRef.call(void 0, null);
3245
+ const dirtyRef = _react.useRef.call(void 0, false);
3246
+ const startedRef = _react.useRef.call(void 0, false);
3247
+ const leadCapturedRef = _react.useRef.call(void 0, false);
3248
+ const completedRef = _react.useRef.call(void 0, false);
3249
+ const timerRef = _react.useRef.call(void 0, null);
3250
+ const fieldNamesRef = _react.useRef.call(void 0, fieldNames);
3251
+ const onRestoreRef = _react.useRef.call(void 0, onRestore);
3252
+ const getSignalsRef = _react.useRef.call(void 0, getSignals);
3253
+ _react.useEffect.call(void 0, () => {
3254
+ fieldNamesRef.current = fieldNames;
3255
+ onRestoreRef.current = onRestore;
3256
+ getSignalsRef.current = getSignals;
3257
+ });
3258
+ const attemptId = _react.useCallback.call(void 0, () => {
3259
+ if (!attemptIdRef.current) attemptIdRef.current = newAttemptId();
3260
+ return attemptIdRef.current;
3261
+ }, []);
3262
+ const send = _react.useCallback.call(void 0,
3263
+ (keepalive) => {
3264
+ if (!formId || !draftsUrl || !dirtyRef.current || completedRef.current || !latestRef.current) return;
3265
+ dirtyRef.current = false;
3266
+ const body = {
3267
+ attempt_id: attemptId(),
3268
+ form_id: formId,
3269
+ ...latestRef.current,
3270
+ source_path: typeof window !== "undefined" ? window.location.pathname : "/",
3271
+ utm: readUtm()
3272
+ };
3273
+ try {
3274
+ void _chunkVTYP25OWcjs.contentFetch.call(void 0, draftsUrl, {
3275
+ method: "POST",
3276
+ headers: { "Content-Type": "application/json" },
3277
+ body: JSON.stringify({ ...body, ..._nullishCoalesce(_optionalChain([getSignalsRef, 'access', _68 => _68.current, 'optionalCall', _69 => _69()]), () => ( {})) }),
3278
+ keepalive
3279
+ }).catch(() => void 0);
3280
+ } catch (e14) {
3281
+ }
3282
+ captureFormRescueEvent(FORM_RESCUE_EVENTS.progress, {
3283
+ form_id: formId,
3284
+ attempt_id: attemptId(),
3285
+ fields_filled: body.fields_filled,
3286
+ last_field: body.last_field,
3287
+ completion_pct: body.completion_pct
3288
+ });
3289
+ },
3290
+ [attemptId, draftsUrl, formId]
3291
+ );
3292
+ _react.useEffect.call(void 0, () => {
3293
+ if (!formId || typeof window === "undefined") return void 0;
3294
+ let cancelled = false;
3295
+ const token = new URLSearchParams(window.location.search).get(FORM_RESCUE_RESUME_PARAM);
3296
+ const restoreLocal = () => {
3297
+ const local = readLocalDraft(formId);
3298
+ if (!local) return;
3299
+ attemptIdRef.current = local.attemptId;
3300
+ if (Object.keys(local.values).length) _optionalChain([onRestoreRef, 'access', _70 => _70.current, 'optionalCall', _71 => _71(local.values)]);
3301
+ };
3302
+ if (token && draftsUrl && /^[A-Za-z0-9_-]{16,128}$/.test(token)) {
3303
+ _chunkVTYP25OWcjs.contentFetch.call(void 0, `${draftsUrl}/resume/${encodeURIComponent(token)}`).then(async (res) => res.ok ? await res.json() : null).then((data) => {
3304
+ if (cancelled) return;
3305
+ if (!data || data.form_id !== formId) {
3306
+ restoreLocal();
3307
+ return;
3308
+ }
3309
+ resumeTokenRef.current = token;
3310
+ _optionalChain([onRestoreRef, 'access', _72 => _72.current, 'optionalCall', _73 => _73(sanitizeRescueValues(data.values))]);
3311
+ captureFormRescueEvent(FORM_RESCUE_EVENTS.resumed, { form_id: formId, attempt_id: attemptId() });
3312
+ }).catch(() => {
3313
+ if (!cancelled) restoreLocal();
3314
+ });
3315
+ } else {
3316
+ restoreLocal();
3317
+ }
3318
+ return () => {
3319
+ cancelled = true;
3320
+ };
3321
+ }, [attemptId, draftsUrl, formId]);
3322
+ _react.useEffect.call(void 0, () => {
3323
+ if (!formId || typeof document === "undefined") return void 0;
3324
+ const onHide = () => {
3325
+ if (completedRef.current || !startedRef.current) return;
3326
+ if (timerRef.current) {
3327
+ clearTimeout(timerRef.current);
3328
+ timerRef.current = null;
3329
+ }
3330
+ send(true);
3331
+ captureFormRescueEvent(FORM_RESCUE_EVENTS.abandoned, {
3332
+ form_id: formId,
3333
+ attempt_id: attemptId(),
3334
+ last_field: _nullishCoalesce(_optionalChain([latestRef, 'access', _74 => _74.current, 'optionalAccess', _75 => _75.last_field]), () => ( null)),
3335
+ completion_pct: _nullishCoalesce(_optionalChain([latestRef, 'access', _76 => _76.current, 'optionalAccess', _77 => _77.completion_pct]), () => ( 0))
3336
+ });
3337
+ };
3338
+ const onVisibility = () => {
3339
+ if (document.visibilityState === "hidden") onHide();
3340
+ };
3341
+ document.addEventListener("visibilitychange", onVisibility);
3342
+ window.addEventListener("pagehide", onHide);
3343
+ return () => {
3344
+ document.removeEventListener("visibilitychange", onVisibility);
3345
+ window.removeEventListener("pagehide", onHide);
3346
+ if (timerRef.current) clearTimeout(timerRef.current);
3347
+ };
3348
+ }, [attemptId, formId, send]);
3349
+ const track = _react.useCallback.call(void 0,
3350
+ (values, lastField) => {
3351
+ if (!formId || completedRef.current) return;
3352
+ const names = fieldNamesRef.current;
3353
+ const visible = {};
3354
+ for (const name of names) visible[name] = values[name];
3355
+ const filled = filledRescueFields(visible, names);
3356
+ if (!filled.length) return;
3357
+ if (!startedRef.current) {
3358
+ startedRef.current = true;
3359
+ captureFormRescueEvent(FORM_RESCUE_EVENTS.started, { form_id: formId, attempt_id: attemptId() });
3360
+ }
3361
+ const clean = sanitizeRescueValues(visible);
3362
+ if (!leadCapturedRef.current && isRescueEmail(clean.email)) {
3363
+ leadCapturedRef.current = true;
3364
+ captureFormRescueEvent(FORM_RESCUE_EVENTS.leadCaptured, { form_id: formId, attempt_id: attemptId() });
3365
+ }
3366
+ latestRef.current = {
3367
+ values: clean,
3368
+ fields_filled: filled,
3369
+ last_field: sanitizeRescueFieldName(lastField),
3370
+ completion_pct: rescueCompletionPct(filled.length, names.length)
3371
+ };
3372
+ dirtyRef.current = true;
3373
+ writeLocalDraft(formId, { attemptId: attemptId(), values: clean, savedAt: Date.now() });
3374
+ if (timerRef.current) clearTimeout(timerRef.current);
3375
+ timerRef.current = setTimeout(() => {
3376
+ timerRef.current = null;
3377
+ send(false);
3378
+ }, FORM_RESCUE_DEBOUNCE_MS);
3379
+ },
3380
+ [attemptId, formId, send]
3381
+ );
3382
+ const submitFields = _react.useCallback.call(void 0, () => {
3383
+ if (!formId) return {};
3384
+ return {
3385
+ [FORM_RESCUE_ATTEMPT_FIELD]: attemptId(),
3386
+ ...resumeTokenRef.current ? { [FORM_RESCUE_RESUME_FIELD]: resumeTokenRef.current } : {}
3387
+ };
3388
+ }, [attemptId, formId]);
3389
+ const complete = _react.useCallback.call(void 0, () => {
3390
+ if (!formId) return;
3391
+ if (timerRef.current) {
3392
+ clearTimeout(timerRef.current);
3393
+ timerRef.current = null;
3394
+ }
3395
+ completeFormRescue(form, attemptId());
3396
+ attemptIdRef.current = null;
3397
+ resumeTokenRef.current = null;
3398
+ latestRef.current = null;
3399
+ dirtyRef.current = false;
3400
+ startedRef.current = false;
3401
+ leadCapturedRef.current = false;
3402
+ }, [attemptId, form, formId]);
3403
+ return _react.useMemo.call(void 0, () => ({ track, submitFields, complete }), [track, submitFields, complete]);
3404
+ }
3405
+
3406
+ // src/hooks/use-rescued-form.ts
3407
+
3408
+ function flattenOneLevel(values) {
3409
+ const flat = {};
3410
+ for (const [key, value] of Object.entries(values)) {
3411
+ if (value && typeof value === "object" && !Array.isArray(value)) Object.assign(flat, value);
3412
+ else flat[key] = value;
3413
+ }
3414
+ return flat;
3415
+ }
3416
+ function useRescuedForm(form, { rescue, fields, getSignals, fieldPath }) {
3417
+ const { watch, getValues, setValue } = form;
3418
+ const handle = useFormRescue({
3419
+ form: rescue,
3420
+ fieldNames: fields,
3421
+ getSignals,
3422
+ onRestore: (values) => {
3423
+ for (const name of fields) {
3424
+ const value = values[name];
3425
+ if (!value) continue;
3426
+ const path = fieldPath ? fieldPath(name) : name;
3427
+ if (!getValues(path)) setValue(path, value, { shouldDirty: true });
3428
+ }
3429
+ }
3430
+ });
3431
+ _react.useEffect.call(void 0, () => {
3432
+ const subscription = watch((values, { name }) => {
3433
+ handle.track(flattenOneLevel(values), name ? _nullishCoalesce(name.split(".").pop(), () => ( null)) : null);
3434
+ });
3435
+ return () => subscription.unsubscribe();
3436
+ }, [watch, handle]);
3437
+ return handle;
3438
+ }
3439
+
3440
+
3441
+
3442
+
3443
+
3444
+
3445
+
3446
+
3447
+
3448
+
3449
+
3450
+
3451
+
3452
+
3453
+
3454
+
3455
+
3456
+
3457
+
3458
+
3459
+
3460
+
3461
+
3462
+
3463
+
3464
+
3465
+
3062
3466
 
3063
3467
 
3064
3468
 
@@ -3145,5 +3549,5 @@ function useHumanitySignals() {
3145
3549
 
3146
3550
 
3147
3551
 
3148
- exports.useAutoLimitTags = useAutoLimitTags; exports.useKeyboardCollisionPadding = useKeyboardCollisionPadding; exports.useDeferredError = useDeferredError; exports.DRAG_AND_DROP_MEDIA_QUERY = DRAG_AND_DROP_MEDIA_QUERY; exports.useDragAndDropEnabled = useDragAndDropEnabled; exports.useFocusTrap = useFocusTrap; exports.useHorizontalScrollbar = useHorizontalScrollbar; exports.useLocalStorage = useLocalStorage; exports.useMemoizedCallback = useMemoizedCallback; exports.useNotificationPermission = useNotificationPermission; exports.useOnboardingState = useOnboardingState; exports.useSearch = useSearch; exports.useTablePagination = useTablePagination; exports.useThrottle = useThrottle; exports.useWindowSize = useWindowSize; exports.usePreventScroll = _overlays.usePreventScroll; exports.platformIcons = platformIcons; exports.transformPlatformConfigsToOptions = transformPlatformConfigsToOptions; exports.getPlatformIcon = getPlatformIcon; exports.getSmallPlatformIcon = getSmallPlatformIcon; exports.getPlatformIconComponent = getPlatformIconComponent; exports.usePlatformConfig = usePlatformConfig; exports.usePlatformByValue = usePlatformByValue; exports.useValidatePlatform = useValidatePlatform; exports.dotColorByVariant = dotColorByVariant; exports.progressColorByVariant = progressColorByVariant; exports.ToastCard = ToastCard; exports.CommandApprovalToast = CommandApprovalToast; exports.Toaster = Toaster; exports.showToast = showToast; exports.showCommandApprovalToast = showCommandApprovalToast; exports.toast = toast; exports.useToast = useToast; exports.useContactSubmission = useContactSubmission; exports.useCopyToClipboard = useCopyToClipboard; exports.configureBatchImageFetch = configureBatchImageFetch; exports.batchFetchAuthenticatedImages = batchFetchAuthenticatedImages; exports.useBatchImages = useBatchImages; exports.configureAuthenticatedImage = configureAuthenticatedImage; exports.useAuthenticatedImage = useAuthenticatedImage; exports.flattenQueryVariables = flattenQueryVariables; exports.mergeDefaults = mergeDefaults; exports.validateSchema = validateSchema; exports.getArrayParams = getArrayParams; exports.getRequiredParams = getRequiredParams; exports.extractVariablesFromQuery = extractVariablesFromQuery; exports.isScalarType = isScalarType; exports.isInputObjectType = isInputObjectType; exports.GraphQLIntrospector = GraphQLIntrospector; exports.introspector = introspector; exports.urlParamsToVariables = urlParamsToVariables; exports.variablesToUrlParams = variablesToUrlParams; exports.coerceValue = coerceValue; exports.setNestedValue = setNestedValue; exports.getNestedValue = getNestedValue; exports.mergeVariables = mergeVariables; exports.clearParams = clearParams; exports.validateVariables = validateVariables; exports.useQueryParams = useQueryParams; exports.useApiParams = useApiParams; exports.useCursorPaginationState = useCursorPaginationState; exports.useNatsClient = useNatsClient; exports.validateAccessCode = validateAccessCode; exports.consumeAccessCode = consumeAccessCode; exports.validateAndConsumeAccessCode = validateAndConsumeAccessCode; exports.useAccessCodeIntegration = useAccessCodeIntegration; exports.toGoogleSheetsEmbedUrl = toGoogleSheetsEmbedUrl; exports.toGoogleSheetsOriginalUrl = toGoogleSheetsOriginalUrl; exports.toFigmaEmbedUrl = toFigmaEmbedUrl; exports.isFigmaSlidesUrl = isFigmaSlidesUrl; exports.toFigmaOriginalUrl = toFigmaOriginalUrl; exports.toClaudeMirrorPath = toClaudeMirrorPath; exports.toClaudeEmbedUrl = toClaudeEmbedUrl; exports.useClaudeMirrorSrc = useClaudeMirrorSrc; exports.useScrollToHash = useScrollToHash; exports.HONEYPOT_FIELD = HONEYPOT_FIELD; exports.ELAPSED_MS_FIELD = ELAPSED_MS_FIELD; exports.DEFAULT_MIN_FILL_MS = DEFAULT_MIN_FILL_MS; exports.HUMANITY_SIGNAL_KEYS = HUMANITY_SIGNAL_KEYS; exports.isHumanitySignalKey = isHumanitySignalKey; exports.extractHumanitySignals = extractHumanitySignals; exports.findHoneypotCopySource = findHoneypotCopySource; exports.evaluateHumanitySignals = evaluateHumanitySignals; exports.splitCsvEnv = splitCsvEnv; exports.useHumanitySignals = useHumanitySignals;
3149
- //# sourceMappingURL=chunk-YNGAJGYB.cjs.map
3552
+ exports.useAutoLimitTags = useAutoLimitTags; exports.useKeyboardCollisionPadding = useKeyboardCollisionPadding; exports.useDeferredError = useDeferredError; exports.DRAG_AND_DROP_MEDIA_QUERY = DRAG_AND_DROP_MEDIA_QUERY; exports.useDragAndDropEnabled = useDragAndDropEnabled; exports.useFocusTrap = useFocusTrap; exports.useHorizontalScrollbar = useHorizontalScrollbar; exports.useLocalStorage = useLocalStorage; exports.useMemoizedCallback = useMemoizedCallback; exports.useNotificationPermission = useNotificationPermission; exports.useOnboardingState = useOnboardingState; exports.useSearch = useSearch; exports.useTablePagination = useTablePagination; exports.useThrottle = useThrottle; exports.useWindowSize = useWindowSize; exports.usePreventScroll = _overlays.usePreventScroll; exports.platformIcons = platformIcons; exports.transformPlatformConfigsToOptions = transformPlatformConfigsToOptions; exports.getPlatformIcon = getPlatformIcon; exports.getSmallPlatformIcon = getSmallPlatformIcon; exports.getPlatformIconComponent = getPlatformIconComponent; exports.usePlatformConfig = usePlatformConfig; exports.usePlatformByValue = usePlatformByValue; exports.useValidatePlatform = useValidatePlatform; exports.dotColorByVariant = dotColorByVariant; exports.progressColorByVariant = progressColorByVariant; exports.ToastCard = ToastCard; exports.CommandApprovalToast = CommandApprovalToast; exports.Toaster = Toaster; exports.showToast = showToast; exports.showCommandApprovalToast = showCommandApprovalToast; exports.toast = toast; exports.useToast = useToast; exports.useContactSubmission = useContactSubmission; exports.useCopyToClipboard = useCopyToClipboard; exports.configureBatchImageFetch = configureBatchImageFetch; exports.batchFetchAuthenticatedImages = batchFetchAuthenticatedImages; exports.useBatchImages = useBatchImages; exports.configureAuthenticatedImage = configureAuthenticatedImage; exports.useAuthenticatedImage = useAuthenticatedImage; exports.flattenQueryVariables = flattenQueryVariables; exports.mergeDefaults = mergeDefaults; exports.validateSchema = validateSchema; exports.getArrayParams = getArrayParams; exports.getRequiredParams = getRequiredParams; exports.extractVariablesFromQuery = extractVariablesFromQuery; exports.isScalarType = isScalarType; exports.isInputObjectType = isInputObjectType; exports.GraphQLIntrospector = GraphQLIntrospector; exports.introspector = introspector; exports.urlParamsToVariables = urlParamsToVariables; exports.variablesToUrlParams = variablesToUrlParams; exports.coerceValue = coerceValue; exports.setNestedValue = setNestedValue; exports.getNestedValue = getNestedValue; exports.mergeVariables = mergeVariables; exports.clearParams = clearParams; exports.validateVariables = validateVariables; exports.useQueryParams = useQueryParams; exports.useApiParams = useApiParams; exports.useCursorPaginationState = useCursorPaginationState; exports.useNatsClient = useNatsClient; exports.validateAccessCode = validateAccessCode; exports.consumeAccessCode = consumeAccessCode; exports.validateAndConsumeAccessCode = validateAndConsumeAccessCode; exports.useAccessCodeIntegration = useAccessCodeIntegration; exports.toGoogleSheetsEmbedUrl = toGoogleSheetsEmbedUrl; exports.toGoogleSheetsOriginalUrl = toGoogleSheetsOriginalUrl; exports.toFigmaEmbedUrl = toFigmaEmbedUrl; exports.isFigmaSlidesUrl = isFigmaSlidesUrl; exports.toFigmaOriginalUrl = toFigmaOriginalUrl; exports.toClaudeMirrorPath = toClaudeMirrorPath; exports.toClaudeEmbedUrl = toClaudeEmbedUrl; exports.useClaudeMirrorSrc = useClaudeMirrorSrc; exports.useScrollToHash = useScrollToHash; exports.HONEYPOT_FIELD = HONEYPOT_FIELD; exports.ELAPSED_MS_FIELD = ELAPSED_MS_FIELD; exports.DEFAULT_MIN_FILL_MS = DEFAULT_MIN_FILL_MS; exports.HUMANITY_SIGNAL_KEYS = HUMANITY_SIGNAL_KEYS; exports.isHumanitySignalKey = isHumanitySignalKey; exports.extractHumanitySignals = extractHumanitySignals; exports.findHoneypotCopySource = findHoneypotCopySource; exports.evaluateHumanitySignals = evaluateHumanitySignals; exports.splitCsvEnv = splitCsvEnv; exports.useHumanitySignals = useHumanitySignals; exports.defineRescueForm = defineRescueForm; exports.getRescueForm = getRescueForm; exports.listRescueForms = listRescueForms; exports.RESCUE_FORMS = RESCUE_FORMS; exports.FORM_RESCUE_VALUE_FIELDS = FORM_RESCUE_VALUE_FIELDS; exports.isExcludedRescueField = isExcludedRescueField; exports.FORM_RESCUE_MAX_VALUE_CHARS = FORM_RESCUE_MAX_VALUE_CHARS; exports.FORM_RESCUE_DEBOUNCE_MS = FORM_RESCUE_DEBOUNCE_MS; exports.FORM_RESCUE_MAX_FIELDS = FORM_RESCUE_MAX_FIELDS; exports.FORM_RESCUE_ATTEMPT_FIELD = FORM_RESCUE_ATTEMPT_FIELD; exports.FORM_RESCUE_RESUME_FIELD = FORM_RESCUE_RESUME_FIELD; exports.FORM_RESCUE_SUBMIT_KEYS = FORM_RESCUE_SUBMIT_KEYS; exports.FORM_RESCUE_RESUME_PARAM = FORM_RESCUE_RESUME_PARAM; exports.FORM_DRAFT_STATUSES = FORM_DRAFT_STATUSES; exports.FORM_RESCUE_SKIP_REASONS = FORM_RESCUE_SKIP_REASONS; exports.isRescueEmail = isRescueEmail; exports.isFormAttemptId = isFormAttemptId; exports.sanitizeRescueValues = sanitizeRescueValues; exports.filledRescueFields = filledRescueFields; exports.rescueCompletionPct = rescueCompletionPct; exports.sanitizeRescueFieldName = sanitizeRescueFieldName; exports.FORM_RESCUE_EVENTS = FORM_RESCUE_EVENTS; exports.captureFormRescueEvent = captureFormRescueEvent; exports.completeFormRescue = completeFormRescue; exports.useFormRescue = useFormRescue; exports.useRescuedForm = useRescuedForm;
3553
+ //# sourceMappingURL=chunk-6LWIJJJ6.cjs.map