@voxepay/checkout 0.0.1-security → 0.5.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.

Potentially problematic release.


This version of @voxepay/checkout might be problematic. Click here for more details.

@@ -0,0 +1,91 @@
1
+ /**
2
+ * Input formatting utilities for VoxePay Checkout
3
+ */
4
+
5
+ /**
6
+ * Format card number with spaces every 4 digits
7
+ */
8
+ export function formatCardNumber(value: string): string {
9
+ const cleaned = value.replace(/\D/g, '');
10
+ const groups = cleaned.match(/.{1,4}/g) || [];
11
+ return groups.join(' ').slice(0, 23); // Max: 19 digits + 4 spaces
12
+ }
13
+
14
+ /**
15
+ * Format expiry date as MM/YY
16
+ */
17
+ export function formatExpiry(value: string): string {
18
+ const cleaned = value.replace(/\D/g, '');
19
+
20
+ if (cleaned.length === 0) return '';
21
+ if (cleaned.length === 1) {
22
+ return parseInt(cleaned) > 1 ? `0${cleaned}` : cleaned;
23
+ }
24
+ if (cleaned.length === 2) {
25
+ const month = parseInt(cleaned);
26
+ if (month > 12) return '12';
27
+ if (month === 0) return '01';
28
+ return cleaned;
29
+ }
30
+
31
+ const month = cleaned.slice(0, 2);
32
+ const year = cleaned.slice(2, 4);
33
+ return `${month}/${year}`;
34
+ }
35
+
36
+ /**
37
+ * Format CVV (numbers only, max 4 digits)
38
+ */
39
+ export function formatCVV(value: string): string {
40
+ return value.replace(/\D/g, '').slice(0, 4);
41
+ }
42
+
43
+ /**
44
+ * Format currency amount
45
+ */
46
+ export function formatAmount(amount: number, currency: string): string {
47
+ const formatter = new Intl.NumberFormat('en-US', {
48
+ style: 'currency',
49
+ currency: currency,
50
+ minimumFractionDigits: 2,
51
+ });
52
+
53
+ // Convert from smallest unit (cents/kobo) to main unit
54
+ return formatter.format(amount / 100);
55
+ }
56
+
57
+ /**
58
+ * Format currency amount when already in main unit
59
+ */
60
+ export function formatMainUnitAmount(amount: number, currency: string): string {
61
+ const formatter = new Intl.NumberFormat('en-US', {
62
+ style: 'currency',
63
+ currency: currency,
64
+ minimumFractionDigits: 2,
65
+ });
66
+
67
+ return formatter.format(amount);
68
+ }
69
+
70
+ /**
71
+ * Get currency symbol
72
+ */
73
+ export function getCurrencySymbol(currency: string): string {
74
+ const symbols: Record<string, string> = {
75
+ NGN: '₦',
76
+ USD: '$',
77
+ EUR: '€',
78
+ GBP: '£',
79
+ GHS: '₵',
80
+ KES: 'KSh',
81
+ ZAR: 'R',
82
+ };
83
+ return symbols[currency.toUpperCase()] || currency;
84
+ }
85
+
86
+ /**
87
+ * Format card PIN (numbers only, max 4 digits)
88
+ */
89
+ export function formatPIN(value: string): string {
90
+ return value.replace(/\D/g, '').slice(0, 4);
91
+ }
package/src/voxepay.ts ADDED
@@ -0,0 +1,200 @@
1
+ /**
2
+ * VoxePay - Modern Payment Checkout SDK
3
+ *
4
+ * A beautiful, modern payment modal for the web.
5
+ *
6
+ * @example
7
+ * ```javascript
8
+ * // Initialize VoxePay
9
+ * VoxePay.init({ apiKey: 'pk_live_xxxxx' });
10
+ *
11
+ * // Open checkout
12
+ * VoxePay.checkout({
13
+ * amount: 4999,
14
+ * currency: 'NGN',
15
+ * description: 'Premium Plan',
16
+ * onSuccess: (result) => console.log('Paid!', result),
17
+ * onError: (error) => console.error('Failed', error),
18
+ * });
19
+ * ```
20
+ */
21
+
22
+ import { VoxePayModal } from './components/modal';
23
+ import type { VoxePayConfig, CheckoutOptions, VoxePayTheme } from './types';
24
+
25
+ class VoxePaySDK {
26
+ private config: VoxePayConfig | null = null;
27
+ private currentModal: VoxePayModal | null = null;
28
+ private initialized = false;
29
+
30
+ /**
31
+ * Initialize VoxePay with your configuration
32
+ * @param config - Configuration object with required organizationId and optional settings
33
+ */
34
+ init(config: VoxePayConfig): void {
35
+ if (!config.organizationId) {
36
+ console.error('[VoxePay] Organization ID is required. Find it in your VoxePay dashboard.');
37
+ return;
38
+ }
39
+
40
+ this.config = {
41
+ theme: 'dark',
42
+ locale: 'en-US',
43
+ ...config,
44
+ };
45
+ this.initialized = true;
46
+
47
+ // Apply theme
48
+ if (config.theme === 'auto') {
49
+ this.applyAutoTheme();
50
+ } else if (config.theme === 'light') {
51
+ document.documentElement.classList.add('voxepay-light');
52
+ }
53
+
54
+ // Apply custom styles
55
+ if (config.customStyles) {
56
+ this.applyCustomStyles(config.customStyles);
57
+ }
58
+
59
+ console.log('[VoxePay] Initialized successfully');
60
+ }
61
+
62
+ /**
63
+ * Open the checkout modal
64
+ * @param options - Checkout options including amount, currency, and callbacks
65
+ */
66
+ checkout(options: CheckoutOptions): void {
67
+ if (!this.initialized) {
68
+ console.error('[VoxePay] Not initialized. Call VoxePay.init() first.');
69
+ options.onError({
70
+ code: 'NOT_INITIALIZED',
71
+ message: 'VoxePay SDK not initialized. Call VoxePay.init() first.',
72
+ recoverable: false,
73
+ });
74
+ return;
75
+ }
76
+
77
+ if (!options.amount || options.amount <= 0) {
78
+ console.error('[VoxePay] Invalid amount');
79
+ options.onError({
80
+ code: 'INVALID_AMOUNT',
81
+ message: 'Payment amount must be greater than 0',
82
+ recoverable: false,
83
+ });
84
+ return;
85
+ }
86
+
87
+ if (!options.currency) {
88
+ console.error('[VoxePay] Currency is required');
89
+ options.onError({
90
+ code: 'INVALID_CURRENCY',
91
+ message: 'Currency code is required',
92
+ recoverable: false,
93
+ });
94
+ return;
95
+ }
96
+
97
+ // Close any existing modal
98
+ this.closeModal();
99
+
100
+ // Create and open new modal
101
+ this.currentModal = new VoxePayModal({
102
+ ...options,
103
+ _sdkConfig: {
104
+ apiKey: this.config!.apiKey,
105
+ organizationId: this.config!.organizationId,
106
+ baseUrl: this.config!.baseUrl,
107
+ paymentLinkSlug: this.config!.paymentLinkSlug,
108
+ simulateWebhook: this.config!.simulateWebhook,
109
+ bypassKey: this.config!.bypassKey,
110
+ },
111
+ onClose: () => {
112
+ this.currentModal = null;
113
+ options.onClose?.();
114
+ },
115
+ });
116
+
117
+ this.currentModal.open();
118
+ }
119
+
120
+ /**
121
+ * Close the current checkout modal
122
+ */
123
+ closeModal(): void {
124
+ if (this.currentModal) {
125
+ this.currentModal.close();
126
+ this.currentModal = null;
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Set the theme
132
+ * @param theme - 'dark', 'light', or 'auto'
133
+ */
134
+ setTheme(theme: 'dark' | 'light' | 'auto'): void {
135
+ document.documentElement.classList.remove('voxepay-light');
136
+
137
+ if (theme === 'light') {
138
+ document.documentElement.classList.add('voxepay-light');
139
+ } else if (theme === 'auto') {
140
+ this.applyAutoTheme();
141
+ }
142
+
143
+ if (this.config) {
144
+ this.config.theme = theme;
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Apply system theme preference
150
+ */
151
+ private applyAutoTheme(): void {
152
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
153
+ if (!prefersDark) {
154
+ document.documentElement.classList.add('voxepay-light');
155
+ }
156
+
157
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
158
+ if (this.config?.theme === 'auto') {
159
+ document.documentElement.classList.toggle('voxepay-light', !e.matches);
160
+ }
161
+ });
162
+ }
163
+
164
+ /**
165
+ * Apply custom CSS variables
166
+ */
167
+ private applyCustomStyles(styles: Partial<VoxePayTheme>): void {
168
+ const root = document.documentElement;
169
+ for (const [key, value] of Object.entries(styles)) {
170
+ if (value) {
171
+ root.style.setProperty(key, value);
172
+ }
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Get the SDK version
178
+ */
179
+ get version(): string {
180
+ return '0.5.7';
181
+ }
182
+
183
+ /**
184
+ * Check if SDK is initialized
185
+ */
186
+ get isInitialized(): boolean {
187
+ return this.initialized;
188
+ }
189
+ }
190
+
191
+ // Create singleton instance
192
+ const VoxePay = new VoxePaySDK();
193
+
194
+ // Export for different module systems
195
+ export { VoxePay, VoxePaySDK };
196
+
197
+ // Make available on window for script tag usage
198
+ if (typeof window !== 'undefined') {
199
+ (window as unknown as { VoxePay: VoxePaySDK }).VoxePay = VoxePay;
200
+ }