@xpayeg/sdk 2.4.0 → 3.0.0

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/README.md CHANGED
@@ -22,36 +22,38 @@ npm install @xpayeg/sdk
22
22
  <script src="https://checkout.xpay.app/v1/sdk.js"></script>
23
23
  ```
24
24
 
25
+ Both ESM (`import`) and CommonJS (`require`) are supported, with matching TypeScript declarations. Your tooling selects the appropriate entrypoint automatically.
26
+
25
27
  ## Step 1: Create a Checkout Session [Server-side]
26
28
 
27
29
  On your server, create a Checkout Session and return the `clientSecret` to your frontend.
28
30
 
29
31
  ```javascript
30
32
  // Your server (Node.js example)
31
- app.post('/api/create-checkout', async (req, res) => {
32
- const response = await fetch('https://api.xpay.app/checkout/sessions', {
33
- method: 'POST',
33
+ app.post("/api/create-checkout", async (req, res) => {
34
+ const response = await fetch("https://api.xpay.app/checkout/sessions", {
35
+ method: "POST",
34
36
  headers: {
35
- 'Authorization': `Bearer ${process.env.XPAY_SECRET_KEY}`,
36
- 'Content-Type': 'application/json',
37
+ Authorization: `Bearer ${process.env.XPAY_SECRET_KEY}`,
38
+ "Content-Type": "application/json",
37
39
  },
38
40
  body: JSON.stringify({
39
- uiMode: 'custom', // 'custom' for Elements SDK, 'embedded' for drop-in modal, 'hosted' for redirect
41
+ uiMode: "custom", // 'custom' for Elements SDK, 'embedded' for drop-in modal, 'hosted' for redirect
40
42
  lineItems: [
41
43
  {
42
44
  priceData: {
43
- unitAmount: 50000, // 500.00 EGP in piasters
44
- currency: 'EGP',
45
- productData: { name: 'Premium Plan' },
45
+ unitAmount: 50000, // 500.00 EGP in piasters
46
+ currency: "EGP",
47
+ productData: { name: "Premium Plan" },
46
48
  },
47
49
  quantity: 1,
48
50
  },
49
51
  ],
50
52
  afterCompletion: {
51
- type: 'redirect',
53
+ type: "redirect",
52
54
  redirect: {
53
55
  // {CHECKOUT_SESSION_ID} is automatically replaced with the actual session ID
54
- url: 'https://yoursite.com/success?session_id={CHECKOUT_SESSION_ID}',
56
+ url: "https://yoursite.com/success?session_id={CHECKOUT_SESSION_ID}",
55
57
  },
56
58
  },
57
59
  }),
@@ -69,55 +71,64 @@ app.post('/api/create-checkout', async (req, res) => {
69
71
  Returns a single object with session fields and action methods merged together.
70
72
 
71
73
  ```javascript
72
- import { loadXPay } from '@xpayeg/sdk';
74
+ import { loadXPay } from "@xpayeg/sdk";
73
75
 
74
- const xpay = await loadXPay('pk_test_xxx');
76
+ const xpay = await loadXPay("pk_test_xxx");
75
77
 
76
78
  // Fetch client secret from your server
77
- const { clientSecret } = await fetch('/api/create-checkout', { method: 'POST' }).then(r => r.json());
79
+ const { clientSecret } = await fetch("/api/create-checkout", { method: "POST" }).then((r) =>
80
+ r.json(),
81
+ );
78
82
 
79
83
  // Initialize checkout -- returns session data + action methods in one object
80
84
  const checkout = await xpay.initCheckout({ clientSecret });
81
85
 
82
86
  // Destructure session fields and actions together
83
87
  const {
84
- status, currency, amountTotal, amountSubtotal, canConfirm, paymentMethods,
85
- confirm, applyPromotionCode, removePromotionCode, updateLineItemQuantity,
88
+ status,
89
+ currency,
90
+ amountTotal,
91
+ amountSubtotal,
92
+ canConfirm,
93
+ paymentMethods,
94
+ confirm,
95
+ applyPromotionCode,
96
+ removePromotionCode,
97
+ updateLineItemQuantity,
86
98
  } = checkout;
87
99
 
88
100
  // Display in your UI
89
- document.getElementById('total').textContent =
90
- `${currency} ${(amountTotal / 100).toFixed(2)}`;
91
- document.getElementById('methods').textContent =
92
- `Pay with: ${paymentMethods.map(pm => pm.displayName).join(', ')}`;
101
+ document.getElementById("total").textContent = `${currency} ${(amountTotal / 100).toFixed(2)}`;
102
+ document.getElementById("methods").textContent =
103
+ `Pay with: ${paymentMethods.map((pm) => pm.displayName).join(", ")}`;
93
104
  ```
94
105
 
95
106
  `clientSecret` accepts `Promise<string> | string`, so you can pass the fetch directly:
96
107
 
97
108
  ```javascript
98
109
  const checkout = await xpay.initCheckout({
99
- clientSecret: fetch('/api/create-checkout', { method: 'POST' })
100
- .then(r => r.json())
101
- .then(data => data.clientSecret),
110
+ clientSecret: fetch("/api/create-checkout", { method: "POST" })
111
+ .then((r) => r.json())
112
+ .then((data) => data.clientSecret),
102
113
  });
103
114
  ```
104
115
 
105
116
  **Session fields on the checkout object:**
106
117
 
107
- | Field | Type | Example | Description |
108
- |-------|------|---------|-------------|
109
- | `id` | `string` | `"cs_test_abc"` | Session ID |
110
- | `status` | `SessionStatus` | `{ type: "open" }` | Structured status (see below) |
111
- | `canConfirm` | `boolean` | `true` | Whether the session is ready for confirmation |
112
- | `amountTotal` | `number` | `52450` | Final total in smallest currency unit |
113
- | `amountSubtotal` | `number` | `50000` | Subtotal before fees/discounts |
114
- | `currency` | `string` | `"EGP"` | ISO 4217 currency code |
115
- | `merchantName` | `string` | `"My Store"` | Merchant display name |
116
- | `livemode` | `boolean` | `false` | Whether live or test mode |
117
- | `paymentMethods` | `PaymentMethodInfo[]` | `[{ type, displayName, category }]` | Available payment methods |
118
- | `lineItems` | `LineItemDto[]` | | Line items with prices and quantities |
119
- | `totalDetails` | `TotalDetailsResponseDto` | | Breakdown of fees, discounts, VAT |
120
- | `discounts` | `DiscountResponseDto[]` | | Applied discounts |
118
+ | Field | Type | Example | Description |
119
+ | ---------------- | ------------------------- | ----------------------------------- | --------------------------------------------- |
120
+ | `id` | `string` | `"cs_test_abc"` | Session ID |
121
+ | `status` | `SessionStatus` | `{ type: "open" }` | Structured status (see below) |
122
+ | `canConfirm` | `boolean` | `true` | Whether the session is ready for confirmation |
123
+ | `amountTotal` | `number` | `52450` | Final total in smallest currency unit |
124
+ | `amountSubtotal` | `number` | `50000` | Subtotal before fees/discounts |
125
+ | `currency` | `string` | `"EGP"` | ISO 4217 currency code |
126
+ | `merchantName` | `string` | `"My Store"` | Merchant display name |
127
+ | `livemode` | `boolean` | `false` | Whether live or test mode |
128
+ | `paymentMethods` | `PaymentMethodInfo[]` | `[{ type, displayName, category }]` | Available payment methods |
129
+ | `lineItems` | `LineItemDto[]` | | Line items with prices and quantities |
130
+ | `totalDetails` | `TotalDetailsResponseDto` | | Breakdown of fees, discounts, VAT |
131
+ | `discounts` | `DiscountResponseDto[]` | | Applied discounts |
121
132
 
122
133
  ### Session Status
123
134
 
@@ -125,19 +136,19 @@ const checkout = await xpay.initCheckout({
125
136
 
126
137
  ```javascript
127
138
  // Check session status
128
- if (checkout.status.type === 'open') {
139
+ if (checkout.status.type === "open") {
129
140
  // Session is active, show payment form
130
141
  }
131
142
 
132
- if (checkout.status.type === 'expired') {
143
+ if (checkout.status.type === "expired") {
133
144
  // Session expired, show message or create a new one
134
- showMessage('This checkout session has expired.');
145
+ showMessage("This checkout session has expired.");
135
146
  }
136
147
 
137
- if (checkout.status.type === 'complete') {
148
+ if (checkout.status.type === "complete") {
138
149
  // Payment finished -- check paymentStatus for details
139
150
  console.log(checkout.status.paymentStatus); // "paid"
140
- showMessage('Payment successful!');
151
+ showMessage("Payment successful!");
141
152
  }
142
153
  ```
143
154
 
@@ -146,29 +157,29 @@ if (checkout.status.type === 'complete') {
146
157
  For event-driven initialization and lower-level control.
147
158
 
148
159
  ```javascript
149
- const xpay = await loadXPay('pk_test_xxx');
160
+ const xpay = await loadXPay("pk_test_xxx");
150
161
  const elements = xpay.elements({ clientSecret });
151
162
 
152
- elements.on('ready', ({ session }) => {
153
- console.log(session.status); // { type: "open" }
154
- console.log(session.canConfirm); // true
155
- console.log(session.amountTotal); // 52450
163
+ elements.on("ready", ({ session }) => {
164
+ console.log(session.status); // { type: "open" }
165
+ console.log(session.canConfirm); // true
166
+ console.log(session.amountTotal); // 52450
156
167
  console.log(session.paymentMethods); // [{ type: 'card', ... }]
157
168
  });
158
169
 
159
- elements.on('loaderror', (event) => {
170
+ elements.on("loaderror", (event) => {
160
171
  // Only fires for actual failures (invalid secret, network error, etc.)
161
172
  // event: { type: "invalid_request_error" | "api_error" | "network_error", message, code?, param?, docUrl? }
162
- console.error('Failed to load:', event.message);
173
+ console.error("Failed to load:", event.message);
163
174
  });
164
175
 
165
- elements.on('error', (error) => {
176
+ elements.on("error", (error) => {
166
177
  // Fires for unsolicited errors not triggered by a merchant action.
167
178
  // Examples: session expired during fee recalculation when switching payment methods, BIN detection failure.
168
- console.log(error.type); // "invalid_request_error"
169
- console.log(error.code); // "checkout_session_expired"
179
+ console.log(error.type); // "invalid_request_error"
180
+ console.log(error.code); // "checkout_session_expired"
170
181
  console.log(error.message); // "This checkout session has expired"
171
- console.log(error.docUrl); // "https://docs.xpay.app/api/errors#checkout_session_expired"
182
+ console.log(error.docUrl); // "https://docs.xpay.app/api/errors#checkout_session_expired"
172
183
  });
173
184
  ```
174
185
 
@@ -180,12 +191,12 @@ elements.on('error', (error) => {
180
191
  const checkout = await xpay.initCheckout({ clientSecret });
181
192
  const elements = checkout.getElements();
182
193
 
183
- const paymentElement = elements.create('payment');
184
- paymentElement.mount('#payment-element');
194
+ const paymentElement = elements.create("payment");
195
+ paymentElement.mount("#payment-element");
185
196
 
186
- paymentElement.on('change', (event) => {
197
+ paymentElement.on("change", (event) => {
187
198
  submitButton.disabled = !event.complete;
188
- console.log(event.value.type); // 'card', 'valu', etc.
199
+ console.log(event.value.type); // 'card', 'valu', etc.
189
200
  });
190
201
  ```
191
202
 
@@ -199,17 +210,17 @@ By default, the result is **returned to your code** (`redirect: "if_required"`).
199
210
  // Default behavior: returns result to your code (no redirect)
200
211
  const result = await checkout.confirm({
201
212
  customerDetails: {
202
- email: 'customer@example.com',
203
- name: 'Ahmed Hassan',
204
- phone: '+201234567890',
213
+ email: "customer@example.com",
214
+ name: "Ahmed Hassan",
215
+ phone: "+201234567890",
205
216
  },
206
217
  });
207
218
 
208
- if (result.type === 'error') {
219
+ if (result.type === "error") {
209
220
  errorDiv.textContent = result.error.message;
210
221
  } else {
211
222
  console.log(result.session.status); // { type: "complete", paymentStatus: "paid" }
212
- window.location.href = '/thank-you';
223
+ window.location.href = "/thank-you";
213
224
  }
214
225
  ```
215
226
 
@@ -218,21 +229,21 @@ To redirect after success instead:
218
229
  ```javascript
219
230
  await checkout.confirm({
220
231
  customerDetails: {
221
- email: 'customer@example.com',
222
- name: 'Ahmed Hassan',
232
+ email: "customer@example.com",
233
+ name: "Ahmed Hassan",
223
234
  },
224
- redirect: 'always', // Redirect to afterCompletion.redirect.url
235
+ redirect: "always", // Redirect to afterCompletion.redirect.url
225
236
  });
226
237
  // ^ If successful, the page navigates away. Code below only runs on error.
227
238
  ```
228
239
 
229
240
  **Redirect behavior:**
230
241
 
231
- | `redirect` | Behavior |
232
- |---|---|
233
- | Not set (default) | `"if_required"` — returns result to your code |
234
- | `"always"` | Redirects to the session's `afterCompletion.redirect.url` |
235
- | `"if_required"` | Returns result to your code — no redirect |
242
+ | `redirect` | Behavior |
243
+ | ----------------- | --------------------------------------------------------- |
244
+ | Not set (default) | `"if_required"` — returns result to your code |
245
+ | `"always"` | Redirects to the session's `afterCompletion.redirect.url` |
246
+ | `"if_required"` | Returns result to your code — no redirect |
236
247
 
237
248
  Your server sets that URL when it creates the session. XPay navigates there unchanged, appending nothing.
238
249
 
@@ -257,18 +268,18 @@ Action methods return `Promise<{ type: "success", session } | { type: "error", e
257
268
 
258
269
  ```javascript
259
270
  // Apply promotion code
260
- const result = await checkout.applyPromotionCode('SAVE20');
261
- if (result.type === 'error') {
271
+ const result = await checkout.applyPromotionCode("SAVE20");
272
+ if (result.type === "error") {
262
273
  errorDiv.textContent = result.error.message; // e.g., "Invalid promotion code"
263
274
  } else {
264
- console.log('New total:', result.session.amountTotal);
275
+ console.log("New total:", result.session.amountTotal);
265
276
  }
266
277
 
267
278
  // Remove promotion code
268
279
  await checkout.removePromotionCode();
269
280
 
270
281
  // Update line item quantity (object param, not positional)
271
- await checkout.updateLineItemQuantity({ lineItem: 'li_abc123', quantity: 3 });
282
+ await checkout.updateLineItemQuantity({ lineItem: "li_abc123", quantity: 3 });
272
283
  ```
273
284
 
274
285
  ### Listening for Session Changes
@@ -277,25 +288,25 @@ Every update (promo codes, quantity changes, payment method selection, BIN detec
277
288
 
278
289
  ```javascript
279
290
  // initCheckout -- use on('change', ...)
280
- checkout.on('change', (session) => {
291
+ checkout.on("change", (session) => {
281
292
  totalDiv.textContent = `Total: ${session.currency} ${(session.amountTotal / 100).toFixed(2)}`;
282
293
 
283
294
  // Amounts breakdown via totalDetails
284
- console.log(session.totalDetails?.amountPlatformFee); // Processing fee
285
- console.log(session.totalDetails?.amountCollectedVat); // VAT
286
- console.log(session.totalDetails?.amountDiscount); // Discount amount
287
- console.log(session.totalDetails?.amountShipping); // Shipping
288
- console.log(session.totalDetails?.amountTax); // Tax
289
-
290
- console.log(session.discounts); // Applied discounts
291
- console.log(session.lineItems); // Updated line items
295
+ console.log(session.totalDetails?.amountPlatformFee); // Processing fee
296
+ console.log(session.totalDetails?.amountCollectedVat); // VAT
297
+ console.log(session.totalDetails?.amountDiscount); // Discount amount
298
+ console.log(session.totalDetails?.amountShipping); // Shipping
299
+ console.log(session.totalDetails?.amountTax); // Tax
300
+
301
+ console.log(session.discounts); // Applied discounts
302
+ console.log(session.lineItems); // Updated line items
292
303
  });
293
304
  ```
294
305
 
295
306
  With the classic `elements` API:
296
307
 
297
308
  ```javascript
298
- elements.on('change', (session) => {
309
+ elements.on("change", (session) => {
299
310
  console.log(session.amountTotal);
300
311
  console.log(session.totalDetails?.amountPlatformFee);
301
312
  });
@@ -307,8 +318,8 @@ Force a fresh session fetch if needed:
307
318
 
308
319
  ```javascript
309
320
  const result = await elements.fetchUpdates();
310
- if (result.type === 'success') {
311
- console.log('Session refreshed:', result.session.amountTotal);
321
+ if (result.type === "success") {
322
+ console.log("Session refreshed:", result.session.amountTotal);
312
323
  }
313
324
  ```
314
325
 
@@ -320,11 +331,10 @@ Retrieve the session from **your server** (using your API key) to display order
320
331
 
321
332
  ```javascript
322
333
  // Your server -- retrieves session using your API key
323
- app.get('/api/order-status', async (req, res) => {
324
- const response = await fetch(
325
- `https://api.xpay.app/checkout/sessions/${req.query.session_id}`,
326
- { headers: { 'Authorization': `Bearer ${process.env.XPAY_SECRET_KEY}` } },
327
- );
334
+ app.get("/api/order-status", async (req, res) => {
335
+ const response = await fetch(`https://api.xpay.app/checkout/sessions/${req.query.session_id}`, {
336
+ headers: { Authorization: `Bearer ${process.env.XPAY_SECRET_KEY}` },
337
+ });
328
338
  const session = await response.json();
329
339
  res.json(session);
330
340
  });
@@ -333,12 +343,12 @@ app.get('/api/order-status', async (req, res) => {
333
343
  **Client-side success page:**
334
344
 
335
345
  ```javascript
336
- const sessionId = new URLSearchParams(window.location.search).get('session_id');
337
- const session = await fetch(`/api/order-status?session_id=${sessionId}`).then(r => r.json());
346
+ const sessionId = new URLSearchParams(window.location.search).get("session_id");
347
+ const session = await fetch(`/api/order-status?session_id=${sessionId}`).then((r) => r.json());
338
348
 
339
- document.getElementById('status').textContent =
340
- session.paymentStatus === 'paid' ? 'Payment Confirmed' : 'Processing...';
341
- document.getElementById('total').textContent =
349
+ document.getElementById("status").textContent =
350
+ session.paymentStatus === "paid" ? "Payment Confirmed" : "Processing...";
351
+ document.getElementById("total").textContent =
342
352
  `${session.currency} ${(session.amountTotal / 100).toFixed(2)}`;
343
353
 
344
354
  // Amounts breakdown
@@ -349,8 +359,8 @@ document.getElementById('total').textContent =
349
359
  // session.totalDetails.amountTax -- 0
350
360
 
351
361
  // Line items
352
- session.lineItems?.forEach(item => {
353
- console.log(item.price.product.name, 'x', item.quantity, '=', item.amountTotal);
362
+ session.lineItems?.forEach((item) => {
363
+ console.log(item.price.product.name, "x", item.quantity, "=", item.amountTotal);
354
364
  });
355
365
  ```
356
366
 
@@ -359,11 +369,11 @@ session.lineItems?.forEach(item => {
359
369
  Listen for webhook events on your server. This is the source of truth for order fulfillment.
360
370
 
361
371
  ```javascript
362
- app.post('/webhooks/xpay', (req, res) => {
372
+ app.post("/webhooks/xpay", (req, res) => {
363
373
  const event = req.body;
364
374
 
365
- if (event.type === 'checkout.session.completed') {
366
- fulfillOrder(event.data); // Ship product, send email, update DB
375
+ if (event.type === "checkout.session.completed") {
376
+ fulfillOrder(event.data); // Ship product, send email, update DB
367
377
  }
368
378
 
369
379
  res.json({ received: true });
@@ -379,17 +389,17 @@ The simplest integration -- opens the full checkout in a modal overlay. No form
379
389
 
380
390
  <script src="https://checkout.xpay.app/v1/sdk.js"></script>
381
391
  <script>
382
- document.getElementById('checkout-button').addEventListener('click', async () => {
383
- const xpay = XPay('pk_test_xxx');
392
+ document.getElementById("checkout-button").addEventListener("click", async () => {
393
+ const xpay = XPay("pk_test_xxx");
384
394
 
385
395
  const checkout = xpay.checkout({
386
- clientSecret: 'cs_test_abc_secret_xyz',
387
- mode: 'modal',
396
+ clientSecret: "cs_test_abc_secret_xyz",
397
+ mode: "modal",
388
398
  onComplete: (result) => {
389
- window.location.href = '/success';
399
+ window.location.href = "/success";
390
400
  },
391
401
  onClose: () => {
392
- console.log('Customer closed checkout');
402
+ console.log("Customer closed checkout");
393
403
  },
394
404
  });
395
405
 
@@ -403,16 +413,16 @@ The simplest integration -- opens the full checkout in a modal overlay. No form
403
413
  The `@xpayeg/react` package provides a `useCheckout()` hook that wraps `initCheckout` with loading/error states:
404
414
 
405
415
  ```javascript
406
- import { useCheckout } from '@xpayeg/react';
416
+ import { useCheckout } from "@xpayeg/react";
407
417
 
408
418
  function CheckoutPage() {
409
419
  const checkoutState = useCheckout();
410
420
 
411
- if (checkoutState.type === 'loading') {
421
+ if (checkoutState.type === "loading") {
412
422
  return <Spinner />;
413
423
  }
414
424
 
415
- if (checkoutState.type === 'error') {
425
+ if (checkoutState.type === "error") {
416
426
  return <div>Error: {checkoutState.error.message}</div>;
417
427
  }
418
428
 
@@ -420,9 +430,13 @@ function CheckoutPage() {
420
430
 
421
431
  return (
422
432
  <div>
423
- <h2>Total: {currency} {(amountTotal / 100).toFixed(2)}</h2>
424
- {lineItems?.map(item => (
425
- <div key={item.id}>{item.price.product.name} x {item.quantity}</div>
433
+ <h2>
434
+ Total: {currency} {(amountTotal / 100).toFixed(2)}
435
+ </h2>
436
+ {lineItems?.map((item) => (
437
+ <div key={item.id}>
438
+ {item.price.product.name} x {item.quantity}
439
+ </div>
426
440
  ))}
427
441
  <button onClick={() => confirm({ customerDetails: { email } })}>Pay</button>
428
442
  </div>
@@ -438,22 +452,22 @@ Override the session's `brandingSettings` at runtime:
438
452
  const checkout = await xpay.initCheckout({
439
453
  clientSecret,
440
454
  appearance: {
441
- colorMode: 'dark',
442
- borderStyle: 'pill',
443
- inputStyle: 'filled',
444
- colors: { primary: '#FF6B35' },
455
+ colorMode: "dark",
456
+ borderStyle: "pill",
457
+ inputStyle: "filled",
458
+ colors: { primary: "#FF6B35" },
445
459
  },
446
460
  });
447
461
 
448
462
  // Update later with changeAppearance()
449
- checkout.changeAppearance({ colorMode: 'light' });
463
+ checkout.changeAppearance({ colorMode: "light" });
450
464
  ```
451
465
 
452
466
  With the classic API:
453
467
 
454
468
  ```javascript
455
- const elements = xpay.elements({ clientSecret, appearance: { colorMode: 'dark' } });
456
- elements.changeAppearance({ colorMode: 'light' });
469
+ const elements = xpay.elements({ clientSecret, appearance: { colorMode: "dark" } });
470
+ elements.changeAppearance({ colorMode: "light" });
457
471
  ```
458
472
 
459
473
  ## API Reference
@@ -463,8 +477,8 @@ elements.changeAppearance({ colorMode: 'light' });
463
477
  Loads the XPay SDK from CDN. Returns a Promise. Call at module level, not inside components.
464
478
 
465
479
  ```javascript
466
- import { loadXPay } from '@xpayeg/sdk';
467
- const xpay = await loadXPay('pk_test_xxx');
480
+ import { loadXPay } from "@xpayeg/sdk";
481
+ const xpay = await loadXPay("pk_test_xxx");
468
482
  ```
469
483
 
470
484
  ### `xpay.initCheckout(options)`
@@ -473,9 +487,9 @@ Initialize a checkout session. Resolves with a merged object containing session
473
487
 
474
488
  ```javascript
475
489
  const checkout = await xpay.initCheckout({
476
- clientSecret: 'cs_test_abc_secret_xyz', // string | Promise<string>
477
- appearance: { colorMode: 'dark' },
478
- locale: 'ar',
490
+ clientSecret: "cs_test_abc_secret_xyz", // string | Promise<string>
491
+ appearance: { colorMode: "dark" },
492
+ locale: "ar",
479
493
  });
480
494
 
481
495
  // Session fields: status, canConfirm, amountTotal, currency, paymentMethods, lineItems, totalDetails, ...
@@ -501,10 +515,20 @@ Full TypeScript support with all types exported:
501
515
 
502
516
  ```typescript
503
517
  import type {
504
- XPayInstance, Elements, PaymentMethodInfo,
505
- CheckoutSession, SessionStatus, CustomerDetails, Appearance,
506
- InitCheckoutResult, CheckoutActions,
507
- ActionResult, XPayError,
508
- CheckoutLineItem, CheckoutTotalDetails, CheckoutFees, CheckoutDiscount,
509
- } from '@xpayeg/sdk';
518
+ XPayInstance,
519
+ Elements,
520
+ PaymentMethodInfo,
521
+ CheckoutSession,
522
+ SessionStatus,
523
+ CustomerDetails,
524
+ Appearance,
525
+ InitCheckoutResult,
526
+ CheckoutActions,
527
+ ActionResult,
528
+ XPayError,
529
+ CheckoutLineItem,
530
+ CheckoutTotalDetails,
531
+ CheckoutFees,
532
+ CheckoutDiscount,
533
+ } from "@xpayeg/sdk";
510
534
  ```
package/dist/index.cjs CHANGED
@@ -1,5 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- //#region src/index.ts
3
2
  const DEFAULT_SDK_URL = "https://checkout.xpay.app/v1/sdk.js";
4
3
  let loadPromise = null;
5
4
  /**
@@ -95,5 +94,4 @@ function findExistingScript() {
95
94
  } catch {}
96
95
  return null;
97
96
  }
98
- //#endregion
99
97
  exports.loadXPay = loadXPay;
package/dist/index.mjs CHANGED
@@ -1,4 +1,3 @@
1
- //#region src/index.ts
2
1
  const DEFAULT_SDK_URL = "https://checkout.xpay.app/v1/sdk.js";
3
2
  let loadPromise = null;
4
3
  /**
@@ -94,5 +93,4 @@ function findExistingScript() {
94
93
  } catch {}
95
94
  return null;
96
95
  }
97
- //#endregion
98
96
  export { loadXPay };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xpayeg/sdk",
3
- "version": "2.4.0",
3
+ "version": "3.0.0",
4
4
  "description": "XPay JavaScript SDK — loader and TypeScript types for embedding XPay payments",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -10,15 +10,15 @@
10
10
  },
11
11
  "main": "./dist/index.cjs",
12
12
  "module": "./dist/index.mjs",
13
- "types": "./dist/index.d.mts",
13
+ "types": "./.types/index.d.mts",
14
14
  "exports": {
15
15
  ".": {
16
16
  "import": {
17
- "types": "./dist/index.d.mts",
17
+ "types": "./.types/index.d.mts",
18
18
  "default": "./dist/index.mjs"
19
19
  },
20
20
  "require": {
21
- "types": "./dist/index.d.cts",
21
+ "types": "./.types/index.d.cts",
22
22
  "default": "./dist/index.cjs"
23
23
  }
24
24
  }
@@ -27,22 +27,14 @@
27
27
  "access": "public"
28
28
  },
29
29
  "files": [
30
- "dist",
30
+ "dist/index.mjs",
31
+ "dist/index.cjs",
31
32
  "README.md",
32
33
  "CHANGELOG.md",
33
- "LICENSE"
34
+ "LICENSE",
35
+ ".types/index.d.mts",
36
+ ".types/index.d.cts"
34
37
  ],
35
- "devDependencies": {
36
- "@arethetypeswrong/cli": "^0.18.2",
37
- "@rollup/plugin-node-resolve": "^16.0.3",
38
- "publint": "^0.3.21",
39
- "rollup": "^4.60.4",
40
- "rollup-plugin-dts": "^6.4.1",
41
- "tsdown": "^0.22.0",
42
- "typescript": "5.9.3",
43
- "@xpay/checkout-api": "0.0.0",
44
- "@xpay/tsconfig": "0.0.0"
45
- },
46
38
  "repository": {
47
39
  "type": "git",
48
40
  "url": "git+https://github.com/xpayeg/xpay-js.git"
@@ -57,10 +49,5 @@
57
49
  "egypt",
58
50
  "checkout",
59
51
  "sdk"
60
- ],
61
- "scripts": {
62
- "build": "tsdown && rollup -c rollup.dts.config.mjs",
63
- "lint:pkg": "publint && attw --pack .",
64
- "typecheck": "tsc --noEmit"
65
- }
52
+ ]
66
53
  }