@solvapay/react 1.0.0-preview.17 → 1.0.0-preview.19

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/index.js CHANGED
@@ -15,8 +15,7 @@ function getActiveSubscriptions(subscriptions) {
15
15
  function getCancelledSubscriptionsWithEndDate(subscriptions) {
16
16
  const now = /* @__PURE__ */ new Date();
17
17
  return subscriptions.filter((sub) => {
18
- const subAny = sub;
19
- return sub.status === "active" && subAny.cancelledAt && subAny.endDate && new Date(subAny.endDate) > now;
18
+ return sub.status === "active" && sub.cancelledAt && sub.endDate && new Date(sub.endDate) > now;
20
19
  });
21
20
  }
22
21
  function getMostRecentSubscription(subscriptions) {
@@ -114,7 +113,9 @@ var SolvaPayProvider = ({
114
113
  const createPaymentRef = useRef(null);
115
114
  const processPaymentRef = useRef(null);
116
115
  const configRef = useRef(config);
117
- const buildDefaultCheckSubscriptionRef = useRef(null);
116
+ const buildDefaultCheckSubscriptionRef = useRef(
117
+ null
118
+ );
118
119
  useEffect(() => {
119
120
  configRef.current = config;
120
121
  }, [config]);
@@ -162,77 +163,83 @@ var SolvaPayProvider = ({
162
163
  useEffect(() => {
163
164
  buildDefaultCheckSubscriptionRef.current = buildDefaultCheckSubscription;
164
165
  }, [buildDefaultCheckSubscription]);
165
- const buildDefaultCreatePayment = useCallback(async (params) => {
166
- const currentConfig = configRef.current;
167
- const adapter = getAuthAdapter(currentConfig);
168
- const token = await adapter.getToken();
169
- const detectedUserId = await adapter.getUserId();
170
- const route = currentConfig?.api?.createPayment || "/api/create-payment-intent";
171
- const fetchFn = currentConfig?.fetch || fetch;
172
- const cachedRef = getCachedCustomerRef(detectedUserId);
173
- const headers = {
174
- "Content-Type": "application/json"
175
- };
176
- if (token) {
177
- headers["Authorization"] = `Bearer ${token}`;
178
- }
179
- if (cachedRef) {
180
- headers["x-solvapay-customer-ref"] = cachedRef;
181
- }
182
- if (currentConfig?.headers) {
183
- const customHeaders = typeof currentConfig.headers === "function" ? await currentConfig.headers() : currentConfig.headers;
184
- Object.assign(headers, customHeaders);
185
- }
186
- const body = { planRef: params.planRef };
187
- if (params.agentRef) {
188
- body.agentRef = params.agentRef;
189
- }
190
- const res = await fetchFn(route, {
191
- method: "POST",
192
- headers,
193
- body: JSON.stringify(body)
194
- });
195
- if (!res.ok) {
196
- const error = new Error(`Failed to create payment: ${res.statusText}`);
197
- currentConfig?.onError?.(error, "createPayment");
198
- throw error;
199
- }
200
- return res.json();
201
- }, []);
202
- const buildDefaultProcessPayment = useCallback(async (params) => {
203
- const currentConfig = configRef.current;
204
- const adapter = getAuthAdapter(currentConfig);
205
- const token = await adapter.getToken();
206
- const detectedUserId = await adapter.getUserId();
207
- const route = currentConfig?.api?.processPayment || "/api/process-payment";
208
- const fetchFn = currentConfig?.fetch || fetch;
209
- const cachedRef = getCachedCustomerRef(detectedUserId);
210
- const headers = {
211
- "Content-Type": "application/json"
212
- };
213
- if (token) {
214
- headers["Authorization"] = `Bearer ${token}`;
215
- }
216
- if (cachedRef) {
217
- headers["x-solvapay-customer-ref"] = cachedRef;
218
- }
219
- if (currentConfig?.headers) {
220
- const customHeaders = typeof currentConfig.headers === "function" ? await currentConfig.headers() : currentConfig.headers;
221
- Object.assign(headers, customHeaders);
222
- }
223
- const res = await fetchFn(route, {
224
- method: "POST",
225
- headers,
226
- body: JSON.stringify(params)
227
- });
228
- if (!res.ok) {
229
- const error = new Error(`Failed to process payment: ${res.statusText}`);
230
- currentConfig?.onError?.(error, "processPayment");
231
- throw error;
232
- }
233
- return res.json();
234
- }, []);
235
- const checkSubscription = useCallback(async () => {
166
+ const buildDefaultCreatePayment = useCallback(
167
+ async (params) => {
168
+ const currentConfig = configRef.current;
169
+ const adapter = getAuthAdapter(currentConfig);
170
+ const token = await adapter.getToken();
171
+ const detectedUserId = await adapter.getUserId();
172
+ const route = currentConfig?.api?.createPayment || "/api/create-payment-intent";
173
+ const fetchFn = currentConfig?.fetch || fetch;
174
+ const cachedRef = getCachedCustomerRef(detectedUserId);
175
+ const headers = {
176
+ "Content-Type": "application/json"
177
+ };
178
+ if (token) {
179
+ headers["Authorization"] = `Bearer ${token}`;
180
+ }
181
+ if (cachedRef) {
182
+ headers["x-solvapay-customer-ref"] = cachedRef;
183
+ }
184
+ if (currentConfig?.headers) {
185
+ const customHeaders = typeof currentConfig.headers === "function" ? await currentConfig.headers() : currentConfig.headers;
186
+ Object.assign(headers, customHeaders);
187
+ }
188
+ const body = { planRef: params.planRef };
189
+ if (params.agentRef) {
190
+ body.agentRef = params.agentRef;
191
+ }
192
+ const res = await fetchFn(route, {
193
+ method: "POST",
194
+ headers,
195
+ body: JSON.stringify(body)
196
+ });
197
+ if (!res.ok) {
198
+ const error = new Error(`Failed to create payment: ${res.statusText}`);
199
+ currentConfig?.onError?.(error, "createPayment");
200
+ throw error;
201
+ }
202
+ return res.json();
203
+ },
204
+ []
205
+ );
206
+ const buildDefaultProcessPayment = useCallback(
207
+ async (params) => {
208
+ const currentConfig = configRef.current;
209
+ const adapter = getAuthAdapter(currentConfig);
210
+ const token = await adapter.getToken();
211
+ const detectedUserId = await adapter.getUserId();
212
+ const route = currentConfig?.api?.processPayment || "/api/process-payment";
213
+ const fetchFn = currentConfig?.fetch || fetch;
214
+ const cachedRef = getCachedCustomerRef(detectedUserId);
215
+ const headers = {
216
+ "Content-Type": "application/json"
217
+ };
218
+ if (token) {
219
+ headers["Authorization"] = `Bearer ${token}`;
220
+ }
221
+ if (cachedRef) {
222
+ headers["x-solvapay-customer-ref"] = cachedRef;
223
+ }
224
+ if (currentConfig?.headers) {
225
+ const customHeaders = typeof currentConfig.headers === "function" ? await currentConfig.headers() : currentConfig.headers;
226
+ Object.assign(headers, customHeaders);
227
+ }
228
+ const res = await fetchFn(route, {
229
+ method: "POST",
230
+ headers,
231
+ body: JSON.stringify(params)
232
+ });
233
+ if (!res.ok) {
234
+ const error = new Error(`Failed to process payment: ${res.statusText}`);
235
+ currentConfig?.onError?.(error, "processPayment");
236
+ throw error;
237
+ }
238
+ return res.json();
239
+ },
240
+ []
241
+ );
242
+ const _checkSubscription = useCallback(async () => {
236
243
  if (checkSubscriptionRef.current) {
237
244
  return checkSubscriptionRef.current();
238
245
  }
@@ -240,19 +247,25 @@ var SolvaPayProvider = ({
240
247
  return buildDefaultCheckSubscriptionRef.current();
241
248
  }
242
249
  return buildDefaultCheckSubscription();
243
- }, []);
244
- const createPayment = useCallback(async (params) => {
245
- if (createPaymentRef.current) {
246
- return createPaymentRef.current(params);
247
- }
248
- return buildDefaultCreatePayment(params);
249
- }, [buildDefaultCreatePayment]);
250
- const processPayment = useCallback(async (params) => {
251
- if (processPaymentRef.current) {
252
- return processPaymentRef.current(params);
253
- }
254
- return buildDefaultProcessPayment(params);
255
- }, [buildDefaultProcessPayment]);
250
+ }, [buildDefaultCheckSubscription]);
251
+ const createPayment = useCallback(
252
+ async (params) => {
253
+ if (createPaymentRef.current) {
254
+ return createPaymentRef.current(params);
255
+ }
256
+ return buildDefaultCreatePayment(params);
257
+ },
258
+ [buildDefaultCreatePayment]
259
+ );
260
+ const processPayment = useCallback(
261
+ async (params) => {
262
+ if (processPaymentRef.current) {
263
+ return processPaymentRef.current(params);
264
+ }
265
+ return buildDefaultProcessPayment(params);
266
+ },
267
+ [buildDefaultProcessPayment]
268
+ );
256
269
  useEffect(() => {
257
270
  const detectAuth = async () => {
258
271
  const currentConfig = configRef.current;
@@ -281,58 +294,61 @@ var SolvaPayProvider = ({
281
294
  const interval = setInterval(detectAuth, 5e3);
282
295
  return () => clearInterval(interval);
283
296
  }, [userId]);
284
- const fetchSubscription = useCallback(async (force = false) => {
285
- if (!isAuthenticated && !internalCustomerRef) {
286
- setSubscriptionData({ subscriptions: [] });
287
- setLoading(false);
288
- inFlightRef.current = null;
289
- lastFetchedRef.current = null;
290
- return;
291
- }
292
- const cacheKey = internalCustomerRef || userId || "anonymous";
293
- if (!force && lastFetchedRef.current === cacheKey && inFlightRef.current !== cacheKey) {
294
- return;
295
- }
296
- if (inFlightRef.current === cacheKey) {
297
- return;
298
- }
299
- inFlightRef.current = cacheKey;
300
- setLoading(true);
301
- try {
302
- const checkFn = checkSubscriptionRef.current || buildDefaultCheckSubscriptionRef.current;
303
- if (!checkFn) {
304
- throw new Error("checkSubscription function not available");
305
- }
306
- const data = await checkFn();
307
- if (data.customerRef) {
308
- setInternalCustomerRef(data.customerRef);
309
- const currentAdapter = getAuthAdapter(configRef.current);
310
- const currentUserId = await currentAdapter.getUserId();
311
- setCachedCustomerRef(data.customerRef, currentUserId);
297
+ const fetchSubscription = useCallback(
298
+ async (force = false) => {
299
+ if (!isAuthenticated && !internalCustomerRef) {
300
+ setSubscriptionData({ subscriptions: [] });
301
+ setLoading(false);
302
+ inFlightRef.current = null;
303
+ lastFetchedRef.current = null;
304
+ return;
312
305
  }
313
- if (inFlightRef.current === cacheKey) {
314
- const filteredData = {
315
- ...data,
316
- subscriptions: filterSubscriptions(data.subscriptions || [])
317
- };
318
- setSubscriptionData(filteredData);
319
- lastFetchedRef.current = cacheKey;
306
+ const cacheKey = internalCustomerRef || userId || "anonymous";
307
+ if (!force && lastFetchedRef.current === cacheKey && inFlightRef.current !== cacheKey) {
308
+ return;
320
309
  }
321
- } catch (error) {
322
- console.error("[SolvaPayProvider] Failed to fetch subscription:", error);
323
310
  if (inFlightRef.current === cacheKey) {
324
- setSubscriptionData({
325
- subscriptions: []
326
- });
327
- lastFetchedRef.current = cacheKey;
311
+ return;
328
312
  }
329
- } finally {
330
- if (inFlightRef.current === cacheKey) {
331
- setLoading(false);
332
- inFlightRef.current = null;
313
+ inFlightRef.current = cacheKey;
314
+ setLoading(true);
315
+ try {
316
+ const checkFn = checkSubscriptionRef.current || buildDefaultCheckSubscriptionRef.current;
317
+ if (!checkFn) {
318
+ throw new Error("checkSubscription function not available");
319
+ }
320
+ const data = await checkFn();
321
+ if (data.customerRef) {
322
+ setInternalCustomerRef(data.customerRef);
323
+ const currentAdapter = getAuthAdapter(configRef.current);
324
+ const currentUserId = await currentAdapter.getUserId();
325
+ setCachedCustomerRef(data.customerRef, currentUserId);
326
+ }
327
+ if (inFlightRef.current === cacheKey) {
328
+ const filteredData = {
329
+ ...data,
330
+ subscriptions: filterSubscriptions(data.subscriptions || [])
331
+ };
332
+ setSubscriptionData(filteredData);
333
+ lastFetchedRef.current = cacheKey;
334
+ }
335
+ } catch (error) {
336
+ console.error("[SolvaPayProvider] Failed to fetch subscription:", error);
337
+ if (inFlightRef.current === cacheKey) {
338
+ setSubscriptionData({
339
+ subscriptions: []
340
+ });
341
+ lastFetchedRef.current = cacheKey;
342
+ }
343
+ } finally {
344
+ if (inFlightRef.current === cacheKey) {
345
+ setLoading(false);
346
+ inFlightRef.current = null;
347
+ }
333
348
  }
334
- }
335
- }, [isAuthenticated, internalCustomerRef, userId]);
349
+ },
350
+ [isAuthenticated, internalCustomerRef, userId]
351
+ );
336
352
  const fetchSubscriptionRef = useRef(fetchSubscription);
337
353
  useEffect(() => {
338
354
  fetchSubscriptionRef.current = fetchSubscription;
@@ -353,17 +369,22 @@ var SolvaPayProvider = ({
353
369
  setLoading(false);
354
370
  }
355
371
  }, [isAuthenticated, internalCustomerRef, userId]);
356
- const updateCustomerRef = useCallback((newCustomerRef) => {
357
- setInternalCustomerRef(newCustomerRef);
358
- setCachedCustomerRef(newCustomerRef, userId);
359
- fetchSubscription(true);
360
- }, [fetchSubscription, userId]);
372
+ const updateCustomerRef = useCallback(
373
+ (newCustomerRef) => {
374
+ setInternalCustomerRef(newCustomerRef);
375
+ setCachedCustomerRef(newCustomerRef, userId);
376
+ fetchSubscription(true);
377
+ },
378
+ [fetchSubscription, userId]
379
+ );
361
380
  const subscription = useMemo(() => {
362
381
  const activeSubscription = getPrimarySubscription(subscriptionData.subscriptions);
363
382
  const activePaidSubscriptions = subscriptionData.subscriptions.filter(
364
383
  (sub) => sub.status === "active" && isPaidSubscription(sub)
365
384
  );
366
- const activePaidSubscription = activePaidSubscriptions.sort((a, b) => new Date(b.startDate).getTime() - new Date(a.startDate).getTime())[0] || null;
385
+ const activePaidSubscription = activePaidSubscriptions.sort(
386
+ (a, b) => new Date(b.startDate).getTime() - new Date(a.startDate).getTime()
387
+ )[0] || null;
367
388
  return {
368
389
  loading,
369
390
  customerRef: subscriptionData.customerRef || internalCustomerRef,
@@ -380,14 +401,25 @@ var SolvaPayProvider = ({
380
401
  activePaidSubscription
381
402
  };
382
403
  }, [loading, subscriptionData, internalCustomerRef]);
383
- const contextValue = useMemo(() => ({
384
- subscription,
385
- refetchSubscription,
386
- createPayment,
387
- processPayment,
388
- customerRef: subscriptionData.customerRef || internalCustomerRef,
389
- updateCustomerRef
390
- }), [subscription, refetchSubscription, createPayment, processPayment, subscriptionData.customerRef, internalCustomerRef, updateCustomerRef]);
404
+ const contextValue = useMemo(
405
+ () => ({
406
+ subscription,
407
+ refetchSubscription,
408
+ createPayment,
409
+ processPayment,
410
+ customerRef: subscriptionData.customerRef || internalCustomerRef,
411
+ updateCustomerRef
412
+ }),
413
+ [
414
+ subscription,
415
+ refetchSubscription,
416
+ createPayment,
417
+ processPayment,
418
+ subscriptionData.customerRef,
419
+ internalCustomerRef,
420
+ updateCustomerRef
421
+ ]
422
+ );
391
423
  return /* @__PURE__ */ jsx(SolvaPayContext.Provider, { value: contextValue, children });
392
424
  };
393
425
 
@@ -493,17 +525,6 @@ function useSubscription() {
493
525
  };
494
526
  }
495
527
 
496
- // src/hooks/useCustomer.ts
497
- function useCustomer() {
498
- const { subscription, customerRef } = useSolvaPay();
499
- return {
500
- customerRef: subscription.customerRef || customerRef,
501
- email: subscription.email,
502
- name: subscription.name,
503
- loading: subscription.loading
504
- };
505
- }
506
-
507
528
  // src/components/Spinner.tsx
508
529
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
509
530
  var Spinner = ({
@@ -525,17 +546,7 @@ var Spinner = ({
525
546
  role: "status",
526
547
  "aria-busy": "true",
527
548
  children: [
528
- /* @__PURE__ */ jsx2(
529
- "circle",
530
- {
531
- className: "opacity-25",
532
- cx: "12",
533
- cy: "12",
534
- r: "10",
535
- stroke: "currentColor",
536
- strokeWidth: "4"
537
- }
538
- ),
549
+ /* @__PURE__ */ jsx2("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
539
550
  /* @__PURE__ */ jsx2(
540
551
  "path",
541
552
  {
@@ -552,11 +563,24 @@ var Spinner = ({
552
563
  // src/components/StripePaymentFormWrapper.tsx
553
564
  import { useState as useState3 } from "react";
554
565
  import { useStripe, useElements, CardElement } from "@stripe/react-stripe-js";
566
+
567
+ // src/hooks/useCustomer.ts
568
+ function useCustomer() {
569
+ const { subscription, customerRef } = useSolvaPay();
570
+ return {
571
+ customerRef: subscription.customerRef || customerRef,
572
+ email: subscription.email,
573
+ name: subscription.name,
574
+ loading: subscription.loading
575
+ };
576
+ }
577
+
578
+ // src/components/StripePaymentFormWrapper.tsx
555
579
  import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
556
580
  var StripePaymentFormWrapper = ({
557
581
  onSuccess,
558
582
  onError,
559
- returnUrl,
583
+ returnUrl: _returnUrl,
560
584
  submitButtonText = "Pay Now",
561
585
  buttonClassName,
562
586
  clientSecret
@@ -681,16 +705,23 @@ var StripePaymentFormWrapper = ({
681
705
  }
682
706
  }
683
707
  }
684
- ) : /* @__PURE__ */ jsx3("div", { style: { padding: "12px", border: "1px solid #cbd5e1", borderRadius: "0.375rem", backgroundColor: "white", display: "flex", alignItems: "center", justifyContent: "center", minHeight: "40px" }, children: /* @__PURE__ */ jsx3(Spinner, { size: "sm" }) }),
685
- message && !isSuccess && /* @__PURE__ */ jsx3(
708
+ ) : /* @__PURE__ */ jsx3(
686
709
  "div",
687
710
  {
688
- role: "alert",
689
- "aria-live": "assertive",
690
- "aria-atomic": "true",
691
- children: message
711
+ style: {
712
+ padding: "12px",
713
+ border: "1px solid #cbd5e1",
714
+ borderRadius: "0.375rem",
715
+ backgroundColor: "white",
716
+ display: "flex",
717
+ alignItems: "center",
718
+ justifyContent: "center",
719
+ minHeight: "40px"
720
+ },
721
+ children: /* @__PURE__ */ jsx3(Spinner, { size: "sm" })
692
722
  }
693
723
  ),
724
+ message && !isSuccess && /* @__PURE__ */ jsx3("div", { role: "alert", "aria-live": "assertive", "aria-atomic": "true", children: message }),
694
725
  /* @__PURE__ */ jsx3(
695
726
  "button",
696
727
  {
@@ -722,106 +753,118 @@ var PaymentForm = ({
722
753
  buttonClassName
723
754
  }) => {
724
755
  const validPlanRef = planRef && typeof planRef === "string" ? planRef : "";
725
- const checkout = useCheckout(validPlanRef, agentRef);
756
+ const {
757
+ loading: checkoutLoading,
758
+ error: checkoutError,
759
+ clientSecret,
760
+ startCheckout,
761
+ stripePromise
762
+ } = useCheckout(validPlanRef, agentRef);
726
763
  const { refetch } = useSubscription();
727
- const { processPayment, customerRef } = useSolvaPay();
728
- const customer = useCustomer();
764
+ const { processPayment } = useSolvaPay();
729
765
  const hasInitializedRef = useRef3(false);
730
766
  useEffect2(() => {
731
- if (!hasInitializedRef.current && validPlanRef && !checkout.loading && !checkout.error && !checkout.clientSecret) {
767
+ if (!hasInitializedRef.current && validPlanRef && !checkoutLoading && !checkoutError && !clientSecret) {
732
768
  hasInitializedRef.current = true;
733
- checkout.startCheckout().catch(() => {
769
+ startCheckout().catch(() => {
734
770
  hasInitializedRef.current = false;
735
771
  });
736
772
  }
737
- if (validPlanRef && checkout.clientSecret) {
773
+ if (validPlanRef && clientSecret) {
738
774
  hasInitializedRef.current = true;
739
775
  }
740
- }, [validPlanRef, checkout.loading, checkout.error, checkout.clientSecret, checkout.startCheckout]);
741
- const handleSuccess = useCallback3(async (paymentIntent) => {
742
- let processingTimeout = false;
743
- let processingResult = null;
744
- if (processPayment && agentRef) {
745
- try {
746
- const result = await processPayment({
747
- paymentIntentId: paymentIntent.id,
748
- agentRef,
749
- planRef
750
- });
751
- processingResult = result;
752
- const isTimeout = result?.status === "timeout";
753
- processingTimeout = isTimeout;
754
- if (isTimeout) {
755
- for (let attempt = 1; attempt <= 5; attempt++) {
756
- const delay = attempt * 1e3;
757
- await new Promise((resolve) => setTimeout(resolve, delay));
776
+ }, [validPlanRef, checkoutLoading, checkoutError, clientSecret, startCheckout]);
777
+ const handleSuccess = useCallback3(
778
+ async (paymentIntent) => {
779
+ let processingTimeout = false;
780
+ let processingResult = null;
781
+ const paymentIntentAny = paymentIntent;
782
+ if (processPayment && agentRef) {
783
+ try {
784
+ const result = await processPayment({
785
+ paymentIntentId: paymentIntentAny.id,
786
+ agentRef,
787
+ planRef
788
+ });
789
+ processingResult = result;
790
+ const isTimeout = result?.status === "timeout";
791
+ processingTimeout = isTimeout;
792
+ if (isTimeout) {
793
+ for (let attempt = 1; attempt <= 5; attempt++) {
794
+ const delay = attempt * 1e3;
795
+ await new Promise((resolve) => setTimeout(resolve, delay));
796
+ await refetch();
797
+ }
798
+ if (onSuccess) {
799
+ await onSuccess({
800
+ ...paymentIntentAny,
801
+ _processingTimeout: processingTimeout,
802
+ _processingResult: processingResult
803
+ });
804
+ }
805
+ throw new Error("Payment processing timed out");
806
+ } else {
758
807
  await refetch();
759
808
  }
809
+ } catch (error) {
810
+ console.error("[PaymentForm] Failed to process payment:", error);
760
811
  if (onSuccess) {
761
- await onSuccess({
762
- ...paymentIntent,
763
- _processingTimeout: processingTimeout,
764
- _processingResult: processingResult
765
- });
766
- }
767
- throw new Error("Payment processing timed out");
768
- } else {
769
- await refetch();
770
- }
771
- } catch (error) {
772
- console.error("[PaymentForm] Failed to process payment:", error);
773
- if (onSuccess) {
774
- try {
775
- await onSuccess({
776
- ...paymentIntent,
777
- _processingError: error
778
- });
779
- } catch (callbackError) {
812
+ try {
813
+ await onSuccess({
814
+ ...paymentIntentAny,
815
+ _processingError: error
816
+ });
817
+ } catch {
818
+ }
780
819
  }
820
+ throw error;
781
821
  }
782
- throw error;
822
+ } else {
823
+ await refetch();
783
824
  }
784
- } else {
785
- await refetch();
786
- }
787
- if (onSuccess && !processingTimeout) {
788
- await onSuccess({
789
- ...paymentIntent,
790
- _processingTimeout: processingTimeout,
791
- _processingResult: processingResult
792
- });
793
- }
794
- }, [processPayment, agentRef, planRef, refetch, onSuccess]);
795
- const handleError = useCallback3((err) => {
796
- if (onError) {
797
- onError(err);
798
- }
799
- }, [onError]);
825
+ if (onSuccess && !processingTimeout) {
826
+ await onSuccess({
827
+ ...paymentIntentAny,
828
+ _processingTimeout: processingTimeout,
829
+ _processingResult: processingResult
830
+ });
831
+ }
832
+ },
833
+ [processPayment, agentRef, planRef, refetch, onSuccess]
834
+ );
835
+ const handleError = useCallback3(
836
+ (err) => {
837
+ if (onError) {
838
+ onError(err);
839
+ }
840
+ },
841
+ [onError]
842
+ );
800
843
  const finalReturnUrl = returnUrl || (typeof window !== "undefined" ? window.location.href : "/");
801
844
  const isValidPlanRef = planRef && typeof planRef === "string";
802
- const hasError = !!checkout.error;
803
- const hasStripeData = !!(checkout.stripePromise && checkout.clientSecret);
845
+ const hasError = !!checkoutError;
846
+ const hasStripeData = !!(stripePromise && clientSecret);
804
847
  const elementsOptions = useMemo2(() => {
805
- if (!checkout.clientSecret) return void 0;
806
- return { clientSecret: checkout.clientSecret };
807
- }, [checkout.clientSecret]);
848
+ if (!clientSecret) return void 0;
849
+ return { clientSecret };
850
+ }, [clientSecret]);
808
851
  const [hasMountedElements, setHasMountedElements] = useState4(false);
809
852
  useEffect2(() => {
810
853
  if (hasStripeData) {
811
854
  setHasMountedElements(true);
812
855
  }
813
856
  }, [hasStripeData]);
814
- const shouldRenderElements = hasStripeData || hasMountedElements && checkout.stripePromise && checkout.clientSecret;
857
+ const shouldRenderElements = hasStripeData || hasMountedElements && stripePromise && clientSecret;
815
858
  return /* @__PURE__ */ jsx4("div", { className, children: !isValidPlanRef ? /* @__PURE__ */ jsx4("div", { children: "PaymentForm: planRef is required and must be a string" }) : hasError ? /* @__PURE__ */ jsxs3("div", { children: [
816
859
  /* @__PURE__ */ jsx4("div", { children: "Payment initialization failed" }),
817
- /* @__PURE__ */ jsx4("div", { children: checkout.error?.message || "Unknown error" })
818
- ] }) : shouldRenderElements && checkout.stripePromise && elementsOptions ? (
860
+ /* @__PURE__ */ jsx4("div", { children: checkoutError?.message || "Unknown error" })
861
+ ] }) : shouldRenderElements && elementsOptions ? (
819
862
  // Once we have Stripe data, always render Elements to maintain hook consistency
820
863
  // This prevents hook count mismatches when transitioning between states
821
864
  /* @__PURE__ */ jsx4(
822
865
  Elements,
823
866
  {
824
- stripe: checkout.stripePromise,
867
+ stripe: stripePromise,
825
868
  options: elementsOptions,
826
869
  children: /* @__PURE__ */ jsx4(
827
870
  StripePaymentFormWrapper,
@@ -831,16 +874,27 @@ var PaymentForm = ({
831
874
  returnUrl: finalReturnUrl,
832
875
  submitButtonText,
833
876
  buttonClassName,
834
- clientSecret: checkout.clientSecret
877
+ clientSecret
835
878
  }
836
879
  )
837
880
  },
838
- checkout.clientSecret
881
+ clientSecret
839
882
  )
840
883
  ) : (
841
884
  // Loading state before Stripe data is available
842
885
  /* @__PURE__ */ jsxs3("div", { children: [
843
- /* @__PURE__ */ jsx4("div", { style: { minHeight: "40px", display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx4(Spinner, { size: "md" }) }),
886
+ /* @__PURE__ */ jsx4(
887
+ "div",
888
+ {
889
+ style: {
890
+ minHeight: "40px",
891
+ display: "flex",
892
+ alignItems: "center",
893
+ justifyContent: "center"
894
+ },
895
+ children: /* @__PURE__ */ jsx4(Spinner, { size: "md" })
896
+ }
897
+ ),
844
898
  /* @__PURE__ */ jsx4(
845
899
  "button",
846
900
  {
@@ -931,10 +985,7 @@ var PlanBadge = ({
931
985
 
932
986
  // src/components/SubscriptionGate.tsx
933
987
  import { Fragment as Fragment3, jsx as jsx6 } from "react/jsx-runtime";
934
- var SubscriptionGate = ({
935
- requirePlan,
936
- children
937
- }) => {
988
+ var SubscriptionGate = ({ requirePlan, children }) => {
938
989
  const { subscriptions, loading, hasPlan } = useSubscription();
939
990
  const hasAccess = requirePlan ? hasPlan(requirePlan) : subscriptions.some((sub) => sub.status === "active");
940
991
  return /* @__PURE__ */ jsx6(Fragment3, { children: children({
@@ -973,99 +1024,99 @@ function usePlans(options) {
973
1024
  useEffect4(() => {
974
1025
  autoSelectFirstPaidRef.current = autoSelectFirstPaid;
975
1026
  }, [autoSelectFirstPaid]);
976
- const fetchPlans = useCallback4(async (force = false) => {
977
- if (!agentRef) {
978
- setError(new Error("Agent reference not configured"));
979
- setLoading(false);
980
- return;
981
- }
982
- const cached = plansCache.get(agentRef);
983
- const now = Date.now();
984
- if (!force && cached && now - cached.timestamp < CACHE_DURATION2) {
985
- const cachedPlans = cached.plans;
986
- let processedPlans = filterRef.current ? cachedPlans.filter(filterRef.current) : cachedPlans;
987
- if (sortByRef.current) {
988
- processedPlans = [...processedPlans].sort(sortByRef.current);
1027
+ const fetchPlans = useCallback4(
1028
+ async (force = false) => {
1029
+ if (!agentRef) {
1030
+ setError(new Error("Agent reference not configured"));
1031
+ setLoading(false);
1032
+ return;
989
1033
  }
990
- setPlans(processedPlans);
991
- setLoading(false);
992
- setError(null);
993
- if (autoSelectFirstPaidRef.current && processedPlans.length > 0) {
994
- const firstPaidIndex = processedPlans.findIndex(
995
- (plan) => plan.price && plan.price > 0
996
- );
997
- setSelectedPlanIndex(firstPaidIndex >= 0 ? firstPaidIndex : 0);
1034
+ const cached = plansCache.get(agentRef);
1035
+ const now = Date.now();
1036
+ if (!force && cached && now - cached.timestamp < CACHE_DURATION2) {
1037
+ const cachedPlans = cached.plans;
1038
+ let processedPlans = filterRef.current ? cachedPlans.filter(filterRef.current) : cachedPlans;
1039
+ if (sortByRef.current) {
1040
+ processedPlans = [...processedPlans].sort(sortByRef.current);
1041
+ }
1042
+ setPlans(processedPlans);
1043
+ setLoading(false);
1044
+ setError(null);
1045
+ if (autoSelectFirstPaidRef.current && processedPlans.length > 0) {
1046
+ const firstPaidIndex = processedPlans.findIndex((plan) => plan.price && plan.price > 0);
1047
+ setSelectedPlanIndex(firstPaidIndex >= 0 ? firstPaidIndex : 0);
1048
+ }
1049
+ return;
1050
+ }
1051
+ if (cached?.promise) {
1052
+ try {
1053
+ setLoading(true);
1054
+ const fetchedPlans = await cached.promise;
1055
+ let processedPlans = filterRef.current ? fetchedPlans.filter(filterRef.current) : fetchedPlans;
1056
+ if (sortByRef.current) {
1057
+ processedPlans = [...processedPlans].sort(sortByRef.current);
1058
+ }
1059
+ setPlans(processedPlans);
1060
+ setError(null);
1061
+ if (autoSelectFirstPaidRef.current && processedPlans.length > 0) {
1062
+ const firstPaidIndex = processedPlans.findIndex((plan) => plan.price && plan.price > 0);
1063
+ setSelectedPlanIndex(firstPaidIndex >= 0 ? firstPaidIndex : 0);
1064
+ }
1065
+ } catch (err) {
1066
+ setError(err instanceof Error ? err : new Error("Failed to load plans"));
1067
+ } finally {
1068
+ setLoading(false);
1069
+ }
1070
+ return;
998
1071
  }
999
- return;
1000
- }
1001
- if (cached?.promise) {
1002
1072
  try {
1003
1073
  setLoading(true);
1004
- const fetchedPlans = await cached.promise;
1074
+ setError(null);
1075
+ const fetchPromise = fetcherRef.current(agentRef);
1076
+ plansCache.set(agentRef, {
1077
+ plans: [],
1078
+ timestamp: now,
1079
+ promise: fetchPromise
1080
+ });
1081
+ const fetchedPlans = await fetchPromise;
1082
+ plansCache.set(agentRef, {
1083
+ plans: fetchedPlans,
1084
+ timestamp: now,
1085
+ promise: null
1086
+ });
1005
1087
  let processedPlans = filterRef.current ? fetchedPlans.filter(filterRef.current) : fetchedPlans;
1006
1088
  if (sortByRef.current) {
1007
1089
  processedPlans = [...processedPlans].sort(sortByRef.current);
1008
1090
  }
1009
1091
  setPlans(processedPlans);
1010
- setError(null);
1011
1092
  if (autoSelectFirstPaidRef.current && processedPlans.length > 0) {
1012
- const firstPaidIndex = processedPlans.findIndex(
1013
- (plan) => plan.price && plan.price > 0
1014
- );
1093
+ const firstPaidIndex = processedPlans.findIndex((plan) => plan.price && plan.price > 0);
1015
1094
  setSelectedPlanIndex(firstPaidIndex >= 0 ? firstPaidIndex : 0);
1016
1095
  }
1017
1096
  } catch (err) {
1097
+ plansCache.delete(agentRef);
1018
1098
  setError(err instanceof Error ? err : new Error("Failed to load plans"));
1019
1099
  } finally {
1020
1100
  setLoading(false);
1021
1101
  }
1022
- return;
1023
- }
1024
- try {
1025
- setLoading(true);
1026
- setError(null);
1027
- const fetchPromise = fetcherRef.current(agentRef);
1028
- plansCache.set(agentRef, {
1029
- plans: [],
1030
- timestamp: now,
1031
- promise: fetchPromise
1032
- });
1033
- const fetchedPlans = await fetchPromise;
1034
- plansCache.set(agentRef, {
1035
- plans: fetchedPlans,
1036
- timestamp: now,
1037
- promise: null
1038
- });
1039
- let processedPlans = filterRef.current ? fetchedPlans.filter(filterRef.current) : fetchedPlans;
1040
- if (sortByRef.current) {
1041
- processedPlans = [...processedPlans].sort(sortByRef.current);
1042
- }
1043
- setPlans(processedPlans);
1044
- if (autoSelectFirstPaidRef.current && processedPlans.length > 0) {
1045
- const firstPaidIndex = processedPlans.findIndex(
1046
- (plan) => plan.price && plan.price > 0
1047
- );
1048
- setSelectedPlanIndex(firstPaidIndex >= 0 ? firstPaidIndex : 0);
1049
- }
1050
- } catch (err) {
1051
- plansCache.delete(agentRef);
1052
- setError(err instanceof Error ? err : new Error("Failed to load plans"));
1053
- } finally {
1054
- setLoading(false);
1055
- }
1056
- }, [agentRef]);
1102
+ },
1103
+ [agentRef]
1104
+ );
1057
1105
  useEffect4(() => {
1058
1106
  fetchPlans();
1059
1107
  }, [fetchPlans]);
1060
1108
  const selectedPlan = useMemo3(() => {
1061
1109
  return plans[selectedPlanIndex] || null;
1062
1110
  }, [plans, selectedPlanIndex]);
1063
- const selectPlan = useCallback4((planRef) => {
1064
- const index = plans.findIndex((p) => p.reference === planRef);
1065
- if (index >= 0) {
1066
- setSelectedPlanIndex(index);
1067
- }
1068
- }, [plans]);
1111
+ const selectPlan = useCallback4(
1112
+ (planRef) => {
1113
+ const index = plans.findIndex((p) => p.reference === planRef);
1114
+ if (index >= 0) {
1115
+ setSelectedPlanIndex(index);
1116
+ }
1117
+ },
1118
+ [plans]
1119
+ );
1069
1120
  return {
1070
1121
  plans,
1071
1122
  loading,
@@ -1098,19 +1149,25 @@ var PlanSelector = ({
1098
1149
  autoSelectFirstPaid
1099
1150
  });
1100
1151
  const { plans } = plansHook;
1101
- const isPaidPlan = useCallback5((planName) => {
1102
- const plan = plans.find((p) => p.name === planName);
1103
- return plan ? (plan.price ?? 0) > 0 && !plan.isFreeTier : true;
1104
- }, [plans]);
1152
+ const isPaidPlan = useCallback5(
1153
+ (planName) => {
1154
+ const plan = plans.find((p) => p.name === planName);
1155
+ return plan ? (plan.price ?? 0) > 0 && !plan.isFreeTier : true;
1156
+ },
1157
+ [plans]
1158
+ );
1105
1159
  const activeSubscription = useMemo4(() => {
1106
1160
  const activeSubs = subscriptions.filter((sub) => sub.status === "active");
1107
1161
  return activeSubs.sort(
1108
1162
  (a, b) => new Date(b.startDate).getTime() - new Date(a.startDate).getTime()
1109
1163
  )[0] || null;
1110
1164
  }, [subscriptions]);
1111
- const isCurrentPlan = useCallback5((planName) => {
1112
- return activeSubscription?.planName === planName;
1113
- }, [activeSubscription]);
1165
+ const isCurrentPlan = useCallback5(
1166
+ (planName) => {
1167
+ return activeSubscription?.planName === planName;
1168
+ },
1169
+ [activeSubscription]
1170
+ );
1114
1171
  return /* @__PURE__ */ jsx7(Fragment4, { children: children({
1115
1172
  ...plansHook,
1116
1173
  subscriptions,
@@ -1128,10 +1185,11 @@ function useSubscriptionStatus() {
1128
1185
  }, []);
1129
1186
  const subscriptionData = useMemo5(() => {
1130
1187
  const cancelledPaidSubscriptions = subscriptions.filter((sub) => {
1131
- const subAny = sub;
1132
- return sub.status === "active" && subAny.cancelledAt && isPaidSubscription2(sub);
1188
+ return sub.status === "active" && sub.cancelledAt && isPaidSubscription2(sub);
1133
1189
  });
1134
- const cancelledSubscription = cancelledPaidSubscriptions.sort((a, b) => new Date(b.startDate).getTime() - new Date(a.startDate).getTime())[0] || null;
1190
+ const cancelledSubscription = cancelledPaidSubscriptions.sort(
1191
+ (a, b) => new Date(b.startDate).getTime() - new Date(a.startDate).getTime()
1192
+ )[0] || null;
1135
1193
  const shouldShowCancelledNotice = !!cancelledSubscription;
1136
1194
  return {
1137
1195
  cancelledSubscription,