@zendfi/sdk 1.0.2 → 1.1.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/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  processWebhook
3
- } from "./chunk-3ACJUM6V.mjs";
3
+ } from "./chunk-6CFQXFNR.mjs";
4
4
  import {
5
5
  DevTools,
6
6
  PerformanceMonitor,
@@ -8,7 +8,7 @@ import {
8
8
  TransactionPoller,
9
9
  WalletConnector,
10
10
  createWalletHook
11
- } from "./chunk-DAJL2Q36.mjs";
11
+ } from "./chunk-B5LO34Q6.mjs";
12
12
  import {
13
13
  __require
14
14
  } from "./chunk-Y6FXYEAI.mjs";
@@ -145,12 +145,12 @@ var ConfigLoader = class {
145
145
  const env = this.detectEnvironment();
146
146
  if (mode === "live" && env === "development") {
147
147
  console.warn(
148
- "\u26A0\uFE0F Warning: Using a live API key (zfi_live_) in development environment. This will create real mainnet transactions. Use a test key (zfi_test_) for devnet testing."
148
+ "Warning: Using a live API key (zfi_live_) in development environment. This will create real mainnet transactions. Use a test key (zfi_test_) for devnet testing."
149
149
  );
150
150
  }
151
151
  if (mode === "test" && env === "production") {
152
152
  console.warn(
153
- "\u26A0\uFE0F Warning: Using a test API key (zfi_test_) in production environment. This will create devnet transactions only. Use a live key (zfi_live_) for mainnet."
153
+ "Warning: Using a test API key (zfi_test_) in production environment. This will create devnet transactions only. Use a live key (zfi_live_) for mainnet."
154
154
  );
155
155
  }
156
156
  }
