@rhinestone/deposit-modal 0.13.0 → 0.14.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 (57) hide show
  1. package/README.md +47 -12
  2. package/bridge-transcript.json +653 -0
  3. package/dist/ClaimModal-GDFENSLV.mjs +13 -0
  4. package/dist/ClaimModal-L3FUBI5U.cjs +13 -0
  5. package/dist/{DepositModalReown-3H75G3XQ.mjs → DepositModalReown-2EVV64OA.mjs} +30 -27
  6. package/dist/{DepositModalReown-YNNHLAV2.cjs → DepositModalReown-GAD45GIC.cjs} +77 -74
  7. package/dist/WithdrawModal-FAQH35NG.cjs +12 -0
  8. package/dist/WithdrawModal-IKUHF5CF.mjs +12 -0
  9. package/dist/{chunk-RAADLTSW.cjs → chunk-4J5ADVIN.cjs} +184 -139
  10. package/dist/{chunk-DSIZNRWA.mjs → chunk-5Q5CSVKF.mjs} +1049 -388
  11. package/dist/{chunk-HOGZKHHY.cjs → chunk-62UCV2LG.cjs} +3 -3
  12. package/dist/{chunk-CVGNCUVU.cjs → chunk-7AZFT2MV.cjs} +22 -13
  13. package/dist/{chunk-7N77GIP4.cjs → chunk-A6JPBMYY.cjs} +465 -171
  14. package/dist/{chunk-GACIGCSN.cjs → chunk-AQVJUXSG.cjs} +1 -1
  15. package/dist/{chunk-LTMMETAB.mjs → chunk-GZ4GQ5MC.mjs} +404 -110
  16. package/dist/{chunk-ZMT4ATHR.cjs → chunk-HAQOFI3D.cjs} +594 -41
  17. package/dist/{chunk-FZ5FZFIG.mjs → chunk-LMG46EP2.mjs} +1 -1
  18. package/dist/{chunk-2G2EIN4A.cjs → chunk-NQMC5VKQ.cjs} +1343 -682
  19. package/dist/{chunk-OLCD75JK.mjs → chunk-QACOOLOE.mjs} +451 -131
  20. package/dist/{chunk-XYJFEN5D.mjs → chunk-R5UQ3TN4.mjs} +1 -1
  21. package/dist/{chunk-EOMT5LKX.mjs → chunk-UX35GYLM.mjs} +556 -3
  22. package/dist/{chunk-YREVFB64.mjs → chunk-VALXN5IO.mjs} +16 -7
  23. package/dist/{chunk-COCBCQQC.mjs → chunk-XCTRKCNM.mjs} +51 -6
  24. package/dist/{chunk-5NUIKYSF.cjs → chunk-YP7QVKQ6.cjs} +458 -138
  25. package/dist/claim.cjs +6 -6
  26. package/dist/claim.d.cts +3 -3
  27. package/dist/claim.d.ts +3 -3
  28. package/dist/claim.mjs +5 -5
  29. package/dist/constants.cjs +2 -2
  30. package/dist/constants.d.cts +1 -1
  31. package/dist/constants.d.ts +1 -1
  32. package/dist/constants.mjs +1 -1
  33. package/dist/deposit.cjs +6 -6
  34. package/dist/deposit.d.cts +2 -2
  35. package/dist/deposit.d.ts +2 -2
  36. package/dist/deposit.mjs +5 -5
  37. package/dist/embed.cjs +310 -102
  38. package/dist/embed.d.cts +7 -1
  39. package/dist/embed.d.ts +7 -1
  40. package/dist/embed.mjs +285 -77
  41. package/dist/index.cjs +9 -9
  42. package/dist/index.d.cts +1 -1
  43. package/dist/index.d.ts +1 -1
  44. package/dist/index.mjs +8 -8
  45. package/dist/types-Bho4OA03.d.ts +982 -0
  46. package/dist/types-DP_3KwlD.d.cts +982 -0
  47. package/dist/withdraw.cjs +5 -5
  48. package/dist/withdraw.d.cts +3 -3
  49. package/dist/withdraw.d.ts +3 -3
  50. package/dist/withdraw.mjs +4 -4
  51. package/package.json +29 -7
  52. package/dist/ClaimModal-CREZO27I.mjs +0 -11
  53. package/dist/ClaimModal-JRIA32U2.cjs +0 -11
  54. package/dist/WithdrawModal-NVRX44IZ.mjs +0 -10
  55. package/dist/WithdrawModal-YYSBPCJJ.cjs +0 -10
  56. package/dist/types-B89I8_8H.d.ts +0 -638
  57. package/dist/types-nnDR4tqA.d.cts +0 -638
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CdnIcon,
3
3
  ChevronRightIcon
