@solvapay/react 1.0.8-preview.6 → 1.0.8-preview.8

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 (106) hide show
  1. package/README.md +12 -95
  2. package/dist/CancelPlanButton-Bb7cvym9.d.cts +1105 -0
  3. package/dist/CancelPlanButton-CieT9swn.d.cts +1102 -0
  4. package/dist/CancelPlanButton-Cq117t7h.d.ts +1105 -0
  5. package/dist/CancelPlanButton-f56UlQN-.d.ts +1102 -0
  6. package/dist/PaymentForm-B5dw0i1X.d.ts +934 -0
  7. package/dist/PaymentForm-CesoRQWu.d.cts +934 -0
  8. package/dist/chunk-C7SKOENW.js +1889 -0
  9. package/dist/chunk-ISYAH4ZL.js +1889 -0
  10. package/dist/chunk-MOP3ZBGC.js +4749 -0
  11. package/dist/chunk-Q7GPX6X4.js +4748 -0
  12. package/dist/chunk-TP4JPKE2.js +3126 -0
  13. package/dist/chunk-VTGIXJQU.js +4755 -0
  14. package/dist/chunk-XMQ4GBWQ.js +4752 -0
  15. package/dist/index-DLl3UwO3.d.ts +798 -0
  16. package/dist/index-Sj2lHLl8.d.cts +798 -0
  17. package/dist/index.cjs +11 -25
  18. package/dist/index.d.cts +2 -2
  19. package/dist/index.d.ts +2 -2
  20. package/dist/index.js +1 -1
  21. package/dist/primitives/index.cjs +4 -21
  22. package/dist/primitives/index.d.cts +2 -2
  23. package/dist/primitives/index.d.ts +2 -2
  24. package/dist/primitives/index.js +1 -1
  25. package/dist/src/PaymentForm.d.ts +56 -0
  26. package/dist/src/PaymentForm.d.ts.map +1 -0
  27. package/dist/src/PaymentForm.js +212 -0
  28. package/dist/src/PaymentForm.js.map +1 -0
  29. package/dist/src/SolvaPayProvider.d.ts +84 -0
  30. package/dist/src/SolvaPayProvider.d.ts.map +1 -0
  31. package/dist/src/SolvaPayProvider.js +537 -0
  32. package/dist/src/SolvaPayProvider.js.map +1 -0
  33. package/dist/src/adapters/auth.d.ts +43 -0
  34. package/dist/src/adapters/auth.d.ts.map +1 -0
  35. package/dist/src/adapters/auth.js +38 -0
  36. package/dist/src/adapters/auth.js.map +1 -0
  37. package/dist/src/components/PlanBadge.d.ts +31 -0
  38. package/dist/src/components/PlanBadge.d.ts.map +1 -0
  39. package/dist/src/components/PlanBadge.js +119 -0
  40. package/dist/src/components/PlanBadge.js.map +1 -0
  41. package/dist/src/components/PlanSelector.d.ts +49 -0
  42. package/dist/src/components/PlanSelector.d.ts.map +1 -0
  43. package/dist/src/components/PlanSelector.js +82 -0
  44. package/dist/src/components/PlanSelector.js.map +1 -0
  45. package/dist/src/components/Spinner.d.ts +10 -0
  46. package/dist/src/components/Spinner.d.ts.map +1 -0
  47. package/dist/src/components/Spinner.js +14 -0
  48. package/dist/src/components/Spinner.js.map +1 -0
  49. package/dist/src/components/StripePaymentFormWrapper.d.ts +17 -0
  50. package/dist/src/components/StripePaymentFormWrapper.d.ts.map +1 -0
  51. package/dist/src/components/StripePaymentFormWrapper.js +158 -0
  52. package/dist/src/components/StripePaymentFormWrapper.js.map +1 -0
  53. package/dist/src/components/SubscriptionGate.d.ts +21 -0
  54. package/dist/src/components/SubscriptionGate.d.ts.map +1 -0
  55. package/dist/src/components/SubscriptionGate.js +32 -0
  56. package/dist/src/components/SubscriptionGate.js.map +1 -0
  57. package/dist/src/hooks/__tests__/useSubscription.test.d.ts +2 -0
  58. package/dist/src/hooks/__tests__/useSubscription.test.d.ts.map +1 -0
  59. package/dist/src/hooks/__tests__/useSubscription.test.js +554 -0
  60. package/dist/src/hooks/__tests__/useSubscription.test.js.map +1 -0
  61. package/dist/src/hooks/__tests__/useSubscriptionStatus.test.d.ts +2 -0
  62. package/dist/src/hooks/__tests__/useSubscriptionStatus.test.d.ts.map +1 -0
  63. package/dist/src/hooks/__tests__/useSubscriptionStatus.test.js +719 -0
  64. package/dist/src/hooks/__tests__/useSubscriptionStatus.test.js.map +1 -0
  65. package/dist/src/hooks/useCheckout.d.ts +59 -0
  66. package/dist/src/hooks/useCheckout.d.ts.map +1 -0
  67. package/dist/src/hooks/useCheckout.js +138 -0
  68. package/dist/src/hooks/useCheckout.js.map +1 -0
  69. package/dist/src/hooks/useCustomer.d.ts +43 -0
  70. package/dist/src/hooks/useCustomer.d.ts.map +1 -0
  71. package/dist/src/hooks/useCustomer.js +31 -0
  72. package/dist/src/hooks/useCustomer.js.map +1 -0
  73. package/dist/src/hooks/usePlans.d.ts +28 -0
  74. package/dist/src/hooks/usePlans.d.ts.map +1 -0
  75. package/dist/src/hooks/usePlans.js +181 -0
  76. package/dist/src/hooks/usePlans.js.map +1 -0
  77. package/dist/src/hooks/useSolvaPay.d.ts +44 -0
  78. package/dist/src/hooks/useSolvaPay.d.ts.map +1 -0
  79. package/dist/src/hooks/useSolvaPay.js +52 -0
  80. package/dist/src/hooks/useSolvaPay.js.map +1 -0
  81. package/dist/src/hooks/useSubscription.d.ts +46 -0
  82. package/dist/src/hooks/useSubscription.d.ts.map +1 -0
  83. package/dist/src/hooks/useSubscription.js +50 -0
  84. package/dist/src/hooks/useSubscription.js.map +1 -0
  85. package/dist/src/hooks/useSubscriptionStatus.d.ts +19 -0
  86. package/dist/src/hooks/useSubscriptionStatus.d.ts.map +1 -0
  87. package/dist/src/hooks/useSubscriptionStatus.js +68 -0
  88. package/dist/src/hooks/useSubscriptionStatus.js.map +1 -0
  89. package/dist/src/index.d.ts +24 -0
  90. package/dist/src/index.d.ts.map +1 -0
  91. package/dist/src/index.js +26 -0
  92. package/dist/src/index.js.map +1 -0
  93. package/dist/src/types/index.d.ts +339 -0
  94. package/dist/src/types/index.d.ts.map +1 -0
  95. package/dist/src/types/index.js +5 -0
  96. package/dist/src/types/index.js.map +1 -0
  97. package/dist/src/utils/__tests__/subscriptions.test.d.ts +2 -0
  98. package/dist/src/utils/__tests__/subscriptions.test.d.ts.map +1 -0
  99. package/dist/src/utils/__tests__/subscriptions.test.js +121 -0
  100. package/dist/src/utils/__tests__/subscriptions.test.js.map +1 -0
  101. package/dist/src/utils/subscriptions.d.ts +57 -0
  102. package/dist/src/utils/subscriptions.d.ts.map +1 -0
  103. package/dist/src/utils/subscriptions.js +85 -0
  104. package/dist/src/utils/subscriptions.js.map +1 -0
  105. package/dist/tsconfig.tsbuildinfo +1 -0
  106. package/package.json +2 -2
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import type { PlanBadgeProps } from '../types';
3
+ /**
4
+ * Headless Plan Badge Component
5
+ *
6
+ * Displays subscription status with complete styling control.
7
+ * Supports render props, custom components, or className patterns.
8
+ *
9
+ * Prevents flickering by hiding the badge during initial load and when no subscription exists.
10
+ * Shows the badge once loading completes AND an active subscription exists (paid or free).
11
+ * Badge only updates when the plan name actually changes (prevents unnecessary re-renders).
12
+ *
13
+ * Displays the primary active subscription (paid or free) to show current plan status.
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * // Render prop pattern
18
+ * <PlanBadge>
19
+ * {({ subscriptions, loading, displayPlan, shouldShow }) => (
20
+ * shouldShow ? (
21
+ * <div>{displayPlan}</div>
22
+ * ) : null
23
+ * )}
24
+ * </PlanBadge>
25
+ *
26
+ * //ClassName pattern
27
+ * <PlanBadge className="badge badge-primary" />
28
+ * ```
29
+ */
30
+ export declare const PlanBadge: React.FC<PlanBadgeProps>;
31
+ //# sourceMappingURL=PlanBadge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlanBadge.d.ts","sourceRoot":"","sources":["../../../src/components/PlanBadge.tsx"],"names":[],"mappings":"AACA,OAAO,KAAsC,MAAM,OAAO,CAAA;AAE1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAsH9C,CAAA"}
@@ -0,0 +1,119 @@
1
+ 'use client';
2
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
3
+ import { useState, useEffect, useRef } from 'react';
4
+ import { useSubscription } from '../hooks/useSubscription';
5
+ /**
6
+ * Headless Plan Badge Component
7
+ *
8
+ * Displays subscription status with complete styling control.
9
+ * Supports render props, custom components, or className patterns.
10
+ *
11
+ * Prevents flickering by hiding the badge during initial load and when no subscription exists.
12
+ * Shows the badge once loading completes AND an active subscription exists (paid or free).
13
+ * Badge only updates when the plan name actually changes (prevents unnecessary re-renders).
14
+ *
15
+ * Displays the primary active subscription (paid or free) to show current plan status.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * // Render prop pattern
20
+ * <PlanBadge>
21
+ * {({ subscriptions, loading, displayPlan, shouldShow }) => (
22
+ * shouldShow ? (
23
+ * <div>{displayPlan}</div>
24
+ * ) : null
25
+ * )}
26
+ * </PlanBadge>
27
+ *
28
+ * //ClassName pattern
29
+ * <PlanBadge className="badge badge-primary" />
30
+ * ```
31
+ */
32
+ export const PlanBadge = ({ children, as: Component = 'div', className, }) => {
33
+ const { subscriptions, loading, hasPaidSubscription, activeSubscription } = useSubscription();
34
+ const [displayPlan, setDisplayPlan] = useState(null);
35
+ const [hasLoadedOnce, setHasLoadedOnce] = useState(false);
36
+ // Refs for tracking previous values and preventing race conditions
37
+ const lastPlanRef = useRef(null);
38
+ const lastLoadingRef = useRef(true); // Start as true (initial loading state)
39
+ const previousSubscriptionsRef = useRef(subscriptions);
40
+ // Use activeSubscription from hook (primary subscription - paid or free)
41
+ const currentPlanName = activeSubscription?.planName || null;
42
+ const effectivePlanName = currentPlanName;
43
+ // Track when loading completes (not when subscriptions exist)
44
+ // This handles the case where loading finishes but subscriptions array is empty
45
+ // Also handles the case where loading starts as false (already loaded)
46
+ useEffect(() => {
47
+ // Simple: if loading is false, we've loaded (either completed or started as false)
48
+ // Only set once to avoid unnecessary re-renders
49
+ if (!loading && !hasLoadedOnce) {
50
+ setHasLoadedOnce(true);
51
+ }
52
+ // Track loading state for potential future use
53
+ lastLoadingRef.current = loading;
54
+ }, [loading, hasLoadedOnce]);
55
+ // Detect customerRef changes (when subscriptions array reference changes)
56
+ // Reset state when customer changes to prevent stale data
57
+ // Note: Subscriptions array reference changes when customerRef changes OR when refetching
58
+ // We reset state conservatively - if loading, state will be restored when loading completes
59
+ useEffect(() => {
60
+ const previousSubs = previousSubscriptionsRef.current;
61
+ // Check if subscriptions array reference changed
62
+ // This happens when customerRef changes OR when subscriptions are refetched
63
+ if (previousSubs !== subscriptions) {
64
+ // Only reset hasLoadedOnce if we're currently loading (new fetch in progress)
65
+ // If not loading, keep hasLoadedOnce true to prevent flickering on refetches
66
+ if (loading) {
67
+ setHasLoadedOnce(false);
68
+ }
69
+ // Always reset displayPlan and lastPlanRef when subscriptions change
70
+ // This ensures we show the latest plan name
71
+ setDisplayPlan(null);
72
+ lastPlanRef.current = null;
73
+ previousSubscriptionsRef.current = subscriptions;
74
+ }
75
+ }, [subscriptions, loading]);
76
+ // Update display plan when plan name changes
77
+ // Only update when effectivePlanName actually changes (prevents unnecessary re-renders)
78
+ // Also handle case where effectivePlanName becomes null
79
+ useEffect(() => {
80
+ const currentPlan = effectivePlanName;
81
+ const previousPlan = lastPlanRef.current;
82
+ if (currentPlan !== previousPlan) {
83
+ // Plan name changed - update displayPlan
84
+ if (currentPlan !== null) {
85
+ lastPlanRef.current = currentPlan;
86
+ setDisplayPlan(currentPlan);
87
+ }
88
+ else {
89
+ // Plan name became null - clear displayPlan
90
+ lastPlanRef.current = null;
91
+ setDisplayPlan(null);
92
+ }
93
+ }
94
+ else if (currentPlan !== null && displayPlan === null) {
95
+ // Initialize displayPlan if it's null but we have an effectivePlanName
96
+ // This handles the case where displayPlan was reset but effectivePlanName is still valid
97
+ setDisplayPlan(currentPlan);
98
+ }
99
+ }, [effectivePlanName, displayPlan]);
100
+ // Determine if badge should be shown
101
+ // Show if: loading has completed AND we have an active subscription (paid or free)
102
+ // This ensures badge only appears after initial load completes (prevents flickering)
103
+ const shouldShow = effectivePlanName !== null && hasLoadedOnce;
104
+ // Use displayPlan if available, otherwise fall back to effectivePlanName
105
+ // displayPlan is stable (only changes when plan name actually changes)
106
+ const planToDisplay = displayPlan ?? effectivePlanName;
107
+ // If using render prop pattern
108
+ if (children) {
109
+ return _jsx(_Fragment, { children: children({ subscriptions, loading, displayPlan: planToDisplay, shouldShow }) });
110
+ }
111
+ // Hide badge if we shouldn't show it
112
+ if (!shouldShow) {
113
+ return null;
114
+ }
115
+ // Determine className
116
+ const computedClassName = typeof className === 'function' ? className({ subscriptions }) : className;
117
+ return (_jsx(Component, { className: computedClassName, "data-loading": loading, "data-has-subscription": !!activeSubscription, "data-has-paid-subscription": hasPaidSubscription, role: "status", "aria-live": "polite", "aria-busy": loading, "aria-label": `Current plan: ${planToDisplay}`, children: planToDisplay }));
118
+ };
119
+ //# sourceMappingURL=PlanBadge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlanBadge.js","sourceRoot":"","sources":["../../../src/components/PlanBadge.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AACZ,OAAc,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAG1D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,MAAM,SAAS,GAA6B,CAAC,EAClD,QAAQ,EACR,EAAE,EAAE,SAAS,GAAG,KAAK,EACrB,SAAS,GACV,EAAE,EAAE;IACH,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,GAAG,eAAe,EAAE,CAAA;IAC7F,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAA;IACnE,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAEzD,mEAAmE;IACnE,MAAM,WAAW,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAA;IAC/C,MAAM,cAAc,GAAG,MAAM,CAAU,IAAI,CAAC,CAAA,CAAC,wCAAwC;IACrF,MAAM,wBAAwB,GAAG,MAAM,CAAuB,aAAa,CAAC,CAAA;IAE5E,yEAAyE;IACzE,MAAM,eAAe,GAAG,kBAAkB,EAAE,QAAQ,IAAI,IAAI,CAAA;IAE5D,MAAM,iBAAiB,GAAG,eAAe,CAAA;IAEzC,8DAA8D;IAC9D,gFAAgF;IAChF,uEAAuE;IACvE,SAAS,CAAC,GAAG,EAAE;QACb,mFAAmF;QACnF,gDAAgD;QAChD,IAAI,CAAC,OAAO,IAAI,CAAC,aAAa,EAAE,CAAC;YAC/B,gBAAgB,CAAC,IAAI,CAAC,CAAA;QACxB,CAAC;QAED,+CAA+C;QAC/C,cAAc,CAAC,OAAO,GAAG,OAAO,CAAA;IAClC,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAA;IAE5B,0EAA0E;IAC1E,0DAA0D;IAC1D,0FAA0F;IAC1F,4FAA4F;IAC5F,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,YAAY,GAAG,wBAAwB,CAAC,OAAO,CAAA;QAErD,iDAAiD;QACjD,4EAA4E;QAC5E,IAAI,YAAY,KAAK,aAAa,EAAE,CAAC;YACnC,8EAA8E;YAC9E,6EAA6E;YAC7E,IAAI,OAAO,EAAE,CAAC;gBACZ,gBAAgB,CAAC,KAAK,CAAC,CAAA;YACzB,CAAC;YAED,qEAAqE;YACrE,4CAA4C;YAC5C,cAAc,CAAC,IAAI,CAAC,CAAA;YACpB,WAAW,CAAC,OAAO,GAAG,IAAI,CAAA;YAC1B,wBAAwB,CAAC,OAAO,GAAG,aAAa,CAAA;QAClD,CAAC;IACH,CAAC,EAAE,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,CAAA;IAE5B,6CAA6C;IAC7C,wFAAwF;IACxF,wDAAwD;IACxD,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,WAAW,GAAG,iBAAiB,CAAA;QACrC,MAAM,YAAY,GAAG,WAAW,CAAC,OAAO,CAAA;QAExC,IAAI,WAAW,KAAK,YAAY,EAAE,CAAC;YACjC,yCAAyC;YACzC,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;gBACzB,WAAW,CAAC,OAAO,GAAG,WAAW,CAAA;gBACjC,cAAc,CAAC,WAAW,CAAC,CAAA;YAC7B,CAAC;iBAAM,CAAC;gBACN,4CAA4C;gBAC5C,WAAW,CAAC,OAAO,GAAG,IAAI,CAAA;gBAC1B,cAAc,CAAC,IAAI,CAAC,CAAA;YACtB,CAAC;QACH,CAAC;aAAM,IAAI,WAAW,KAAK,IAAI,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;YACxD,uEAAuE;YACvE,yFAAyF;YACzF,cAAc,CAAC,WAAW,CAAC,CAAA;QAC7B,CAAC;IACH,CAAC,EAAE,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC,CAAA;IAEpC,qCAAqC;IACrC,mFAAmF;IACnF,qFAAqF;IACrF,MAAM,UAAU,GAAG,iBAAiB,KAAK,IAAI,IAAI,aAAa,CAAA;IAE9D,yEAAyE;IACzE,uEAAuE;IACvE,MAAM,aAAa,GAAG,WAAW,IAAI,iBAAiB,CAAA;IAEtD,+BAA+B;IAC/B,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,4BAAG,QAAQ,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC,GAAI,CAAA;IAC5F,CAAC;IAED,qCAAqC;IACrC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,sBAAsB;IACtB,MAAM,iBAAiB,GACrB,OAAO,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAE5E,OAAO,CACL,KAAC,SAAS,IACR,SAAS,EAAE,iBAAiB,kBACd,OAAO,2BACE,CAAC,CAAC,kBAAkB,gCACf,mBAAmB,EAC/C,IAAI,EAAC,QAAQ,eACH,QAAQ,eACP,OAAO,gBACN,iBAAiB,aAAa,EAAE,YAE3C,aAAa,GACJ,CACb,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ import type { PlanSelectorProps } from '../types';
3
+ /**
4
+ * Headless Plan Selector Component
5
+ *
6
+ * Provides plan selection logic with complete styling control via render props.
7
+ * Integrates plan fetching, subscription status, and selection state management.
8
+ *
9
+ * Features:
10
+ * - Fetches and manages plans
11
+ * - Tracks selected plan
12
+ * - Provides helpers for checking if plan is current/paid
13
+ * - Integrates with subscription context
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * <PlanSelector
18
+ * agentRef="agent_123"
19
+ * fetcher={async (agentRef) => {
20
+ * const res = await fetch(`/api/list-plans?agentRef=${agentRef}`);
21
+ * const data = await res.json();
22
+ * return data.plans;
23
+ * }}
24
+ * sortBy={(a, b) => (a.price || 0) - (b.price || 0)}
25
+ * autoSelectFirstPaid
26
+ * >
27
+ * {({ plans, selectedPlan, setSelectedPlanIndex, loading, isPaidPlan, isCurrentPlan }) => (
28
+ * <div>
29
+ * {loading ? (
30
+ * <div>Loading plans...</div>
31
+ * ) : (
32
+ * plans.map((plan, index) => (
33
+ * <button
34
+ * key={plan.reference}
35
+ * onClick={() => setSelectedPlanIndex(index)}
36
+ * disabled={!isPaidPlan(plan.name)}
37
+ * >
38
+ * {plan.name} - ${plan.price}
39
+ * {isCurrentPlan(plan.name) && ' (Current)'}
40
+ * </button>
41
+ * ))
42
+ * )}
43
+ * </div>
44
+ * )}
45
+ * </PlanSelector>
46
+ * ```
47
+ */
48
+ export declare const PlanSelector: React.FC<PlanSelectorProps>;
49
+ //# sourceMappingURL=PlanSelector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlanSelector.d.ts","sourceRoot":"","sources":["../../../src/components/PlanSelector.tsx"],"names":[],"mappings":"AACA,OAAO,KAA+B,MAAM,OAAO,CAAA;AAGnD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAyDpD,CAAA"}
@@ -0,0 +1,82 @@
1
+ 'use client';
2
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
3
+ import { useCallback, useMemo } from 'react';
4
+ import { usePlans } from '../hooks/usePlans';
5
+ import { useSubscription } from '../hooks/useSubscription';
6
+ /**
7
+ * Headless Plan Selector Component
8
+ *
9
+ * Provides plan selection logic with complete styling control via render props.
10
+ * Integrates plan fetching, subscription status, and selection state management.
11
+ *
12
+ * Features:
13
+ * - Fetches and manages plans
14
+ * - Tracks selected plan
15
+ * - Provides helpers for checking if plan is current/paid
16
+ * - Integrates with subscription context
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * <PlanSelector
21
+ * agentRef="agent_123"
22
+ * fetcher={async (agentRef) => {
23
+ * const res = await fetch(`/api/list-plans?agentRef=${agentRef}`);
24
+ * const data = await res.json();
25
+ * return data.plans;
26
+ * }}
27
+ * sortBy={(a, b) => (a.price || 0) - (b.price || 0)}
28
+ * autoSelectFirstPaid
29
+ * >
30
+ * {({ plans, selectedPlan, setSelectedPlanIndex, loading, isPaidPlan, isCurrentPlan }) => (
31
+ * <div>
32
+ * {loading ? (
33
+ * <div>Loading plans...</div>
34
+ * ) : (
35
+ * plans.map((plan, index) => (
36
+ * <button
37
+ * key={plan.reference}
38
+ * onClick={() => setSelectedPlanIndex(index)}
39
+ * disabled={!isPaidPlan(plan.name)}
40
+ * >
41
+ * {plan.name} - ${plan.price}
42
+ * {isCurrentPlan(plan.name) && ' (Current)'}
43
+ * </button>
44
+ * ))
45
+ * )}
46
+ * </div>
47
+ * )}
48
+ * </PlanSelector>
49
+ * ```
50
+ */
51
+ export const PlanSelector = ({ agentRef, fetcher, filter, sortBy, autoSelectFirstPaid, children, }) => {
52
+ const { subscriptions } = useSubscription();
53
+ const plansHook = usePlans({
54
+ agentRef,
55
+ fetcher,
56
+ filter,
57
+ sortBy,
58
+ autoSelectFirstPaid,
59
+ });
60
+ const { plans } = plansHook;
61
+ // Helper to check if a plan is paid
62
+ const isPaidPlan = useCallback((planName) => {
63
+ const plan = plans.find(p => p.name === planName);
64
+ return plan ? (plan.price ?? 0) > 0 && !plan.isFreeTier : true;
65
+ }, [plans]);
66
+ // Get active subscription plan name
67
+ const activeSubscription = useMemo(() => {
68
+ const activeSubs = subscriptions.filter(sub => sub.status === 'active');
69
+ return (activeSubs.sort((a, b) => new Date(b.startDate).getTime() - new Date(a.startDate).getTime())[0] || null);
70
+ }, [subscriptions]);
71
+ // Helper to check if a plan is the current subscription
72
+ const isCurrentPlan = useCallback((planName) => {
73
+ return activeSubscription?.planName === planName;
74
+ }, [activeSubscription]);
75
+ return (_jsx(_Fragment, { children: children({
76
+ ...plansHook,
77
+ subscriptions,
78
+ isPaidPlan,
79
+ isCurrentPlan,
80
+ }) }));
81
+ };
82
+ //# sourceMappingURL=PlanSelector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlanSelector.js","sourceRoot":"","sources":["../../../src/components/PlanSelector.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AACZ,OAAc,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAG1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,CAAC,MAAM,YAAY,GAAgC,CAAC,EACxD,QAAQ,EACR,OAAO,EACP,MAAM,EACN,MAAM,EACN,mBAAmB,EACnB,QAAQ,GACT,EAAE,EAAE;IACH,MAAM,EAAE,aAAa,EAAE,GAAG,eAAe,EAAE,CAAA;IAE3C,MAAM,SAAS,GAAG,QAAQ,CAAC;QACzB,QAAQ;QACR,OAAO;QACP,MAAM;QACN,MAAM;QACN,mBAAmB;KACpB,CAAC,CAAA;IAEF,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAA;IAE3B,oCAAoC;IACpC,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,QAAgB,EAAW,EAAE;QAC5B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAA;QACjD,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAA;IAChE,CAAC,EACD,CAAC,KAAK,CAAC,CACR,CAAA;IAED,oCAAoC;IACpC,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,EAAE;QACtC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAA;QACvE,OAAO,CACL,UAAU,CAAC,IAAI,CACb,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAC5E,CAAC,CAAC,CAAC,IAAI,IAAI,CACb,CAAA;IACH,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAA;IAEnB,wDAAwD;IACxD,MAAM,aAAa,GAAG,WAAW,CAC/B,CAAC,QAAgB,EAAW,EAAE;QAC5B,OAAO,kBAAkB,EAAE,QAAQ,KAAK,QAAQ,CAAA;IAClD,CAAC,EACD,CAAC,kBAAkB,CAAC,CACrB,CAAA;IAED,OAAO,CACL,4BACG,QAAQ,CAAC;YACR,GAAG,SAAS;YACZ,aAAa;YACb,UAAU;YACV,aAAa;SACd,CAAC,GACD,CACJ,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ /**
3
+ * SVG-based spinner component using CSS animations
4
+ * Uses the same spinner design as the rest of the site
5
+ */
6
+ export declare const Spinner: React.FC<{
7
+ className?: string;
8
+ size?: 'sm' | 'md' | 'lg';
9
+ }>;
10
+ //# sourceMappingURL=Spinner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Spinner.d.ts","sourceRoot":"","sources":["../../../src/components/Spinner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;CAAE,CA2B/E,CAAA"}
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * SVG-based spinner component using CSS animations
4
+ * Uses the same spinner design as the rest of the site
5
+ */
6
+ export const Spinner = ({ className = '', size = 'md', }) => {
7
+ const sizeClasses = {
8
+ sm: 'h-4 w-4',
9
+ md: 'h-5 w-5',
10
+ lg: 'h-6 w-6',
11
+ };
12
+ return (_jsxs("svg", { className: `animate-spin ${sizeClasses[size]} ${className}`, xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", role: "status", "aria-busy": "true", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }));
13
+ };
14
+ //# sourceMappingURL=Spinner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Spinner.js","sourceRoot":"","sources":["../../../src/components/Spinner.tsx"],"names":[],"mappings":";AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAgE,CAAC,EACnF,SAAS,GAAG,EAAE,EACd,IAAI,GAAG,IAAI,GACZ,EAAE,EAAE;IACH,MAAM,WAAW,GAAG;QAClB,EAAE,EAAE,SAAS;QACb,EAAE,EAAE,SAAS;QACb,EAAE,EAAE,SAAS;KACd,CAAA;IAED,OAAO,CACL,eACE,SAAS,EAAE,gBAAgB,WAAW,CAAC,IAAI,CAAC,IAAI,SAAS,EAAE,EAC3D,KAAK,EAAC,4BAA4B,EAClC,IAAI,EAAC,MAAM,EACX,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,QAAQ,eACH,MAAM,aAEhB,iBAAQ,SAAS,EAAC,YAAY,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,CAAC,EAAC,IAAI,EAAC,MAAM,EAAC,cAAc,EAAC,WAAW,EAAC,GAAG,GAAG,EAC9F,eACE,SAAS,EAAC,YAAY,EACtB,IAAI,EAAC,cAAc,EACnB,CAAC,EAAC,iHAAiH,GACnH,IACE,CACP,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ interface StripePaymentFormWrapperProps {
3
+ onSuccess?: (paymentIntent: any) => void | Promise<void>;
4
+ onError?: (error: Error) => void;
5
+ returnUrl?: string;
6
+ submitButtonText?: string;
7
+ buttonClassName?: string;
8
+ clientSecret: string;
9
+ }
10
+ /**
11
+ * Stripe Payment Form Wrapper Component
12
+ * Renders inside Stripe Elements context and handles the payment flow
13
+ * All hooks are called unconditionally to comply with React Rules of Hooks
14
+ */
15
+ export declare const StripePaymentFormWrapper: React.FC<StripePaymentFormWrapperProps>;
16
+ export {};
17
+ //# sourceMappingURL=StripePaymentFormWrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StripePaymentFormWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/StripePaymentFormWrapper.tsx"],"names":[],"mappings":"AACA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAKlD,UAAU,6BAA6B;IACrC,SAAS,CAAC,EAAE,CAAC,aAAa,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACxD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,EAAE,CAAC,6BAA6B,CAuM5E,CAAA"}
@@ -0,0 +1,158 @@
1
+ 'use client';
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import { useStripe, useElements, CardElement } from '@stripe/react-stripe-js';
5
+ import { useCustomer } from '../hooks/useCustomer';
6
+ import { Spinner } from './Spinner';
7
+ /**
8
+ * Stripe Payment Form Wrapper Component
9
+ * Renders inside Stripe Elements context and handles the payment flow
10
+ * All hooks are called unconditionally to comply with React Rules of Hooks
11
+ */
12
+ export const StripePaymentFormWrapper = ({ onSuccess, onError, returnUrl, submitButtonText = 'Pay Now', buttonClassName, clientSecret, }) => {
13
+ // Always call hooks unconditionally
14
+ const stripe = useStripe();
15
+ const elements = useElements();
16
+ const customer = useCustomer();
17
+ const [isProcessing, setIsProcessing] = useState(false);
18
+ const [message, setMessage] = useState(null);
19
+ const [cardComplete, setCardComplete] = useState(false);
20
+ const handleSubmit = async (event) => {
21
+ event.preventDefault();
22
+ // Double-check Stripe availability (defensive programming)
23
+ if (!stripe || !elements) {
24
+ const errorMessage = 'Stripe is not available. Please refresh the page.';
25
+ setMessage(errorMessage);
26
+ if (onError) {
27
+ onError(new Error(errorMessage));
28
+ }
29
+ return;
30
+ }
31
+ if (!clientSecret) {
32
+ const errorMessage = 'Payment intent not available. Please refresh the page.';
33
+ setMessage(errorMessage);
34
+ if (onError) {
35
+ onError(new Error(errorMessage));
36
+ }
37
+ return;
38
+ }
39
+ setIsProcessing(true);
40
+ setMessage(null);
41
+ try {
42
+ const cardElement = elements.getElement(CardElement);
43
+ if (!cardElement) {
44
+ const errorMessage = 'Card element not found';
45
+ setMessage(errorMessage);
46
+ setIsProcessing(false);
47
+ if (onError) {
48
+ onError(new Error(errorMessage));
49
+ }
50
+ return;
51
+ }
52
+ // Confirm the payment using the clientSecret from the payment intent
53
+ const { error, paymentIntent } = await stripe.confirmCardPayment(clientSecret, {
54
+ payment_method: {
55
+ card: cardElement,
56
+ billing_details: {
57
+ email: customer.email,
58
+ name: customer.name,
59
+ },
60
+ },
61
+ });
62
+ if (error) {
63
+ // Show error to customer (e.g., payment details are invalid)
64
+ const errorMessage = error.message || 'An unexpected error occurred.';
65
+ setMessage(errorMessage);
66
+ setIsProcessing(false);
67
+ if (onError) {
68
+ onError(new Error(errorMessage));
69
+ }
70
+ }
71
+ else if (paymentIntent && paymentIntent.status === 'succeeded') {
72
+ // Payment succeeded on Stripe side - now wait for backend processing
73
+ // Don't show any message during processing - wait for backend to confirm
74
+ setMessage(null);
75
+ if (onSuccess) {
76
+ try {
77
+ // Wait for backend processing to complete
78
+ await onSuccess(paymentIntent);
79
+ // Backend processing completed - now show success
80
+ setMessage('Payment successful!');
81
+ }
82
+ catch (err) {
83
+ // Backend processing failed
84
+ const error = err instanceof Error ? err : new Error('Payment processing failed');
85
+ setMessage('Payment processing failed. Please try again or contact support.');
86
+ setIsProcessing(false);
87
+ if (onError) {
88
+ onError(error);
89
+ }
90
+ return;
91
+ }
92
+ }
93
+ else {
94
+ // No onSuccess callback - show success immediately
95
+ setMessage('Payment successful!');
96
+ }
97
+ }
98
+ else if (paymentIntent && paymentIntent.status === 'requires_action') {
99
+ // Payment requires additional action (3D Secure, etc.)
100
+ setMessage('Payment requires additional authentication. Please complete the verification.');
101
+ setIsProcessing(false);
102
+ }
103
+ else if (paymentIntent) {
104
+ // Payment is processing or requires additional action
105
+ setMessage(`Payment status: ${paymentIntent.status || 'processing'}`);
106
+ setIsProcessing(false);
107
+ }
108
+ }
109
+ catch (err) {
110
+ const error = err instanceof Error ? err : new Error('Unknown error occurred');
111
+ setMessage(error.message);
112
+ if (onError) {
113
+ onError(error);
114
+ }
115
+ }
116
+ finally {
117
+ setIsProcessing(false);
118
+ }
119
+ };
120
+ const isSuccess = message?.includes('successful') ?? false;
121
+ const isReady = !!(stripe && elements);
122
+ // Card element options for minimal styling
123
+ const cardElementOptions = {
124
+ style: {
125
+ base: {
126
+ fontSize: '16px',
127
+ color: '#424770',
128
+ '::placeholder': {
129
+ color: '#aab7c4',
130
+ },
131
+ },
132
+ invalid: {
133
+ color: '#9e2146',
134
+ },
135
+ },
136
+ hidePostalCode: true,
137
+ };
138
+ return (_jsxs(_Fragment, { children: [isReady ? (_jsx(CardElement, { options: cardElementOptions, onChange: e => {
139
+ if (e.error) {
140
+ setMessage(e.error.message);
141
+ setCardComplete(false);
142
+ }
143
+ else {
144
+ setMessage(null);
145
+ setCardComplete(e.complete);
146
+ }
147
+ } })) : (_jsx("div", { style: {
148
+ padding: '12px',
149
+ border: '1px solid #cbd5e1',
150
+ borderRadius: '0.375rem',
151
+ backgroundColor: 'white',
152
+ display: 'flex',
153
+ alignItems: 'center',
154
+ justifyContent: 'center',
155
+ minHeight: '40px',
156
+ }, children: _jsx(Spinner, { size: "sm" }) })), message && !isSuccess && (_jsx("div", { role: "alert", "aria-live": "assertive", "aria-atomic": "true", children: message })), _jsx("button", { type: "submit", disabled: !isReady || !cardComplete || isProcessing || !clientSecret, className: buttonClassName, "aria-busy": isProcessing, "aria-disabled": !isReady || !cardComplete || isProcessing || !clientSecret, onClick: handleSubmit, children: isProcessing ? (_jsxs(_Fragment, { children: [_jsx(Spinner, { size: "sm" }), _jsx("span", { children: "Processing..." })] })) : (submitButtonText) })] }));
157
+ };
158
+ //# sourceMappingURL=StripePaymentFormWrapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StripePaymentFormWrapper.js","sourceRoot":"","sources":["../../../src/components/StripePaymentFormWrapper.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import type { SubscriptionGateProps } from '../types';
3
+ /**
4
+ * Headless Subscription Gate Component
5
+ *
6
+ * Controls access to content based on subscription status.
7
+ * Uses render props to give developers full control over locked/unlocked states.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * <SubscriptionGate requirePlan="Pro Plan">
12
+ * {({ hasAccess, loading }) => {
13
+ * if (loading) return <Skeleton />;
14
+ * if (!hasAccess) return <Paywall />;
15
+ * return <PremiumContent />;
16
+ * }}
17
+ * </SubscriptionGate>
18
+ * ```
19
+ */
20
+ export declare const SubscriptionGate: React.FC<SubscriptionGateProps>;
21
+ //# sourceMappingURL=SubscriptionGate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubscriptionGate.d.ts","sourceRoot":"","sources":["../../../src/components/SubscriptionGate.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AAErD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAgB5D,CAAA"}
@@ -0,0 +1,32 @@
1
+ 'use client';
2
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
3
+ import { useSubscription } from '../hooks/useSubscription';
4
+ /**
5
+ * Headless Subscription Gate Component
6
+ *
7
+ * Controls access to content based on subscription status.
8
+ * Uses render props to give developers full control over locked/unlocked states.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * <SubscriptionGate requirePlan="Pro Plan">
13
+ * {({ hasAccess, loading }) => {
14
+ * if (loading) return <Skeleton />;
15
+ * if (!hasAccess) return <Paywall />;
16
+ * return <PremiumContent />;
17
+ * }}
18
+ * </SubscriptionGate>
19
+ * ```
20
+ */
21
+ export const SubscriptionGate = ({ requirePlan, children }) => {
22
+ const { subscriptions, loading, hasPlan } = useSubscription();
23
+ const hasAccess = requirePlan
24
+ ? hasPlan(requirePlan)
25
+ : subscriptions.some(sub => sub.status === 'active');
26
+ return (_jsx(_Fragment, { children: children({
27
+ hasAccess,
28
+ subscriptions,
29
+ loading,
30
+ }) }));
31
+ };
32
+ //# sourceMappingURL=SubscriptionGate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubscriptionGate.js","sourceRoot":"","sources":["../../../src/components/SubscriptionGate.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAG1D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAoC,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,EAAE;IAC7F,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,eAAe,EAAE,CAAA;IAE7D,MAAM,SAAS,GAAG,WAAW;QAC3B,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;QACtB,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAA;IAEtD,OAAO,CACL,4BACG,QAAQ,CAAC;YACR,SAAS;YACT,aAAa;YACb,OAAO;SACR,CAAC,GACD,CACJ,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=useSubscription.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSubscription.test.d.ts","sourceRoot":"","sources":["../../../../src/hooks/__tests__/useSubscription.test.tsx"],"names":[],"mappings":""}