@@ -252,10 +252,10 @@ var ZendFiError2 = class _ZendFiError extends Error {
252
252
  let message = `[${this.code}] ${this.message}`;
253
253
  if (this.suggestion) {
254
254
  message += `
255
- \u{1F4A1} Suggestion: ${this.suggestion}`;
255
+ Suggestion: ${this.suggestion}`;
256
256
  }
257
257
  message += `
258
- \u{1F4DA} Docs: ${this.docs_url}`;
258
+ Docs: ${this.docs_url}`;
259
259
  return message;
260
260
  }
261
261
  /**
@@ -279,7 +279,7 @@ var AuthenticationError2 = class extends ZendFiError2 {
279
279
  code,
280
280
  message,
281
281
  type: "authentication_error",
282
- suggestion: suggestion || "Check your API key in the dashboard at https://app.zendfi.com/settings/api-keys",
282
+ suggestion: suggestion || "Check your API key in the dashboard at https://dashboard.zendfi.tech",
283
283
  statusCode: 401
284
284
  });
285
285
  this.name = "AuthenticationError";
@@ -387,25 +387,19 @@ function createZendFiError(statusCode, responseBody, message) {
387
387
  return new ApiError(errorMessage, errorCode, statusCode, responseBody);
388
388
  }
389
389
  var ERROR_CODES = {
390
- // Authentication
391
390
  INVALID_API_KEY: "invalid_api_key",
392
391
  API_KEY_EXPIRED: "api_key_expired",
393
392
  API_KEY_REVOKED: "api_key_revoked",
394
- // Payment
395
393
  INSUFFICIENT_BALANCE: "insufficient_balance",
396
394
  PAYMENT_DECLINED: "payment_declined",
397
395
  PAYMENT_EXPIRED: "payment_expired",
398
396
  INVALID_AMOUNT: "invalid_amount",
399
397
  INVALID_CURRENCY: "invalid_currency",
400
- // Validation
401
398
  MISSING_REQUIRED_FIELD: "missing_required_field",
402
399
  INVALID_PARAMETER: "invalid_parameter",
403
- // Network
404
400
  NETWORK_ERROR: "network_error",
405
401
  TIMEOUT: "timeout",
406
- // Rate limiting
407
402
  RATE_LIMIT_EXCEEDED: "rate_limit_exceeded",
408
- // Webhook
409
403
  WEBHOOK_SIGNATURE_INVALID: "webhook_signature_invalid",
410
404
  WEBHOOK_TIMESTAMP_TOO_OLD: "webhook_timestamp_too_old"
411
405
  };
@@ -932,6 +926,18 @@ function verifyWebhookSignature(payload, signature, secret) {
932
926
  }
933
927
 
934
928
  // src/embedded-checkout.ts
929
+ var Icons = {
930
+ clipboard: `<svg class="icon" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 01-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 011.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 00-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 01-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 00-3.375-3.375h-1.5a1.125 1.125 0 01-1.125-1.125v-1.5a3.375 3.375 0 00-3.375-3.375H9.75" /></svg>`,
931
+ checkCircle: `<svg class="icon icon-lg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>`,
932
+ xCircle: `<svg class="icon icon-lg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9.75 9.75l4.5 4.5m0-4.5l-4.5 4.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>`,
933
+ check: `<svg class="icon icon-sm" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" /></svg>`,
934
+ refresh: `<svg class="icon icon-sm" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" /></svg>`,
935
+ clock: `<svg class="icon icon-sm" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>`,
936
+ loader: `<svg class="icon icon-spin" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="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"></path></svg>`,
937
+ bank: `<svg class="icon" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 21v-8.25M15.75 21v-8.25M8.25 21v-8.25M3 9l9-6 9 6m-1.5 12V10.332A48.36 48.36 0 0012 9.75c-2.551 0-5.056.2-7.5.582V21M3 21h18M12 6.75h.008v.008H12V6.75z" /></svg>`,
938
+ clocklg: `<svg class="icon icon-lg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>`,
939
+ hammer: `<svg class="icon" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M11.42 15.17L17.25 21A2.652 2.652 0 0021 17.25l-5.877-5.877M11.42 15.17l2.496-3.03c.317-.384.74-.626 1.208-.766M11.42 15.17l-4.655 5.653a2.548 2.548 0 11-3.586-3.586l6.837-5.63m5.108-.233c.55-.164 1.163-.188 1.743-.14a4.5 4.5 0 004.486-6.336l-3.276 3.277a3.004 3.004 0 01-2.25-2.25l3.276-3.276a4.5 4.5 0 00-6.336 4.486c.091 1.076-.071 2.264-.904 2.95l-.102.085m-1.745 1.437L5.909 7.5H4.5L2.25 3.75l1.5-1.5L7.5 4.5v1.409l4.26 4.26m-1.745 1.437l1.745-1.437m6.615 8.206L15.75 15.75M4.867 19.125h.008v.008h-.008v-.008z" /></svg>`
940
+ };
935
941
  var ZendFiEmbeddedCheckout = class {
936
942
  config;
937
943
  container = null;
@@ -939,8 +945,6 @@ var ZendFiEmbeddedCheckout = class {
939
945
  pollInterval = null;
940
946
  mounted = false;
941
947
  paymentProcessed = false;
942
- // Prevent duplicate success callbacks
943
- // Bank payment state
944
948
  bankPaymentState = {};
945
949
  constructor(config) {
946
950
  this.config = {
@@ -1154,13 +1158,28 @@ var ZendFiEmbeddedCheckout = class {
1154
1158
  */
1155
1159
  renderHeader() {
1156
1160
  if (!this.checkoutData) return "";
1161
+ const testnetBadge = this.checkoutData.solana_network === "devnet" || this.checkoutData.solana_network === "testnet" ? `<span style="font-size: 9px; font-weight: 500; color: #d97706; background: #fef3c7; padding: 2px 6px; border-radius: 4px; margin-left: 6px;">Testnet</span>` : "";
1157
1162
  return `
1158
- <div class="zendfi-checkout-header" style="padding: 24px; border-bottom: 1px solid #e5e7eb;">
1159
- <h2 style="margin: 0; font-size: 24px; font-weight: 600; color: ${this.config.theme.textColor || "#1f2937"};">
1160
- Pay ${this.checkoutData.merchant_name}
1161
- </h2>
1163
+ <div class="zendfi-checkout-header" style="padding: 24px; text-align: center; border-bottom: 1px solid #e5e7eb;">
1164
+ <!-- Merchant Badge -->
1165
+ <div style="display: inline-flex; items-center; gap: 8px; padding: 6px 12px; background: white; border: 1px solid #e5e7eb; border-radius: 20px; margin-bottom: 16px;">
1166
+ <div style="width: 20px; height: 20px; border-radius: 50%; background: #1f2937; display: flex; align-items: center; justify-content: center;">
1167
+ <span style="font-size: 10px; font-weight: 600; color: white;">
1168
+ ${this.checkoutData.merchant_name.charAt(0).toUpperCase()}
1169
+ </span>
1170
+ </div>
1171
+ <span style="font-size: 12px; font-weight: 500; color: #374151;">${this.checkoutData.merchant_name}</span>
1172
+ ${testnetBadge}
1173
+ </div>
1174
+
1175
+ <!-- Amount -->
1176
+ <div style="font-size: 40px; font-weight: 600; color: #1f2937; margin-bottom: 4px;">
1177
+ $${this.checkoutData.amount_usd.toFixed(2)}
1178
+ </div>
1179
+ <p style="margin: 0; font-size: 13px; color: #6b7280;">${this.checkoutData.token} on Solana</p>
1180
+
1162
1181
  ${this.checkoutData.description ? `
1163
- <p style="margin: 8px 0 0 0; color: #6b7280; font-size: 14px;">
1182
+ <p style="margin: 12px auto 0; color: #9ca3af; font-size: 13px; max-width: 280px;">
1164
1183
  ${this.checkoutData.description}
1165
1184
  </p>
1166
1185
  ` : ""}
@@ -1244,21 +1263,22 @@ var ZendFiEmbeddedCheckout = class {
1244
1263
  renderQRCodeMethod() {
1245
1264
  if (!this.checkoutData) return "";
1246
1265
  return `
1247
- <div class="zendfi-payment-method" style="padding: 16px; border: 1px solid #e5e7eb; border-radius: 12px; margin-bottom: 16px;">
1266
+ <div class="zendfi-payment-method" style="padding: 20px; border: 1px solid #e5e7eb; border-radius: 12px; margin-bottom: 16px; background: white; transition: all 0.2s;" onmouseover="this.style.borderColor='#d1d5db'; this.style.boxShadow='0 2px 8px rgba(0,0,0,0.05)';" onmouseout="this.style.borderColor='#e5e7eb'; this.style.boxShadow='none';">
1248
1267
  <div style="text-align: center;">
1249
- <p style="font-size: 14px; color: #6b7280; margin-bottom: 16px;">
1250
- Scan with Solana wallet
1268
+ <h4 style="margin: 0 0 12px 0; font-size: 15px; font-weight: 600; color: #374151;">Scan QR Code</h4>
1269
+ <p style="font-size: 13px; color: #6b7280; margin-bottom: 16px;">
1270
+ Use any Solana wallet app
1251
1271
  </p>
1252
- <div id="zendfi-qr-container" style="display: flex; justify-content: center; margin-bottom: 16px;">
1272
+ <div id="zendfi-qr-container" style="display: flex; justify-content: center; margin-bottom: 16px; padding: 12px; background: #fafbfc; border-radius: 8px;">
1253
1273
  <canvas id="zendfi-qr-code"></canvas>
1254
1274
  </div>
1255
1275
  <button
1256
1276
  id="zendfi-copy-address"
1257
- style="padding: 10px 20px; background: #f3f4f6; border: 1px solid #d1d5db; border-radius: 8px; cursor: pointer; font-size: 14px; color: #374151; transition: all 0.2s;"
1277
+ style="padding: 10px 20px; background: #f3f4f6; border: 1px solid #d1d5db; border-radius: 8px; cursor: pointer; font-size: 14px; color: #374151; font-weight: 500; transition: all 0.2s; display: inline-flex; align-items: center; gap: 6px;"
1258
1278
  onmouseover="this.style.background='#e5e7eb'"
1259
1279
  onmouseout="this.style.background='#f3f4f6'"
1260
1280
  >
1261
- \u{1F4CB} Copy Address
1281
+ ${Icons.clipboard} Copy Address
1262
1282
  </button>
1263
1283
  </div>
1264
1284
  </div>
@@ -1268,15 +1288,16 @@ var ZendFiEmbeddedCheckout = class {
1268
1288
  * Render browser wallet method
1269
1289
  */
1270
1290
  renderWalletMethod() {
1291
+ const walletIcon = `<svg style="width: 20px; height: 20px; display: inline-block; vertical-align: middle; margin-right: 8px;" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21 12a2.25 2.25 0 00-2.25-2.25H15a3 3 0 11-6 0H5.25A2.25 2.25 0 003 12m18 0v6a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 18v-6m18 0V9M3 12V9m18 0a2.25 2.25 0 00-2.25-2.25H5.25A2.25 2.25 0 003 9m18 0V6a2.25 2.25 0 00-2.25-2.25H5.25A2.25 2.25 0 003 6v3" /></svg>`;
1271
1292
  return `
1272
1293
  <div class="zendfi-payment-method" style="margin-bottom: 16px;">
1273
1294
  <button
1274
1295
  id="zendfi-connect-wallet"
1275
- style="width: 100%; padding: 16px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; border-radius: 12px; font-size: 16px; font-weight: 600; cursor: pointer; transition: transform 0.2s, box-shadow 0.2s; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);"
1276
- onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 6px 12px rgba(0, 0, 0, 0.15)';"
1277
- onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='0 4px 6px rgba(0, 0, 0, 0.1)';"
1296
+ style="width: 100%; padding: 16px; background: #1f2937; color: white; border: none; border-radius: 12px; font-size: 16px; font-weight: 600; cursor: pointer; transition: all 0.2s; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); display: flex; align-items: center; justify-content: center;"
1297
+ onmouseover="this.style.transform='translateY(-1px)'; this.style.boxShadow='0 4px 12px rgba(0, 0, 0, 0.15)'; this.style.background='#111827';"
1298
+ onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='0 2px 6px rgba(0, 0, 0, 0.1)'; this.style.background='#1f2937';"
1278
1299
  >
1279
- \u{1F517} Connect Wallet
1300
+ ${walletIcon} Connect Wallet
1280
1301
  </button>
1281
1302
  </div>
1282
1303
  `;
@@ -1285,15 +1306,16 @@ var ZendFiEmbeddedCheckout = class {
1285
1306
  * Render WalletConnect method
1286
1307
  */
1287
1308
  renderWalletConnectMethod() {
1309
+ const qrIcon = `<svg style="width: 20px; height: 20px; display: inline-block; vertical-align: middle; margin-right: 8px;" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 4.875c0-.621.504-1.125 1.125-1.125h4.5c.621 0 1.125.504 1.125 1.125v4.5c0 .621-.504 1.125-1.125 1.125h-4.5A1.125 1.125 0 013.75 9.375v-4.5zM3.75 14.625c0-.621.504-1.125 1.125-1.125h4.5c.621 0 1.125.504 1.125 1.125v4.5c0 .621-.504 1.125-1.125 1.125h-4.5a1.125 1.125 0 01-1.125-1.125v-4.5zM13.5 4.875c0-.621.504-1.125 1.125-1.125h4.5c.621 0 1.125.504 1.125 1.125v4.5c0 .621-.504 1.125-1.125 1.125h-4.5A1.125 1.125 0 0113.5 9.375v-4.5z" /><path stroke-linecap="round" stroke-linejoin="round" d="M6.75 6.75h.75v.75h-.75v-.75zM6.75 16.5h.75v.75h-.75v-.75zM16.5 6.75h.75v.75h-.75v-.75zM13.5 13.5h.75v.75h-.75v-.75zM13.5 19.5h.75v.75h-.75v-.75zM19.5 13.5h.75v.75h-.75v-.75zM19.5 19.5h.75v.75h-.75v-.75zM16.5 16.5h.75v.75h-.75v-.75z" /></svg>`;
1288
1310
  return `
1289
- <div class="zendfi-payment-method">
1311
+ <div class="zendfi-payment-method" style="margin-bottom: 16px;">
1290
1312
  <button
1291
1313
  id="zendfi-wallet-connect"
1292
- style="width: 100%; padding: 16px; background: white; color: #1f2937; border: 2px solid #e5e7eb; border-radius: 12px; font-size: 16px; font-weight: 600; cursor: pointer; transition: all 0.2s;"
1293
- onmouseover="this.style.borderColor='#667eea'; this.style.background='#f9fafb';"
1294
- onmouseout="this.style.borderColor='#e5e7eb'; this.style.background='white';"
1314
+ style="width: 100%; padding: 16px; background: white; color: #1f2937; border: 2px solid #d1d5db; border-radius: 12px; font-size: 16px; font-weight: 600; cursor: pointer; transition: all 0.2s; display: flex; align-items: center; justify-content: center;"
1315
+ onmouseover="this.style.borderColor='#9ca3af'; this.style.background='#f9fafb';"
1316
+ onmouseout="this.style.borderColor='#d1d5db'; this.style.background='white';"
1295
1317
  >
1296
- \u{1F4F1} WalletConnect
1318
+ ${qrIcon} WalletConnect
1297
1319
  </button>
1298
1320
  </div>
1299
1321
  `;
@@ -1306,13 +1328,13 @@ var ZendFiEmbeddedCheckout = class {
1306
1328
  const isEmailStep = !this.bankPaymentState.orderId;
1307
1329
  const isBankDetailsStep = !!this.bankPaymentState.bankDetails;
1308
1330
  return `
1309
- <div class="zendfi-payment-method" style="padding: 16px; border: 2px solid #10b981; border-radius: 12px; margin-bottom: 16px; background: #f0fdf4;">
1331
+ <div class="zendfi-payment-method" style="padding: 20px; border: 2px solid #10b981; border-radius: 12px; margin-bottom: 16px; background: #f0fdf4; transition: all 0.2s;" onmouseover="this.style.boxShadow='0 2px 8px rgba(16,185,129,0.15)';" onmouseout="this.style.boxShadow='none';">
1310
1332
  <div style="margin-bottom: 12px;">
1311
- <h4 style="margin: 0 0 4px 0; font-size: 16px; font-weight: 600; color: #065f46; display: flex; align-items: center;">
1312
- \u{1F3E6} Pay with Bank Transfer (Nigeria)
1333
+ <h4 style="margin: 0 0 4px 0; font-size: 16px; font-weight: 600; color: #065f46; display: flex; align-items: center; gap: 8px;">
1334
+ ${Icons.bank} Pay with Bank Transfer
1313
1335
  </h4>
1314
- <p style="margin: 0; font-size: 12px; color: #047857;">
1315
- Pay with your Nigerian bank account \u2022 Instant confirmation
1336
+ <p style="margin: 0; font-size: 13px; color: #047857;">
1337
+ Nigerian bank account \u2022 Instant confirmation
1316
1338
  </p>
1317
1339
  </div>
1318
1340
 
@@ -1377,8 +1399,8 @@ var ZendFiEmbeddedCheckout = class {
1377
1399
  return `
1378
1400
  <div id="zendfi-bank-details-step">
1379
1401
  <div style="background: white; border: 1px solid #d1d5db; border-radius: 8px; padding: 16px; margin-bottom: 16px;">
1380
- <h5 style="margin: 0 0 12px 0; font-size: 14px; font-weight: 600; color: #374151;">
1381
- \u{1F4CB} Transfer to this account:
1402
+ <h5 style="margin: 0 0 12px 0; font-size: 14px; font-weight: 600; color: #374151; display: flex; align-items: center; gap: 6px;">
1403
+ ${Icons.bank} Transfer to this account:
1382
1404
  </h5>
1383
1405
 
1384
1406
  <div style="margin-bottom: 8px;">
@@ -1421,14 +1443,14 @@ var ZendFiEmbeddedCheckout = class {
1421
1443
  <div style="color: #6b7280; font-size: 14px;" id="zendfi-bank-status-text">
1422
1444
  Waiting for bank transfer... (<span id="zendfi-bank-timer">0:00</span>)
1423
1445
  </div>
1424
- <div style="font-size: 12px; color: #9ca3af; margin-top: 4px;">
1425
- \u23F1\uFE0F Usually takes 10-30 seconds
1446
+ <div style="font-size: 12px; color: #9ca3af; margin-top: 4px; display: inline-flex; align-items: center; gap: 4px;">
1447
+ ${Icons.clock} Usually takes 10-30 seconds
1426
1448
  </div>
1427
1449
  <button
1428
1450
  id="zendfi-refresh-status"
1429
- style="margin-top: 12px; padding: 8px 16px; background: white; border: 1px solid #e5e7eb; border-radius: 8px; cursor: pointer; color: #6b7280; font-size: 14px;"
1451
+ style="margin-top: 12px; padding: 8px 16px; background: white; border: 1px solid #e5e7eb; border-radius: 8px; cursor: pointer; color: #6b7280; font-size: 14px; display: inline-flex; align-items: center; gap: 6px;"
1430
1452
  >
1431
- \u{1F504} Refresh Status
1453
+ ${Icons.refresh} Refresh Status
1432
1454
  </button>
1433
1455
  </div>
1434
1456
  </div>
@@ -1438,10 +1460,13 @@ var ZendFiEmbeddedCheckout = class {
1438
1460
  * Render footer
1439
1461
  */
1440
1462
  renderFooter() {
1463
+ const lockIcon = `<svg style="width: 14px; height: 14px; display: inline-block; vertical-align: middle; margin-right: 4px;" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z" /></svg>`;
1441
1464
  return `
1442
1465
  <div class="zendfi-checkout-footer" style="padding: 16px 24px; border-top: 1px solid #e5e7eb; text-align: center;">
1443
- <p style="margin: 0; font-size: 12px; color: #9ca3af;">
1444
- Powered by <a href="https://zendfi.tech" target="_blank" style="color: #667eea; text-decoration: none; font-weight: 600;">ZendFi</a>
1466
+ <p style="margin: 0; font-size: 12px; color: #9ca3af; display: flex; align-items: center; justify-content: center; gap: 4px;">
1467
+ ${lockIcon}
1468
+ <span>Secured by</span>
1469
+ <a href="https://zendfi.tech" target="_blank" style="color: #667eea; text-decoration: none; font-weight: 600; transition: opacity 0.2s;" onmouseover="this.style.opacity='0.7'" onmouseout="this.style.opacity='1'">ZendFi</a>
1445
1470
  </p>
1446
1471
  </div>
1447
1472
  `;
@@ -1453,7 +1478,7 @@ var ZendFiEmbeddedCheckout = class {
1453
1478
  if (!this.container) return;
1454
1479
  this.container.innerHTML = `
1455
1480
  <div class="zendfi-checkout-success" style="${this.getSuccessStyles()}">
1456
- <div style="font-size: 64px; margin-bottom: 16px;">\u2705</div>
1481
+ <div style="color: #10b981; margin-bottom: 16px;">${Icons.checkCircle}</div>
1457
1482
  <h3 style="margin: 0 0 8px 0; font-size: 24px; font-weight: 600; color: #059669;">
1458
1483
  Payment Successful!
1459
1484
  </h3>
@@ -1463,6 +1488,91 @@ var ZendFiEmbeddedCheckout = class {
1463
1488
  </div>
1464
1489
  `;
1465
1490
  }
1491
+ /**
1492
+ * Render payment under review state
1493
+ */
1494
+ renderUnderReview() {
1495
+ if (!this.container) return;
1496
+ const customerEmail = this.bankPaymentState.customerEmail || "unknown";
1497
+ const orderId = this.bankPaymentState.orderId || "N/A";
1498
+ this.container.innerHTML = `
1499
+ <div class="zendfi-checkout-under-review" style="padding: 32px 24px; text-align: center;">
1500
+ <div style="width: 64px; height: 64px; background: #fef3c7; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 16px; color: #d97706;">
1501
+ ${Icons.clock}
1502
+ </div>
1503
+
1504
+ <h3 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #1f2937;">
1505
+ Payment Under Review
1506
+ </h3>
1507
+ <p style="margin: 0 0 24px 0; color: #6b7280; font-size: 14px; line-height: 1.5;">
1508
+ We're still processing your bank transfer. This is taking longer than usual.
1509
+ </p>
1510
+
1511
+ <!-- What's Happening -->
1512
+ <div style="background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 12px; padding: 16px; margin-bottom: 16px; text-align: left;">
1513
+ <h4 style="margin: 0 0 12px 0; font-size: 14px; font-weight: 600; color: #1e3a8a;">What's happening?</h4>
1514
+ <ul style="margin: 0; padding: 0 0 0 20px; font-size: 13px; color: #1e40af; line-height: 1.6;">
1515
+ <li style="margin-bottom: 8px;">Our team has been notified and is investigating</li>
1516
+ <li style="margin-bottom: 8px;">We're coordinating with our payment partner</li>
1517
+ <li>You'll receive an update via email within 24 hours</li>
1518
+ </ul>
1519
+ </div>
1520
+
1521
+ <!-- Guarantee -->
1522
+ <div style="background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 12px; padding: 16px; margin-bottom: 16px; text-align: left;">
1523
+ <div style="display: flex; align-items: start; gap: 12px;">
1524
+ <div style="color: #16a34a; flex-shrink: 0;">${Icons.checkCircle}</div>
1525
+ <div>
1526
+ <h4 style="margin: 0 0 4px 0; font-size: 14px; font-weight: 600; color: #15803d;">You're Protected</h4>
1527
+ <p style="margin: 0; font-size: 13px; color: #166534; line-height: 1.5;">
1528
+ If we can't deliver your USDC, you'll receive a <strong>full refund</strong> to your bank account within 3-5 business days.
1529
+ </p>
1530
+ </div>
1531
+ </div>
1532
+ </div>
1533
+
1534
+ <!-- Contact Support -->
1535
+ <div style="background: #f9fafb; border-radius: 12px; padding: 16px; text-align: left;">
1536
+ <h4 style="margin: 0 0 8px 0; font-size: 14px; font-weight: 600; color: #1f2937;">Need help?</h4>
1537
+ <p style="margin: 0 0 12px 0; font-size: 13px; color: #6b7280;">
1538
+ Contact our support team if you have questions:
1539
+ </p>
1540
+ <a
1541
+ href="mailto:tosinoyinboblessed@gmail.com?subject=Payment%20Review%20-%20${orderId}&body=Order%20ID:%20${orderId}%0AEmail:%20${customerEmail}"
1542
+ style="display: block; width: 100%; padding: 12px; background: #1f2937; color: white; text-decoration: none; border-radius: 8px; font-size: 14px; font-weight: 600; text-align: center; transition: background 0.2s;"
1543
+ onmouseover="this.style.background='#111827'"
1544
+ onmouseout="this.style.background='#1f2937'"
1545
+ >
1546
+ Email Support
1547
+ </a>
1548
+ <p style="margin: 12px 0 0 0; font-size: 12px; color: #9ca3af; text-align: center;">
1549
+ Reference: ${orderId.slice(0, 8)}
1550
+ </p>
1551
+ </div>
1552
+ </div>
1553
+ `;
1554
+ }
1555
+ /**
1556
+ * Handle payment timeout (15 minutes)
1557
+ */
1558
+ handlePaymentTimeout() {
1559
+ if (this.bankPaymentState.pollingInterval) {
1560
+ clearInterval(this.bankPaymentState.pollingInterval);
1561
+ this.bankPaymentState.pollingInterval = void 0;
1562
+ }
1563
+ if (this.bankPaymentState.timerInterval) {
1564
+ clearInterval(this.bankPaymentState.timerInterval);
1565
+ }
1566
+ this.renderUnderReview();
1567
+ this.config.onError({
1568
+ code: "PAYMENT_TIMEOUT",
1569
+ message: "Payment is taking longer than expected and is now under review",
1570
+ details: {
1571
+ orderId: this.bankPaymentState.orderId,
1572
+ customerEmail: this.bankPaymentState.customerEmail
1573
+ }
1574
+ });
1575
+ }
1466
1576
  /**
1467
1577
  * Render error state
1468
1578
  */
@@ -1470,7 +1580,7 @@ var ZendFiEmbeddedCheckout = class {
1470
1580
  if (!this.container) return;
1471
1581
  this.container.innerHTML = `
1472
1582
  <div class="zendfi-checkout-error" style="${this.getErrorStyles()}">
1473
- <div style="font-size: 64px; margin-bottom: 16px;">\u274C</div>
1583
+ <div style="color: #ef4444; margin-bottom: 16px;">${Icons.xCircle}</div>
1474
1584
  <h3 style="margin: 0 0 8px 0; font-size: 24px; font-weight: 600; color: #dc2626;">
1475
1585
  Payment Failed
1476
1586
  </h3>
@@ -1492,9 +1602,9 @@ var ZendFiEmbeddedCheckout = class {
1492
1602
  if (copyBtn && this.checkoutData) {
1493
1603
  copyBtn.addEventListener("click", () => {
1494
1604
  navigator.clipboard.writeText(this.checkoutData.wallet_address);
1495
- copyBtn.textContent = "\u2713 Copied!";
1605
+ copyBtn.innerHTML = `${Icons.check} Copied!`;
1496
1606
  setTimeout(() => {
1497
- copyBtn.textContent = "\u{1F4CB} Copy Address";
1607
+ copyBtn.innerHTML = `${Icons.clipboard} Copy Address`;
1498
1608
  }, 2e3);
1499
1609
  });
1500
1610
  }
@@ -1542,13 +1652,13 @@ var ZendFiEmbeddedCheckout = class {
1542
1652
  }
1543
1653
  const connectBtn = document.getElementById("zendfi-connect-wallet");
1544
1654
  if (connectBtn) {
1545
- connectBtn.textContent = "\u{1F504} Connecting...";
1655
+ connectBtn.innerHTML = `${Icons.loader} Connecting...`;
1546
1656
  connectBtn.disabled = true;
1547
1657
  }
1548
1658
  await provider.connect();
1549
1659
  const publicKey = provider.publicKey.toString();
1550
1660
  if (connectBtn) {
1551
- connectBtn.textContent = "\u{1F528} Building transaction...";
1661
+ connectBtn.innerHTML = `${Icons.hammer} Building transaction...`;
1552
1662
  }
1553
1663
  const response = await fetch(
1554
1664
  `${this.config.apiUrl}/api/v1/payments/${this.checkoutData.payment_id}/build-transaction`,
@@ -1566,14 +1676,14 @@ var ZendFiEmbeddedCheckout = class {
1566
1676
  }
1567
1677
  const { transaction: transactionBase64, is_gasless } = await response.json();
1568
1678
  if (connectBtn) {
1569
- connectBtn.textContent = "\u270D\uFE0F Sign transaction...";
1679
+ connectBtn.innerHTML = `${Icons.loader} Signing...`;
1570
1680
  }
1571
1681
  const solanaWeb3 = window.solanaWeb3;
1572
1682
  const transactionBuffer = Uint8Array.from(atob(transactionBase64), (c) => c.charCodeAt(0));
1573
1683
  const transaction = solanaWeb3.Transaction.from(transactionBuffer);
1574
1684
  const signedTransaction = await provider.signTransaction(transaction);
1575
1685
  if (connectBtn) {
1576
- connectBtn.textContent = "\u{1F4E1} Submitting...";
1686
+ connectBtn.innerHTML = `${Icons.loader} Submitting...`;
1577
1687
  }
1578
1688
  if (is_gasless) {
1579
1689
  const serialized = signedTransaction.serialize();
@@ -1613,13 +1723,13 @@ var ZendFiEmbeddedCheckout = class {
1613
1723
  }
1614
1724
  }
1615
1725
  if (connectBtn) {
1616
- connectBtn.textContent = "\u23F3 Confirming...";
1726
+ connectBtn.innerHTML = `${Icons.loader} Confirming...`;
1617
1727
  }
1618
1728
  } catch (error) {
1619
1729
  console.error("Wallet connection error:", error);
1620
1730
  const connectBtn = document.getElementById("zendfi-connect-wallet");
1621
1731
  if (connectBtn) {
1622
- connectBtn.textContent = "\u{1F517} Connect Wallet";
1732
+ connectBtn.textContent = "Connect Wallet";
1623
1733
  connectBtn.disabled = false;
1624
1734
  }
1625
1735
  this.config.onError({
@@ -1682,6 +1792,38 @@ var ZendFiEmbeddedCheckout = class {
1682
1792
  @keyframes zendfi-spin {
1683
1793
  to { transform: rotate(360deg); }
1684
1794
  }
1795
+
1796
+ .zendfi-embedded-checkout .icon {
1797
+ width: 20px;
1798
+ height: 20px;
1799
+ display: inline-block;
1800
+ vertical-align: middle;
1801
+ }
1802
+
1803
+ .zendfi-embedded-checkout .icon-sm {
1804
+ width: 16px;
1805
+ height: 16px;
1806
+ }
1807
+
1808
+ .zendfi-embedded-checkout .icon-lg {
1809
+ width: 64px;
1810
+ height: 64px;
1811
+ }
1812
+
1813
+ .zendfi-embedded-checkout .icon-spin {
1814
+ animation: zendfi-spin 0.8s linear infinite;
1815
+ width: 40px;
1816
+ height: 40px;
1817
+ }
1818
+
1819
+ .zendfi-spinner {
1820
+ width: 40px;
1821
+ height: 40px;
1822
+ border: 4px solid #f3f4f6;
1823
+ border-top-color: #667eea;
1824
+ border-radius: 50%;
1825
+ animation: zendfi-spin 0.8s linear infinite;
1826
+ }
1685
1827
  `;
1686
1828
  document.head.appendChild(style);
1687
1829
  }
@@ -1733,9 +1875,10 @@ var ZendFiEmbeddedCheckout = class {
1733
1875
  font-family: ${theme.fontFamily};
1734
1876
  background: ${theme.backgroundColor};
1735
1877
  border-radius: ${theme.borderRadius};
1736
- box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
1878
+ border: 1px solid #e5e7eb;
1879
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
1737
1880
  overflow: hidden;
1738
- max-width: 500px;
1881
+ max-width: 480px;
1739
1882
  margin: 0 auto;
1740
1883
  `.replace(/\s+/g, " ").trim();
1741
1884
  }
@@ -1792,7 +1935,9 @@ var ZendFiEmbeddedCheckout = class {
1792
1935
  otp,
1793
1936
  fiat_amount: this.checkoutData.amount_usd,
1794
1937
  currency: this.checkoutData.currency,
1795
- payment_link_id: this.checkoutData.payment_link_id
1938
+ payment_link_id: this.checkoutData.payment_link_id,
1939
+ amount_ngn: this.checkoutData.amount_ngn,
1940
+ payer_service_charge: this.checkoutData.payer_service_charge
1796
1941
  })
1797
1942
  });
1798
1943
  if (!response.ok) {
@@ -1822,7 +1967,8 @@ var ZendFiEmbeddedCheckout = class {
1822
1967
  body: JSON.stringify({
1823
1968
  customer_email: email,
1824
1969
  fiat_amount: this.checkoutData.amount_usd,
1825
- payment_link_id: this.checkoutData.payment_link_id
1970
+ payment_link_id: this.checkoutData.payment_link_id,
1971
+ amount_ngn: this.checkoutData.amount_ngn
1826
1972
  })
1827
1973
  });
1828
1974
  if (!response.ok) {
@@ -1848,6 +1994,7 @@ var ZendFiEmbeddedCheckout = class {
1848
1994
  startBankStatusPolling() {
1849
1995
  if (!this.bankPaymentState.orderId) return;
1850
1996
  let startTime = Date.now();
1997
+ const TIMEOUT_MS = 15 * 60 * 1e3;
1851
1998
  const timerInterval = setInterval(() => {
1852
1999
  const elapsed = Math.floor((Date.now() - startTime) / 1e3);
1853
2000
  const minutes = Math.floor(elapsed / 60);
@@ -1856,6 +2003,9 @@ var ZendFiEmbeddedCheckout = class {
1856
2003
  if (timerEl) {
1857
2004
  timerEl.textContent = `${minutes}:${seconds.toString().padStart(2, "0")}`;
1858
2005
  }
2006
+ if (Date.now() - startTime > TIMEOUT_MS) {
2007
+ this.handlePaymentTimeout();
2008
+ }
1859
2009
  }, 1e3);
1860
2010
  const pollInterval = setInterval(async () => {
1861
2011
  await this.checkBankPaymentStatus();
package/dist/nextjs.d.mts CHANGED
@@ -1,11 +1,10 @@
1
- import { W as WebhookHandlerConfig, a as WebhookHandlers } from './webhook-handler-61UWBtDI.mjs';
1
+ import { W as WebhookHandlerConfig, a as WebhookHandlers } from './webhook-handler-hUfWh-_Y.mjs';
2
2
 
3
3
  /**
4
4
  * Next.js Webhook Handler for App Router
5
5
  *
6
6
  * @example
7
7
  * ```typescript
8
- * // app/api/webhooks/zendfi/route.ts
9
8
  * import { createNextWebhookHandler } from '@zendfi/sdk/nextjs';
10
9
  *
11
10
  * export const POST = createNextWebhookHandler({
package/dist/nextjs.d.ts CHANGED
@@ -1,11 +1,10 @@
1
- import { W as WebhookHandlerConfig, a as WebhookHandlers } from './webhook-handler-61UWBtDI.js';
1
+ import { W as WebhookHandlerConfig, a as WebhookHandlers } from './webhook-handler-hUfWh-_Y.js';
2
2
 
3
3
  /**
4
4
  * Next.js Webhook Handler for App Router
5
5
  *
6
6
  * @example
7
7
  * ```typescript
8
- * // app/api/webhooks/zendfi/route.ts
9
8
  * import { createNextWebhookHandler } from '@zendfi/sdk/nextjs';
10
9
  *
11
10
  * export const POST = createNextWebhookHandler({
package/dist/nextjs.js CHANGED
@@ -150,7 +150,6 @@ async function processWebhook(a, b, c) {
150
150
  isProcessed: cfg.isProcessed,
151
151
  onProcessed: cfg.onProcessed,
152
152
  onError: cfg.onError,
153
- // Forward compatibility for alternate names and flags
154
153
  enableDeduplication: cfg.enableDeduplication,
155
154
  checkDuplicate: cfg.checkDuplicate,
156
155
  markProcessed: cfg.markProcessed
package/dist/nextjs.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  processWebhook
3
- } from "./chunk-3ACJUM6V.mjs";
3
+ } from "./chunk-6CFQXFNR.mjs";
4
4
  import "./chunk-Y6FXYEAI.mjs";
5
5
 
6
6
  // src/nextjs.ts