4
- } from "./chunk-EOMT5LKX.mjs";
4
+ } from "./chunk-UX35GYLM.mjs";
5
5
 
6
6
  // src/components/ui/ListRow.tsx
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -1,6 +1,7 @@
1
1
  import {
2
+ MODAL_VERSION,
2
3
  serviceHeaders
3
- } from "./chunk-FZ5FZFIG.mjs";
4
+ } from "./chunk-LMG46EP2.mjs";
4
5
  import {
5
6
  CHAIN_DISPLAY_ORDER,
6
7
  HYPERCORE_CHAIN_ID,
@@ -83,7 +84,7 @@ function Modal({
83
84
  (event) => {
84
85
  if (event.key === "Escape") {
85
86
  event.preventDefault();
86
- onClose();
87
+ onClose("escape");
87
88
  return;
88
89
  }
89
90
  if (event.key === "Tab" && contentRef.current) {
@@ -109,7 +110,7 @@ function Modal({
109
110
  const handleOverlayClick = useCallback(
110
111
  (event) => {
111
112
  if (closeOnOverlayClick && event.target === overlayRef.current) {
112
- onClose();
113
+ onClose("overlay");
113
114
  }
114
115
  },
115
116
  [closeOnOverlayClick, onClose]
@@ -2875,6 +2876,554 @@ function formatReceiveEstimate(params) {
2875
2876
  return sameSymbol ? `${formatted} ${params.targetSymbol}` : `~${formatted} ${params.targetSymbol}`;
2876
2877
  }
2877
2878
 
2879
+ // src/core/analytics.tsx
2880
+ import {
2881
+ createContext as createContext3,
2882
+ useCallback as useCallback2,
2883
+ useContext as useContext3,
2884
+ useEffect as useEffect4,
2885
+ useMemo as useMemo3,
2886
+ useRef as useRef3
2887
+ } from "react";
2888
+
2889
+ // src/core/analytics-ingest.ts
2890
+ var DEFAULT_ANALYTICS_INGEST_URL = "https://v1.orchestrator.rhinestone.dev/deposit-processor/analytics/events";
2891
+ var MAX_BATCH = 20;
2892
+ var MAX_QUEUE = 200;
2893
+ var FLUSH_DELAY_MS = 5e3;
2894
+ var MAX_BODY_BYTES = 48 * 1024;
2895
+ var TOKEN_REFRESH_MARGIN_MS = 6e4;
2896
+ var TOKEN_TIMEOUT_MS = 3e3;
2897
+ var CLOSE_MINT_WAIT_MS = 1500;
2898
+ var MAX_ATTEMPTS = 3;
2899
+ var MAX_BACKOFF_MS = 3e4;
2900
+ var IDLE = 0;
2901
+ var CLOSING = 1;
2902
+ var DISMISSAL = 2;
2903
+ var ENVELOPE_FIELDS = /* @__PURE__ */ new Set([
2904
+ "type",
2905
+ "timestamp",
2906
+ "session_id",
2907
+ "modal",
2908
+ "widget_version",
2909
+ "session_properties",
2910
+ "funding_method"
2911
+ ]);
2912
+ function createIngestTransport(options) {
2913
+ const {
2914
+ ingestUrl,
2915
+ backendUrl,
2916
+ proxyOrigin,
2917
+ sessionId,
2918
+ modal,
2919
+ widgetVersion,
2920
+ sessionProperties,
2921
+ onFailure
2922
+ } = options;
2923
+ const fetchImpl = options.fetchImpl ?? (typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0);
2924
+ const now = options.now ?? (() => Date.now());
2925
+ const createEventId = options.createEventId ?? randomUuid;
2926
+ const mintUrl = `${backendUrl.replace(/\/$/, "")}/analytics/ingest-token`;
2927
+ const queue = [];
2928
+ let sequence = 0;
2929
+ let dropped = 0;
2930
+ let token = null;
2931
+ let mintUnavailable = false;
2932
+ let mintFailures = 0;
2933
+ let mintBackoffUntil = 0;
2934
+ let timer = null;
2935
+ let sending = false;
2936
+ let disposed = false;
2937
+ let pendingRun = false;
2938
+ let urgency = IDLE;
2939
+ let minting = null;
2940
+ let mintAbort = null;
2941
+ const sleepers = /* @__PURE__ */ new Set();
2942
+ function report(reason, status) {
2943
+ try {
2944
+ onFailure({ reason, status, droppedEvents: dropped });
2945
+ } catch {
2946
+ }
2947
+ }
2948
+ function drop(batch, reason, status) {
2949
+ dropped += batch.length;
2950
+ report(reason, status);
2951
+ }
2952
+ function toWireEvent(event) {
2953
+ const payload = {};
2954
+ for (const [key, value] of Object.entries(event)) {
2955
+ if (!ENVELOPE_FIELDS.has(key)) payload[key] = value;
2956
+ }
2957
+ const wire = {
2958
+ event_id: createEventId(),
2959
+ session_id: sessionId,
2960
+ sequence: sequence++,
2961
+ type: String(event.type),
2962
+ timestamp: String(event.timestamp),
2963
+ widget_version: widgetVersion,
2964
+ proxy_origin: proxyOrigin,
2965
+ modal,
2966
+ session_properties: sessionProperties,
2967
+ payload
2968
+ };
2969
+ if (modal === "deposit") wire.funding_method = event.funding_method ?? null;
2970
+ return wire;
2971
+ }
2972
+ function takeBatch() {
2973
+ const batch = queue.slice(0, MAX_BATCH);
2974
+ while (batch.length > 1 && bodyOf(batch).length > MAX_BODY_BYTES) {
2975
+ batch.pop();
2976
+ }
2977
+ queue.splice(0, batch.length);
2978
+ return batch;
2979
+ }
2980
+ function bodyOf(batch) {
2981
+ return JSON.stringify({ events: batch });
2982
+ }
2983
+ function backoff(attempt) {
2984
+ return Math.min(1e3 * 2 ** (attempt - 1), MAX_BACKOFF_MS);
2985
+ }
2986
+ function sleep(ms) {
2987
+ return new Promise((resolve) => {
2988
+ const timeout = setTimeout(finish, ms);
2989
+ function finish() {
2990
+ clearTimeout(timeout);
2991
+ sleepers.delete(finish);
2992
+ resolve();
2993
+ }
2994
+ sleepers.add(finish);
2995
+ });
2996
+ }
2997
+ function interruptForUnload() {
2998
+ for (const wake of [...sleepers]) wake();
2999
+ mintAbort?.abort();
3000
+ }
3001
+ function retryDelay(response, attempt) {
3002
+ const seconds = Number(response.headers?.get?.("Retry-After"));
3003
+ if (Number.isFinite(seconds) && seconds > 0) {
3004
+ return Math.min(seconds * 1e3, MAX_BACKOFF_MS);
3005
+ }
3006
+ return backoff(attempt);
3007
+ }
3008
+ async function mintToken() {
3009
+ if (mintUnavailable || !fetchImpl) return;
3010
+ const controller = typeof AbortController === "function" ? new AbortController() : null;
3011
+ mintAbort = controller;
3012
+ const timeout = controller ? setTimeout(() => controller.abort(), TOKEN_TIMEOUT_MS) : null;
3013
+ let response;
3014
+ try {
3015
+ response = await fetchImpl(mintUrl, {
3016
+ method: "POST",
3017
+ headers: serviceHeaders(),
3018
+ signal: controller?.signal
3019
+ });
3020
+ } catch {
3021
+ if (urgency !== DISMISSAL) {
3022
+ mintFailures += 1;
3023
+ mintBackoffUntil = now() + backoff(mintFailures);
3024
+ }
3025
+ return;
3026
+ } finally {
3027
+ if (timeout !== null) clearTimeout(timeout);
3028
+ mintAbort = null;
3029
+ }
3030
+ if (response.status === 404 || response.status === 401 || response.status === 403) {
3031
+ mintUnavailable = true;
3032
+ report("token_unavailable", response.status);
3033
+ return;
3034
+ }
3035
+ if (!response.ok) {
3036
+ mintFailures += 1;
3037
+ mintBackoffUntil = now() + backoff(mintFailures);
3038
+ return;
3039
+ }
3040
+ try {
3041
+ const data = await response.json();
3042
+ const value = typeof data.token === "string" ? data.token : "";
3043
+ const expiresAt = Date.parse(String(data.expiresAt));
3044
+ if (!value || Number.isNaN(expiresAt)) throw new Error("malformed");
3045
+ token = { value, expiresAt };
3046
+ mintFailures = 0;
3047
+ mintBackoffUntil = 0;
3048
+ } catch {
3049
+ mintUnavailable = true;
3050
+ report("token_unavailable", response.status);
3051
+ }
3052
+ }
3053
+ function startMint() {
3054
+ if (!minting) {
3055
+ minting = mintToken().finally(() => {
3056
+ minting = null;
3057
+ });
3058
+ }
3059
+ return minting;
3060
+ }
3061
+ async function ensureToken(maxWaitMs) {
3062
+ if (mintUnavailable) return;
3063
+ if (token && token.expiresAt - now() > TOKEN_REFRESH_MARGIN_MS) return;
3064
+ if (now() < mintBackoffUntil) return;
3065
+ const pending = startMint();
3066
+ await (maxWaitMs === void 0 ? pending : Promise.race([pending, sleep(maxWaitMs)]));
3067
+ }
3068
+ async function deliver(batch) {
3069
+ if (!fetchImpl) return drop(batch, "unsupported");
3070
+ let attempt = 0;
3071
+ let refreshed = false;
3072
+ let unattributed = false;
3073
+ for (; ; ) {
3074
+ const terminal = urgency === DISMISSAL;
3075
+ attempt += 1;
3076
+ const headers = {
3077
+ "Content-Type": "application/json"
3078
+ };
3079
+ if (token && !unattributed) headers.Authorization = `Bearer ${token.value}`;
3080
+ let response;
3081
+ try {
3082
+ response = await fetchImpl(ingestUrl, {
3083
+ method: "POST",
3084
+ headers,
3085
+ body: bodyOf(batch),
3086
+ keepalive: true
3087
+ });
3088
+ } catch {
3089
+ if (terminal || attempt >= MAX_ATTEMPTS) {
3090
+ return drop(batch, "network");
3091
+ }
3092
+ await sleep(backoff(attempt));
3093
+ continue;
3094
+ }
3095
+ if (response.ok) return;
3096
+ const status = response.status;
3097
+ if (status === 401) {
3098
+ token = null;
3099
+ if (!refreshed && !terminal) {
3100
+ refreshed = true;
3101
+ await startMint();
3102
+ if (token) continue;
3103
+ }
3104
+ if (!unattributed) {
3105
+ unattributed = true;
3106
+ continue;
3107
+ }
3108
+ return drop(batch, "unauthorized", status);
3109
+ }
3110
+ if (status === 409) return drop(batch, "conflict", status);
3111
+ if (status === 429 || status >= 500) {
3112
+ if (terminal || attempt >= MAX_ATTEMPTS) {
3113
+ return drop(batch, status === 429 ? "throttled" : "unavailable", status);
3114
+ }
3115
+ await sleep(retryDelay(response, attempt));
3116
+ continue;
3117
+ }
3118
+ return drop(batch, "rejected", status);
3119
+ }
3120
+ }
3121
+ function escalate(level) {
3122
+ if (level <= urgency) return;
3123
+ urgency = level;
3124
+ if (level === DISMISSAL) interruptForUnload();
3125
+ }
3126
+ function onDismissal(event) {
3127
+ if (event.type === "pagehide" || document.visibilityState === "hidden") {
3128
+ escalate(DISMISSAL);
3129
+ }
3130
+ }
3131
+ function dismissalGuard(attach) {
3132
+ if (typeof window === "undefined" || typeof document === "undefined") return;
3133
+ const bind = attach ? "addEventListener" : "removeEventListener";
3134
+ window[bind]("pagehide", onDismissal);
3135
+ document[bind]("visibilitychange", onDismissal);
3136
+ }
3137
+ async function run(level) {
3138
+ escalate(level);
3139
+ if (sending) {
3140
+ pendingRun = true;
3141
+ return;
3142
+ }
3143
+ sending = true;
3144
+ try {
3145
+ while (queue.length > 0) {
3146
+ const batch = takeBatch();
3147
+ if (urgency !== DISMISSAL) {
3148
+ await ensureToken(urgency === CLOSING ? CLOSE_MINT_WAIT_MS : void 0);
3149
+ }
3150
+ await deliver(batch);
3151
+ }
3152
+ } finally {
3153
+ sending = false;
3154
+ }
3155
+ if (pendingRun) {
3156
+ pendingRun = false;
3157
+ await run(urgency);
3158
+ return;
3159
+ }
3160
+ if (!disposed) urgency = IDLE;
3161
+ else dismissalGuard(false);
3162
+ }
3163
+ function clearFlushTimer() {
3164
+ if (timer !== null) {
3165
+ clearTimeout(timer);
3166
+ timer = null;
3167
+ }
3168
+ }
3169
+ function scheduleFlush() {
3170
+ if (timer !== null || disposed) return;
3171
+ timer = setTimeout(() => {
3172
+ timer = null;
3173
+ void run(IDLE);
3174
+ }, FLUSH_DELAY_MS);
3175
+ }
3176
+ return {
3177
+ enqueue(event) {
3178
+ if (disposed) return;
3179
+ queue.push(toWireEvent(event));
3180
+ if (sequence === 1) void ensureToken();
3181
+ if (queue.length > MAX_QUEUE) {
3182
+ dropped += queue.length - MAX_QUEUE;
3183
+ queue.splice(0, queue.length - MAX_QUEUE);
3184
+ }
3185
+ if (queue.length >= MAX_BATCH) {
3186
+ clearFlushTimer();
3187
+ void run(IDLE);
3188
+ } else {
3189
+ scheduleFlush();
3190
+ }
3191
+ },
3192
+ flush(flushOptions) {
3193
+ const dismissal = flushOptions?.terminal ?? false;
3194
+ if (disposed && !dismissal) return;
3195
+ clearFlushTimer();
3196
+ void run(dismissal ? DISMISSAL : IDLE);
3197
+ },
3198
+ dispose() {
3199
+ if (disposed) return;
3200
+ disposed = true;
3201
+ clearFlushTimer();
3202
+ dismissalGuard(true);
3203
+ void run(CLOSING);
3204
+ }
3205
+ };
3206
+ }
3207
+ function randomUuid() {
3208
+ if (typeof globalThis.crypto?.randomUUID === "function") {
3209
+ return globalThis.crypto.randomUUID();
3210
+ }
3211
+ const bytes = new Uint8Array(16);
3212
+ globalThis.crypto?.getRandomValues?.(bytes);
3213
+ if (!bytes.some(Boolean)) {
3214
+ for (let index = 0; index < bytes.length; index += 1) {
3215
+ bytes[index] = Math.floor(Math.random() * 256);
3216
+ }
3217
+ }
3218
+ bytes[6] = bytes[6] & 15 | 64;
3219
+ bytes[8] = bytes[8] & 63 | 128;
3220
+ const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0"));
3221
+ return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
3222
+ }
3223
+ function resolveProxyOrigin(backendUrl) {
3224
+ if (!backendUrl.trim()) return null;
3225
+ try {
3226
+ const { origin } = new URL(backendUrl, globalThis.location?.href);
3227
+ return origin.startsWith("http") ? origin : null;
3228
+ } catch {
3229
+ return null;
3230
+ }
3231
+ }
3232
+
3233
+ // src/core/analytics.tsx
3234
+ import { jsx as jsx11 } from "react/jsx-runtime";
3235
+ var AnalyticsContext = createContext3(null);
3236
+ var noopDepositEmitter = () => {
3237
+ };
3238
+ var noopWithdrawEmitter = () => {
3239
+ };
3240
+ var noopClaimEmitter = () => {
3241
+ };
3242
+ function cloneAndFreeze(value) {
3243
+ if (Array.isArray(value)) {
3244
+ return Object.freeze(value.map(cloneAndFreeze));
3245
+ }
3246
+ if (value && typeof value === "object") {
3247
+ const clone = Object.fromEntries(
3248
+ Object.entries(value).map(([key, child]) => [key, cloneAndFreeze(child)])
3249
+ );
3250
+ return Object.freeze(clone);
3251
+ }
3252
+ return value;
3253
+ }
3254
+ function AnalyticsSession(props) {
3255
+ const sessionIdRef = useRef3(void 0);
3256
+ if (sessionIdRef.current === void 0) {
3257
+ sessionIdRef.current = (props.createSessionId ?? randomUuid)();
3258
+ }
3259
+ const sessionPropertiesRef = useRef3(void 0);
3260
+ if (sessionPropertiesRef.current === void 0) {
3261
+ sessionPropertiesRef.current = cloneAndFreeze(props.sessionProperties);
3262
+ }
3263
+ const onEventRef = useRef3(props.onEvent);
3264
+ onEventRef.current = props.onEvent;
3265
+ const nowRef = useRef3(props.now ?? (() => /* @__PURE__ */ new Date()));
3266
+ nowRef.current = props.now ?? (() => /* @__PURE__ */ new Date());
3267
+ const modal = props.modal;
3268
+ const reportedFailuresRef = useRef3(/* @__PURE__ */ new Set());
3269
+ const emitFailure = useCallback2(
3270
+ ({ reason, status, droppedEvents }) => {
3271
+ if (reportedFailuresRef.current.has(reason)) return;
3272
+ reportedFailuresRef.current.add(reason);
3273
+ const event = {
3274
+ type: "analytics_ingest_failure",
3275
+ session_id: sessionIdRef.current,
3276
+ modal,
3277
+ widget_version: MODAL_VERSION,
3278
+ timestamp: nowRef.current().toISOString(),
3279
+ reason,
3280
+ ...status === void 0 ? {} : { status },
3281
+ dropped_events: droppedEvents
3282
+ };
3283
+ onEventRef.current?.(event);
3284
+ },
3285
+ [modal]
3286
+ );
3287
+ function createIngest() {
3288
+ if (props.enableIngest === false) {
3289
+ return { transport: null, initialFailure: null };
3290
+ }
3291
+ const proxyOrigin = resolveProxyOrigin(props.backendUrl ?? "");
3292
+ if (!proxyOrigin || typeof globalThis.fetch !== "function") {
3293
+ return {
3294
+ transport: null,
3295
+ initialFailure: { reason: "unsupported", droppedEvents: 0 }
3296
+ };
3297
+ }
3298
+ return {
3299
+ transport: createIngestTransport({
3300
+ ingestUrl: props.ingestUrl ?? DEFAULT_ANALYTICS_INGEST_URL,
3301
+ backendUrl: props.backendUrl,
3302
+ proxyOrigin,
3303
+ sessionId: sessionIdRef.current,
3304
+ modal,
3305
+ widgetVersion: MODAL_VERSION,
3306
+ sessionProperties: sessionPropertiesRef.current,
3307
+ onFailure: (failure) => emitFailure(failure),
3308
+ fetchImpl: props.fetchImpl,
3309
+ createEventId: props.createEventId
3310
+ }),
3311
+ initialFailure: null
3312
+ };
3313
+ }
3314
+ const ingestRef = useRef3(void 0);
3315
+ if (ingestRef.current === void 0) {
3316
+ ingestRef.current = createIngest();
3317
+ }
3318
+ const pendingDisposalRef = useRef3(null);
3319
+ const enqueue = useCallback2(
3320
+ (event) => {
3321
+ try {
3322
+ ingestRef.current?.transport?.enqueue(
3323
+ event
3324
+ );
3325
+ } catch {
3326
+ }
3327
+ },
3328
+ []
3329
+ );
3330
+ useEffect4(() => {
3331
+ if (pendingDisposalRef.current !== null) {
3332
+ clearTimeout(pendingDisposalRef.current);
3333
+ pendingDisposalRef.current = null;
3334
+ }
3335
+ const setup = ingestRef.current;
3336
+ if (setup.initialFailure) emitFailure(setup.initialFailure);
3337
+ const transport = setup.transport;
3338
+ if (!transport) return;
3339
+ const flush = () => transport.flush({ terminal: true });
3340
+ const onVisibilityChange = () => {
3341
+ if (document.visibilityState === "hidden") flush();
3342
+ };
3343
+ window.addEventListener("pagehide", flush);
3344
+ document.addEventListener("visibilitychange", onVisibilityChange);
3345
+ return () => {
3346
+ window.removeEventListener("pagehide", flush);
3347
+ document.removeEventListener("visibilitychange", onVisibilityChange);
3348
+ pendingDisposalRef.current = setTimeout(() => {
3349
+ pendingDisposalRef.current = null;
3350
+ transport.dispose();
3351
+ }, 0);
3352
+ };
3353
+ }, [emitFailure]);
3354
+ const emitDeposit = useCallback2(
3355
+ (...[payload, fundingMethod]) => {
3356
+ if (modal !== "deposit") return;
3357
+ const event = {
3358
+ ...payload,
3359
+ session_id: sessionIdRef.current,
3360
+ modal,
3361
+ widget_version: MODAL_VERSION,
3362
+ timestamp: nowRef.current().toISOString(),
3363
+ session_properties: sessionPropertiesRef.current,
3364
+ funding_method: fundingMethod
3365
+ };
3366
+ onEventRef.current?.(
3367
+ event
3368
+ );
3369
+ enqueue(event);
3370
+ },
3371
+ [enqueue, modal, nowRef, onEventRef]
3372
+ );
3373
+ const emitWithdraw = useCallback2(
3374
+ (payload) => {
3375
+ if (modal !== "withdraw") return;
3376
+ const event = {
3377
+ ...payload,
3378
+ session_id: sessionIdRef.current,
3379
+ modal,
3380
+ widget_version: MODAL_VERSION,
3381
+ timestamp: nowRef.current().toISOString(),
3382
+ session_properties: sessionPropertiesRef.current
3383
+ };
3384
+ onEventRef.current?.(event);
3385
+ enqueue(event);
3386
+ },
3387
+ [enqueue, modal, nowRef, onEventRef]
3388
+ );
3389
+ const emitClaim = useCallback2(
3390
+ (payload) => {
3391
+ if (modal !== "claim") return;
3392
+ const event = {
3393
+ ...payload,
3394
+ session_id: sessionIdRef.current,
3395
+ modal,
3396
+ widget_version: MODAL_VERSION,
3397
+ timestamp: nowRef.current().toISOString(),
3398
+ session_properties: sessionPropertiesRef.current
3399
+ };
3400
+ onEventRef.current?.(event);
3401
+ enqueue(event);
3402
+ },
3403
+ [enqueue, modal, nowRef, onEventRef]
3404
+ );
3405
+ const context = useMemo3(
3406
+ () => modal === "deposit" ? { modal, emit: emitDeposit } : modal === "withdraw" ? { modal, emit: emitWithdraw } : { modal, emit: emitClaim },
3407
+ [modal, emitDeposit, emitWithdraw, emitClaim]
3408
+ );
3409
+ return /* @__PURE__ */ jsx11(AnalyticsContext.Provider, { value: context, children: props.children });
3410
+ }
3411
+ function useDepositAnalyticsEmitter() {
3412
+ const context = useContext3(AnalyticsContext);
3413
+ if (!context || context.modal !== "deposit") return noopDepositEmitter;
3414
+ return context.emit;
3415
+ }
3416
+ function useWithdrawAnalyticsEmitter() {
3417
+ const context = useContext3(AnalyticsContext);
3418
+ if (!context || context.modal !== "withdraw") return noopWithdrawEmitter;
3419
+ return context.emit;
3420
+ }
3421
+ function useClaimAnalyticsEmitter() {
3422
+ const context = useContext3(AnalyticsContext);
3423
+ if (!context || context.modal !== "claim") return noopClaimEmitter;
3424
+ return context.emit;
3425
+ }
3426
+
2878
3427
  // src/core/theme.ts
2879
3428
  var RADIUS_SCALE = {
2880
3429
  none: { sm: "0", md: "0", lg: "0" },
@@ -3139,6 +3688,10 @@ export {
3139
3688
  estimateReceiveAmount,
3140
3689
  formatQuotedReceive,
3141
3690
  formatReceiveEstimate,
3691
+ AnalyticsSession,
3692
+ useDepositAnalyticsEmitter,
3693
+ useWithdrawAnalyticsEmitter,
3694
+ useClaimAnalyticsEmitter,
3142
3695
  resolveThemeMode,
3143
3696
  followSystemAppearance,
3144
3697
  applyTheme,
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  debugError,
3
3
  debugLog
4
- } from "./chunk-EOMT5LKX.mjs";
4
+ } from "./chunk-UX35GYLM.mjs";
5
5
  import {
6
6
  serviceHeaders
7
- } from "./chunk-FZ5FZFIG.mjs";
7
+ } from "./chunk-LMG46EP2.mjs";
8
8
 
9
9
  // src/core/recovery.ts
10
10
  var RECOVER_DOMAIN = {
@@ -18,12 +18,13 @@ var RECOVER_TYPES = {
18
18
  ]
19
19
  };
20
20
  var RecoveryError = class extends Error {
21
- constructor(message, status, code, retryable = false) {
21
+ constructor(message, status, code, retryable = false, phase = "response") {
22
22
  super(message);
23
23
  this.name = "RecoveryError";
24
24
  this.status = status;
25
25
  this.code = code;
26
26
  this.retryable = retryable;
27
+ this.phase = phase;
27
28
  }
28
29
  };
29
30
  function formatRecoveryError(status, code, serverMessage) {
@@ -95,7 +96,8 @@ async function submitSignedRecovery(params) {
95
96
  "Signature request was declined. Approve it in your wallet to recover this deposit.",
96
97
  0,
97
98
  void 0,
98
- true
99
+ true,
100
+ "signature"
99
101
  );
100
102
  }
101
103
  if (!signature) {
@@ -103,7 +105,8 @@ async function submitSignedRecovery(params) {
103
105
  "Signature request was declined. Approve it in your wallet to recover this deposit.",
104
106
  0,
105
107
  void 0,
106
- true
108
+ true,
109
+ "signature"
107
110
  );
108
111
  }
109
112
  const url = `${backendUrl.replace(/\/$/, "")}/deposits/recover`;
@@ -127,7 +130,7 @@ async function submitSignedRecovery(params) {
127
130
  } catch (error) {
128
131
  debugError(debug, scope, "submitSignedRecovery:network", error);
129
132
  const { message, retryable } = formatRecoveryError(0);
130
- throw new RecoveryError(message, 0, void 0, retryable);
133
+ throw new RecoveryError(message, 0, void 0, retryable, "request");
131
134
  }
132
135
  if (!response.ok) {
133
136
  const body = await response.json().catch(() => ({}));
@@ -139,7 +142,13 @@ async function submitSignedRecovery(params) {
139
142
  body.code,
140
143
  body.error
141
144
  );
142
- throw new RecoveryError(message, response.status, body.code, retryable);
145
+ throw new RecoveryError(
146
+ message,
147
+ response.status,
148
+ body.code,
149
+ retryable,
150
+ "response"
151
+ );
143
152
  }
144
153
  const result = await response.json();
145
154
  debugLog(debug, scope, "submitSignedRecovery:success", {