UNPKG

@cedros/pay-react

Version:

React frontend library for Cedros Pay - unified Stripe and Solana x402 payments

1,383 lines 56.4 kB
import { jsxs as E, jsx as S } from "react/jsx-runtime"; import { useState as F, useCallback as x, useMemo as W, useEffect as B, useRef as Ce } from "react"; import { g as m, u as fe, a as me, f as se } from "./CedrosContext-CFEXGwQg.mjs"; import { useWallet as De } from "@solana/wallet-adapter-react"; import { WalletReadyState as ke } from "@solana/wallet-adapter-base"; import { WalletIcon as Ge } from "@solana/wallet-adapter-react-ui"; import "@solana/wallet-adapter-wallets"; function wt(e) { return !e || !e.coupon_codes ? [] : e.coupon_codes.split(",").map((t) => t.trim()).filter((t) => t.length > 0); } function bt(e, t = ", ") { return e.join(t); } function vt(e, t) { return e <= 0 ? 0 : (e - t) / e * 100; } function It(e, t) { if (!t || t.length === 0) return e; let n = e, o = 0; for (const a of t) if (a.discountType === "percentage") { const r = 1 - a.discountValue / 100; n = n * r; } else a.discountType === "fixed" && (o += a.discountValue); return n = n - o, n < 0 && (n = 0), Math.ceil(n * 100) / 100; } function Ee(e) { const t = Number(e); if (!Number.isFinite(t) || t <= 0) return 1; const n = Math.floor(t); return n > 0 ? n : 1; } function Oe(e) { return e.map((t) => ({ resource: t.resource, quantity: Ee(t.quantity), metadata: t.metadata })); } function K(e) { return e.reduce((t, n) => t + Ee(n.quantity), 0); } function Ve(e) { return !!(e && e.length > 0 && (e.length > 1 || e.length === 1 && (e[0].quantity ?? 1) > 1)); } const Xe = { // ===== PAYMENT VERIFICATION ERRORS (402) ===== invalid_payment_proof: { message: "Payment verification failed", action: "Please try your payment again. If this continues, contact support.", technicalHint: "Invalid payment proof format" }, invalid_signature: { message: "Transaction signature is invalid", action: "Please approve the transaction in your wallet and try again.", technicalHint: "Transaction signature verification failed" }, invalid_transaction: { message: "Transaction format is invalid", action: "Please try your payment again. If this continues, try updating your wallet app.", technicalHint: "Malformed transaction structure" }, transaction_not_found: { message: "Transaction not found on the blockchain", action: "Your transaction may still be processing. Please wait a moment and check your wallet, or try again.", technicalHint: "Transaction signature not found on-chain" }, transaction_not_confirmed: { message: "Transaction is still processing", action: "Please wait a moment for the blockchain to confirm your transaction, then try again.", technicalHint: "Transaction not yet confirmed" }, transaction_failed: { message: "Transaction failed on the blockchain", action: "Check your wallet for details. You may need to adjust your transaction settings or add more SOL for fees.", technicalHint: "On-chain transaction failure" }, transaction_expired: { message: "Transaction took too long to process", action: "Please try your payment again. Consider increasing transaction priority if your wallet supports it.", technicalHint: "Transaction blockhash expired" }, invalid_recipient: { message: "Payment was sent to the wrong address", action: "Please try again and ensure you approve the correct transaction in your wallet.", technicalHint: "Recipient address mismatch" }, invalid_sender: { message: "Payment sender wallet is invalid", action: "Please reconnect your wallet and try again.", technicalHint: "Sender address validation failed" }, unauthorized_refund_issuer: { message: "You are not authorized to issue refunds", action: "Only authorized accounts can process refunds. Please contact support if you believe this is an error.", technicalHint: "Refund issuer not in authorized list" }, amount_below_minimum: { message: "Payment amount is too low", action: "Please check the required amount and try again.", technicalHint: "Amount below minimum threshold" }, amount_mismatch: { message: "Payment amount does not match the quote", action: "The price may have changed. Please refresh and try your payment again.", technicalHint: "Amount does not match quote" }, insufficient_funds_sol: { message: "Not enough SOL for transaction fees", action: "Add at least 0.001 SOL to your wallet to cover network fees, then try again.", technicalHint: "Insufficient SOL balance for fees" }, insufficient_funds_token: { message: "Insufficient balance in your wallet", action: "Add more funds to your wallet and try again.", technicalHint: "Insufficient token balance" }, invalid_token_mint: { message: "Incorrect payment token", action: "Please pay with the correct token as shown in the payment details.", technicalHint: "Token mint address mismatch" }, not_spl_transfer: { message: "Transaction is not a valid token transfer", action: "Please ensure you are sending the correct token type from your wallet.", technicalHint: "Transaction is not an SPL token transfer" }, missing_token_account: { message: "Token account not found", action: "Your wallet may need to create a token account first. Try again or use a different wallet.", technicalHint: "Associated token account does not exist" }, invalid_token_program: { message: "Invalid token program", action: "Please try your payment again. If this continues, try using a different wallet.", technicalHint: "Token program ID mismatch" }, missing_memo: { message: "Payment memo is required but was not included", action: "Please try your payment again and ensure transaction details are approved in your wallet.", technicalHint: "Required memo instruction missing" }, invalid_memo: { message: "Payment memo format is invalid", action: "Please try your payment again.", technicalHint: "Memo does not match expected format" }, payment_already_used: { message: "This payment has already been processed", action: "Check your transaction history. If you need to make another payment, please start a new transaction.", technicalHint: "Payment signature already recorded" }, signature_reused: { message: "Transaction signature has already been used", action: "Please create a new payment transaction.", technicalHint: "Duplicate signature detected" }, quote_expired: { message: "Payment quote has expired", action: "Prices are updated frequently. Please refresh and try your payment again.", technicalHint: "Quote timestamp expired" }, // ===== VALIDATION ERRORS (400) ===== missing_field: { message: "Required information is missing", action: "Please check all required fields and try again.", technicalHint: "Required field not provided" }, invalid_field: { message: "Some information is invalid", action: "Please check your input and try again.", technicalHint: "Field validation failed" }, invalid_amount: { message: "Payment amount is invalid", action: "Please check the amount and try again.", technicalHint: "Amount validation failed" }, invalid_wallet: { message: "Wallet address is invalid", action: "Please reconnect your wallet and try again.", technicalHint: "Wallet address validation failed" }, invalid_resource: { message: "Invalid item selection", action: "Please refresh the page and try again.", technicalHint: "Resource ID validation failed" }, invalid_coupon: { message: "Invalid coupon code", action: "Please check the coupon code and try again.", technicalHint: "Coupon code format invalid" }, invalid_cart_item: { message: "One or more cart items are invalid", action: "Please review your cart and try again.", technicalHint: "Cart item validation failed" }, empty_cart: { message: "Your cart is empty", action: "Please add items to your cart before checking out.", technicalHint: "Cart contains no items" }, // ===== RESOURCE/STATE ERRORS (404) ===== resource_not_found: { message: "Item not found", action: "This item may no longer be available. Please refresh and try again.", technicalHint: "Resource not found in database" }, cart_not_found: { message: "Shopping cart not found", action: "Your cart may have expired. Please start a new order.", technicalHint: "Cart ID not found" }, refund_not_found: { message: "Refund not found", action: "Please check your refund reference number or contact support.", technicalHint: "Refund ID not found" }, product_not_found: { message: "Product not available", action: "This product may no longer be available. Please browse our current selection.", technicalHint: "Product ID not found" }, coupon_not_found: { message: "Coupon code not found", action: "Please check the coupon code or remove it to continue.", technicalHint: "Coupon code not in database" }, session_not_found: { message: "Payment session expired", action: "Please start a new payment.", technicalHint: "Session ID not found or expired" }, cart_already_paid: { message: "This order has already been paid", action: "Check your order history. If you need to make another purchase, please start a new order.", technicalHint: "Cart marked as paid" }, refund_already_processed: { message: "This refund has already been processed", action: "Check your transaction history or contact support for details.", technicalHint: "Refund already completed" }, // ===== COUPON-SPECIFIC ERRORS (409) ===== coupon_expired: { message: "Coupon has expired", action: "Please remove the coupon code or use a different code.", technicalHint: "Coupon expiration date passed" }, coupon_usage_limit_reached: { message: "Coupon usage limit reached", action: "This coupon has been fully redeemed. Please try a different code.", technicalHint: "Coupon max uses exceeded" }, coupon_not_applicable: { message: "Coupon cannot be applied to this purchase", action: "Please check the coupon terms or remove it to continue.", technicalHint: "Coupon conditions not met" }, coupon_wrong_payment_method: { message: "Coupon not valid for this payment method", action: "Try a different payment method or remove the coupon code.", technicalHint: "Coupon restricted to specific payment methods" }, // ===== EXTERNAL SERVICE ERRORS (502) ===== stripe_error: { message: "Card payment service temporarily unavailable", action: "Please try again in a moment, or use cryptocurrency payment instead.", technicalHint: "Stripe API error" }, rpc_error: { message: "Blockchain network temporarily unavailable", action: "Please try again in a moment, or use card payment instead.", technicalHint: "Solana RPC error" }, network_error: { message: "Network connection issue", action: "Please check your internet connection and try again.", technicalHint: "Network request failed" }, // ===== INTERNAL/SYSTEM ERRORS (500) ===== internal_error: { message: "Something went wrong on our end", action: "Please try again. If this continues, contact support.", technicalHint: "Internal server error" }, database_error: { message: "Service temporarily unavailable", action: "Please try again in a moment.", technicalHint: "Database operation failed" }, config_error: { message: "Service configuration error", action: "Please contact support for assistance.", technicalHint: "Server misconfiguration" } }; function ne(e) { return Xe[e] || { message: "An unexpected error occurred", action: "Please try again or contact support if this continues.", technicalHint: `Unknown error code: ${e}` }; } const xe = /* @__PURE__ */ new Map(), le = /* @__PURE__ */ new Map(), ue = /* @__PURE__ */ new Map(), Ae = 200, ge = 2e3; function Ke(e) { const t = ue.get(e); return t ? Date.now() < t ? !0 : (ue.delete(e), !1) : !1; } function Qe(e, t = Ae) { const n = Date.now() + t; ue.set(e, n); } function Ze(e, t = ge) { const n = xe.get(e); if (!n) return !1; const a = Date.now() - n; return a < t ? (m().debug(`[Deduplication] Duplicate request blocked: ${e} (${a}ms ago)`), !0) : !1; } function Je(e) { xe.set(e, Date.now()); } function et(e) { return le.get(e) || null; } function tt(e, t) { le.set(e, t); const n = () => { le.delete(e), Je(e); }; return t.then(n, n), t; } async function nt(e, t, n = {}) { const { windowMs: o = ge, throwOnDuplicate: a = !0 } = n, r = et(e); if (r) return m().debug(`[Deduplication] Reusing in-flight request: ${e}`), r; if (Ze(e, o)) { if (a) throw new Error(`Duplicate request blocked: ${e}`); return m().warn(`[Deduplication] Duplicate request blocked but not throwing: ${e}`), Promise.reject(new Error("Duplicate request")); } const l = t(); return tt(e, l); } function Le(e, t, n = {}) { const { cooldownMs: o = Ae, deduplicationWindowMs: a = ge } = n; return async () => { if (Ke(e)) { m().debug(`[Deduplication] Button in cooldown: ${e}`); return; } Qe(e, o); try { await nt( e, async () => { const r = t(); r instanceof Promise && await r; }, { windowMs: a, throwOnDuplicate: !1 } ); } catch (r) { if (r instanceof Error && r.message.includes("Duplicate request")) return; throw r; } }; } function je(e) { return { background: "none", border: "none", fontSize: "1.5rem", cursor: "pointer", color: e, opacity: 0.6, padding: "0.25rem", lineHeight: 1 }; } const $ = { PAYMENT_START: "cedros:payment:start", WALLET_CONNECT: "cedros:wallet:connect", WALLET_CONNECTED: "cedros:wallet:connected", WALLET_ERROR: "cedros:wallet:error", PAYMENT_PROCESSING: "cedros:payment:processing", PAYMENT_SUCCESS: "cedros:payment:success", PAYMENT_ERROR: "cedros:payment:error" }; function z(e, t) { if (typeof window > "u") return; const n = new CustomEvent(e, { detail: t, bubbles: !0, cancelable: !1 }); window.dispatchEvent(n); } function Me(e, t, n) { z($.PAYMENT_START, { timestamp: Date.now(), method: e, resource: t, itemCount: n }); } function Se(e) { z($.WALLET_CONNECT, { timestamp: Date.now(), wallet: e }); } function at(e, t) { z($.WALLET_CONNECTED, { timestamp: Date.now(), wallet: e, publicKey: t }); } function ie(e, t) { z($.WALLET_ERROR, { timestamp: Date.now(), wallet: t, error: e }); } function de(e, t, n) { z($.PAYMENT_PROCESSING, { timestamp: Date.now(), method: e, resource: t, itemCount: n }); } function He(e, t, n, o) { z($.PAYMENT_SUCCESS, { timestamp: Date.now(), method: e, transactionId: t, resource: n, itemCount: o }); } function ae(e, t, n, o) { z($.PAYMENT_ERROR, { timestamp: Date.now(), method: e, error: t, resource: n, itemCount: o }); } var pe = /* @__PURE__ */ ((e) => (e.INVALID_PAYMENT_PROOF = "invalid_payment_proof", e.INVALID_SIGNATURE = "invalid_signature", e.INVALID_TRANSACTION = "invalid_transaction", e.TRANSACTION_NOT_FOUND = "transaction_not_found", e.TRANSACTION_NOT_CONFIRMED = "transaction_not_confirmed", e.TRANSACTION_FAILED = "transaction_failed", e.TRANSACTION_EXPIRED = "transaction_expired", e.INVALID_RECIPIENT = "invalid_recipient", e.INVALID_SENDER = "invalid_sender", e.UNAUTHORIZED_REFUND_ISSUER = "unauthorized_refund_issuer", e.AMOUNT_BELOW_MINIMUM = "amount_below_minimum", e.AMOUNT_MISMATCH = "amount_mismatch", e.INSUFFICIENT_FUNDS_SOL = "insufficient_funds_sol", e.INSUFFICIENT_FUNDS_TOKEN = "insufficient_funds_token", e.INVALID_TOKEN_MINT = "invalid_token_mint", e.NOT_SPL_TRANSFER = "not_spl_transfer", e.MISSING_TOKEN_ACCOUNT = "missing_token_account", e.INVALID_TOKEN_PROGRAM = "invalid_token_program", e.MISSING_MEMO = "missing_memo", e.INVALID_MEMO = "invalid_memo", e.PAYMENT_ALREADY_USED = "payment_already_used", e.SIGNATURE_REUSED = "signature_reused", e.QUOTE_EXPIRED = "quote_expired", e.MISSING_FIELD = "missing_field", e.INVALID_FIELD = "invalid_field", e.INVALID_AMOUNT = "invalid_amount", e.INVALID_WALLET = "invalid_wallet", e.INVALID_RESOURCE = "invalid_resource", e.INVALID_COUPON = "invalid_coupon", e.INVALID_CART_ITEM = "invalid_cart_item", e.EMPTY_CART = "empty_cart", e.RESOURCE_NOT_FOUND = "resource_not_found", e.CART_NOT_FOUND = "cart_not_found", e.REFUND_NOT_FOUND = "refund_not_found", e.PRODUCT_NOT_FOUND = "product_not_found", e.COUPON_NOT_FOUND = "coupon_not_found", e.SESSION_NOT_FOUND = "session_not_found", e.CART_ALREADY_PAID = "cart_already_paid", e.REFUND_ALREADY_PROCESSED = "refund_already_processed", e.COUPON_EXPIRED = "coupon_expired", e.COUPON_USAGE_LIMIT_REACHED = "coupon_usage_limit_reached", e.COUPON_NOT_APPLICABLE = "coupon_not_applicable", e.COUPON_WRONG_PAYMENT_METHOD = "coupon_wrong_payment_method", e.STRIPE_ERROR = "stripe_error", e.RPC_ERROR = "rpc_error", e.NETWORK_ERROR = "network_error", e.INTERNAL_ERROR = "internal_error", e.DATABASE_ERROR = "database_error", e.CONFIG_ERROR = "config_error", e))(pe || {}); class M extends Error { /** Machine-readable error code enum */ code; /** Whether this error can be safely retried */ retryable; /** Additional error context */ details; /** HTTP status code (if from API response) */ httpStatus; constructor(t, n, o = !1, a, r) { super(n), this.name = "PaymentError", this.code = t, this.retryable = o, this.details = a, this.httpStatus = r, Object.setPrototypeOf(this, M.prototype); } /** * Check if this error is retryable */ canRetry() { return this.retryable; } /** * Check if this is a specific error code */ is(t) { return this.code === t; } /** * Check if this error is in a specific category */ isInCategory(t) { return t.includes(this.code); } /** * Get a user-friendly error message * Uses structured error messages with actionable guidance */ getUserMessage() { const t = this.getErrorInfo(); return t.action ? `${t.message} ${t.action}` : t.message; } /** * Get short error message without action guidance */ getShortMessage() { return this.getErrorInfo().message; } /** * Get actionable guidance for this error */ getAction() { return this.getErrorInfo().action; } /** * Get error info from error messages map * @private */ getErrorInfo() { return ne(this.code); } /** * Create PaymentError from API error response */ static fromErrorResponse(t, n) { return new M( t.error.code, t.error.message, t.error.retryable, t.error.details, n ); } /** * Create PaymentError from unknown error * Useful for catch blocks where error type is unknown */ static fromUnknown(t) { return t instanceof M ? t : t instanceof Error ? new M( "internal_error", t.message, !1 ) : new M( "internal_error", String(t), !1 ); } } const Tt = { /** Insufficient funds errors requiring user to add funds */ INSUFFICIENT_FUNDS: [ "insufficient_funds_sol", "insufficient_funds_token" /* INSUFFICIENT_FUNDS_TOKEN */ ], /** Transaction state errors that may resolve with time */ TRANSACTION_PENDING: [ "transaction_not_confirmed", "transaction_not_found" /* TRANSACTION_NOT_FOUND */ ], /** Validation errors requiring input correction */ VALIDATION: [ "missing_field", "invalid_field", "invalid_amount", "invalid_wallet", "invalid_resource", "invalid_cart_item", "empty_cart" /* EMPTY_CART */ ], /** Coupon-related errors */ COUPON: [ "invalid_coupon", "coupon_not_found", "coupon_expired", "coupon_usage_limit_reached", "coupon_not_applicable", "coupon_wrong_payment_method" /* COUPON_WRONG_PAYMENT_METHOD */ ], /** Retryable errors (temporary failures) */ RETRYABLE: [ "transaction_not_confirmed", "rpc_error", "network_error", "stripe_error" /* STRIPE_ERROR */ ], /** Resource not found errors */ NOT_FOUND: [ "resource_not_found", "cart_not_found", "refund_not_found", "product_not_found", "coupon_not_found", "session_not_found" /* SESSION_NOT_FOUND */ ] }; async function Rt(e) { const t = e.status; try { const n = await e.json(); if (n.error && typeof n.error.code == "string") { const o = n; return M.fromErrorResponse(o, t); } return new M( pe.INTERNAL_ERROR, n.error || n.message || "An unknown error occurred", !1, void 0, t ); } catch { return new M( pe.INTERNAL_ERROR, e.statusText || "Request failed", !1, void 0, t ); } } function Nt(e) { return e instanceof M && e.canRetry(); } function Ct(e) { return e instanceof M ? e.getUserMessage() : e instanceof Error ? e.message : String(e); } function ot() { const { stripeManager: e } = fe(), [t, n] = F({ status: "idle", error: null, transactionId: null }), o = x( async (l, d, N, g, _, w) => { n({ status: "loading", error: null, transactionId: null }); const y = { resource: l, successUrl: d, cancelUrl: N, metadata: g, customerEmail: _, couponCode: w }, b = await e.processPayment(y); return n({ status: b.success ? "success" : "error", error: b.success ? null : b.error || "Payment failed", transactionId: b.success && b.transactionId || null }), b; }, [e] ), a = x( async (l, d, N, g, _, w) => { n({ status: "loading", error: null, transactionId: null }); const y = Oe(l), b = await e.processCartCheckout({ items: y, successUrl: d, cancelUrl: N, metadata: g, customerEmail: _, couponCode: w }); return n({ status: b.success ? "success" : "error", error: b.success ? null : b.error || "Cart checkout failed", transactionId: b.success && b.transactionId || null }), b; }, [e] ), r = x(() => { n({ status: "idle", error: null, transactionId: null }); }, []); return { ...t, processPayment: o, processCartCheckout: a, reset: r }; } function Fe(e, t) { const n = Ve(t), o = e || (t?.length === 1 ? t[0].resource : ""); return { isCartMode: n, effectiveResource: o }; } const rt = (e, t, n) => { const o = e[t]; return o ? typeof o == "function" ? o() : Promise.resolve(o) : new Promise((a, r) => { (typeof queueMicrotask == "function" ? queueMicrotask : setTimeout)(r.bind(null, /* @__PURE__ */ new Error("Unknown variable dynamic import: " + t + (t.split("/").length !== n ? ". Note that variables only represent file names one level deep." : "")))); }); }, ce = /* @__PURE__ */ new Map(); let te = null; async function Pe(e) { if (ce.has(e)) return ce.get(e); try { const t = await rt(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-w27mU-4x.mjs"), "./translations/bn.json": () => import("./bn-Ba_k3Kex.mjs"), "./translations/de.json": () => import("./de-CoZiPFN7.mjs"), "./translations/en.json": () => import("./en-C739WV_-.mjs"), "./translations/es.json": () => import("./es-BWGIBp2f.mjs"), "./translations/fil.json": () => import("./fil-Czo27xmj.mjs"), "./translations/fr.json": () => import("./fr-DQ-2ThBv.mjs"), "./translations/he.json": () => import("./he-DpV1WnBQ.mjs"), "./translations/id.json": () => import("./id-BJMqsu19.mjs"), "./translations/in.json": () => import("./in-BxgxKLQH.mjs"), "./translations/it.json": () => import("./it-DZFFPALf.mjs"), "./translations/jp.json": () => import("./jp-ZExTrlHK.mjs"), "./translations/kr.json": () => import("./kr-DHX3i4Ht.mjs"), "./translations/ms.json": () => import("./ms-Cv1fdIi2.mjs"), "./translations/nl.json": () => import("./nl-BmGonsKb.mjs"), "./translations/pa.json": () => import("./pa-BfwcJIar.mjs"), "./translations/pl.json": () => import("./pl-DE5IB9xv.mjs"), "./translations/pt.json": () => import("./pt-CLzkqDzf.mjs"), "./translations/ru.json": () => import("./ru-DM6-oUR0.mjs"), "./translations/ta.json": () => import("./ta-A5HnrGb5.mjs"), "./translations/th.json": () => import("./th-3fbB3Ytp.mjs"), "./translations/tr.json": () => import("./tr-BrgfFFdq.mjs"), "./translations/uk.json": () => import("./uk-0hFun_g_.mjs"), "./translations/ur.json": () => import("./ur-CaOjJXai.mjs"), "./translations/vn.json": () => import("./vn-0nlIZFLP.mjs"), "./translations/zh.json": () => import("./zh-B4Endr1F.mjs") }), `./translations/${e}.json`, 3), n = t.default || t; return ce.set(e, n), n; } catch { return null; } } async function kt() { if (te) return te; const e = /* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-w27mU-4x.mjs"), "./translations/bn.json": () => import("./bn-Ba_k3Kex.mjs"), "./translations/de.json": () => import("./de-CoZiPFN7.mjs"), "./translations/en.json": () => import("./en-C739WV_-.mjs"), "./translations/es.json": () => import("./es-BWGIBp2f.mjs"), "./translations/fil.json": () => import("./fil-Czo27xmj.mjs"), "./translations/fr.json": () => import("./fr-DQ-2ThBv.mjs"), "./translations/he.json": () => import("./he-DpV1WnBQ.mjs"), "./translations/id.json": () => import("./id-BJMqsu19.mjs"), "./translations/in.json": () => import("./in-BxgxKLQH.mjs"), "./translations/it.json": () => import("./it-DZFFPALf.mjs"), "./translations/jp.json": () => import("./jp-ZExTrlHK.mjs"), "./translations/kr.json": () => import("./kr-DHX3i4Ht.mjs"), "./translations/ms.json": () => import("./ms-Cv1fdIi2.mjs"), "./translations/nl.json": () => import("./nl-BmGonsKb.mjs"), "./translations/pa.json": () => import("./pa-BfwcJIar.mjs"), "./translations/pl.json": () => import("./pl-DE5IB9xv.mjs"), "./translations/pt.json": () => import("./pt-CLzkqDzf.mjs"), "./translations/ru.json": () => import("./ru-DM6-oUR0.mjs"), "./translations/ta.json": () => import("./ta-A5HnrGb5.mjs"), "./translations/th.json": () => import("./th-3fbB3Ytp.mjs"), "./translations/tr.json": () => import("./tr-BrgfFFdq.mjs"), "./translations/uk.json": () => import("./uk-0hFun_g_.mjs"), "./translations/ur.json": () => import("./ur-CaOjJXai.mjs"), "./translations/vn.json": () => import("./vn-0nlIZFLP.mjs"), "./translations/zh.json": () => import("./zh-B4Endr1F.mjs") }), t = []; for (const n in e) { const o = n.match(/\.\/translations\/([a-z]{2,3}(?:-[A-Z]{2})?)\.json$/); o && t.push(o[1]); } return te = t.length > 0 ? t : ["en"], te; } function st() { return typeof navigator > "u" ? "en" : (navigator.language || navigator.userLanguage || "en").split("-")[0].toLowerCase(); } async function it(e) { let t = await Pe(e); if (t || (t = await Pe("en"), t)) return t; throw new Error("Critical: No translation files found, not even en.json"); } function ct(e) { return (t, n) => { const o = t.split("."); let a = e; for (const r of o) if (a && typeof a == "object" && r in a) a = a[r]; else return t; return typeof a != "string" ? t : n ? Object.entries(n).reduce( (r, [l, d]) => r.replace(new RegExp(`\\{${l}\\}`, "g"), d), a ) : a; }; } function St(e, t, n = !0) { const o = t.errors[e]; if (!o) { const a = ne(e); return n && a.action ? `${a.message} ${a.action}` : a.message; } return n && o.action ? `${o.message} ${o.action}` : o.message; } function ye(e) { const [t, n] = F(null), [o, a] = F(!0), r = W(() => e || st(), [e]); return B(() => { let d = !1; return (async () => { a(!0); try { const g = await it(r); d || (n(g), a(!1)); } catch (g) { console.error("[CedrosPay] Failed to load translations:", g), d || a(!1); } })(), () => { d = !0; }; }, [r]), { t: W(() => t ? ct(t) : (d) => ({ "ui.purchase": "Purchase", "ui.pay_with_card": "Pay with Card", "ui.pay_with_crypto": "Pay with USDC", "ui.pay_with_usdc": "Pay with USDC", "ui.card": "Card", "ui.usdc_solana": "USDC (Solana)", "ui.crypto": "Crypto", "ui.processing": "Processing...", "ui.loading": "Loading...", "ui.connect_wallet": "Connect Wallet", "ui.connecting": "Connecting..." })[d] || d, [t]), locale: r, isLoading: o, translations: t }; } function Pt(e, t = !0) { const { translations: n } = ye(); if (!n) { const a = ne(e); return t && a.action ? `${a.message} ${a.action}` : a.message; } const o = n.errors[e]; if (!o) { const a = ne(e); return t && a.action ? `${a.message} ${a.action}` : a.message; } return t && o.action ? `${o.message} ${o.action}` : o.message; } function lt({ resource: e, items: t, successUrl: n, cancelUrl: o, metadata: a, customerEmail: r, couponCode: l, label: d, disabled: N = !1, onAttempt: g, onSuccess: _, onError: w, className: y = "" }) { const { status: b, error: D, transactionId: H, processPayment: f, processCartCheckout: h } = ot(), i = me(), { isCartMode: v, effectiveResource: c } = Fe(e, t), { t: u, translations: C } = ye(), I = d || u("ui.pay_with_card"), k = i.unstyled ? y : `${i.className} cedros-theme__stripe-button ${y}`.trim(), p = D && typeof D != "string" ? D?.code ?? null : null, O = D ? typeof D == "string" ? D : ((L) => { if (!L || !C) return ""; const R = C.errors[L]; return R ? R.action ? `${R.message} ${R.action}` : R.message : ""; })(p) : null, P = x(async () => { m().debug("[StripeButton] executePayment with couponCode:", l); const L = v && t ? K(t) : void 0; if (Me("stripe", c, L), g && g("stripe"), !v && !c) { const Y = "Invalid payment configuration: missing resource or items"; m().error("[StripeButton]", Y), ae("stripe", Y, c, L), w && w(Y); return; } let R; de("stripe", c, L), v && t ? (m().debug("[StripeButton] Processing cart checkout with coupon:", l), R = await h( t, n, o, a, r, l )) : c && (m().debug("[StripeButton] Processing single payment with coupon:", l), R = await f( c, n, o, a, r, l )), R && R.success && R.transactionId ? (He("stripe", R.transactionId, c, L), _ && _(R.transactionId)) : R && !R.success && R.error && (ae("stripe", R.error, c, L), w && w(R.error)); }, [l, v, c, t, n, o, a, r, h, f, g, _, w]), U = W(() => v && t ? `stripe-cart-${t.map((L) => L.resource).join("-")}` : `stripe-${c || "unknown"}`, [v, t, c]), Q = W( () => Le(U, P), [U, P] ), Z = b === "loading", oe = N || Z; return /* @__PURE__ */ E("div", { className: k, style: i.unstyled ? {} : i.style, children: [ /* @__PURE__ */ S( "button", { onClick: Q, disabled: oe, className: i.unstyled ? y : "cedros-theme__button cedros-theme__stripe", type: "button", children: Z ? u("ui.processing") : I } ), O && /* @__PURE__ */ S("div", { className: i.unstyled ? "" : "cedros-theme__error", children: O }), H && /* @__PURE__ */ S("div", { className: i.unstyled ? "" : "cedros-theme__success", children: u("ui.payment_successful") }) ] }); } function ut() { const { x402Manager: e, walletManager: t } = fe(), { publicKey: n, signTransaction: o } = De(), [a, r] = F({ status: "idle", error: null, transactionId: null }), [l, d] = F(null), [N, g] = F(null), _ = x(() => { if (!n) { const f = "Wallet not connected"; return r({ status: "error", error: f, transactionId: null }), { valid: !1, error: f }; } if (!o) { const f = "Wallet does not support signing"; return r({ status: "error", error: f, transactionId: null }), { valid: !1, error: f }; } return { valid: !0 }; }, [n, o]), w = x( async (f) => { try { r((i) => ({ ...i, status: "loading" })); const h = await e.requestQuote({ resource: f }); if (!e.validateRequirement(h)) throw new Error("Invalid requirement received from server"); return d(h), r((i) => ({ ...i, status: "idle" })), h; } catch (h) { const i = se(h, "Failed to fetch requirement"); throw r({ status: "error", error: i, transactionId: null }), h; } }, [e] ), y = x( async (f, h, i, v, c = "regular") => { if (!!f.extra?.feePayer) { console.log("⚡ [useX402Payment] GASLESS FLOW - Backend pays fees"), console.log("🔨 [useX402Payment] Requesting backend to build gasless transaction"); const { transaction: C, blockhash: I } = await e.buildGaslessTransaction({ resourceId: h, userWallet: n.toString(), feePayer: f.extra.feePayer, couponCode: i }); console.log("📦 [useX402Payment] Deserializing transaction from backend"); const k = t.deserializeTransaction(C); console.log("✍️ [useX402Payment] Requesting wallet to partially sign (transfer authority only)"); const p = await t.partiallySignTransaction({ transaction: k, signTransaction: o, blockhash: I }); console.log("📤 [useX402Payment] Submitting partially-signed transaction to backend"); const A = await e.submitGaslessTransaction({ resource: h, partialTx: p, couponCode: i, metadata: v, resourceType: c, requirement: f }); return A.success && A.settlement && g(A.settlement), A; } else { const C = await t.buildTransaction({ requirement: f, payerPublicKey: n }), I = await t.signTransaction({ transaction: C, signTransaction: o }), k = t.buildPaymentPayload({ requirement: f, signedTx: I, payerPublicKey: n }), p = await e.submitPayment({ resource: h, payload: k, couponCode: i, metadata: v, resourceType: c }); return p.success && p.settlement && g(p.settlement), p; } }, [n, o, e, t] ), b = x( async (f, h, i) => { const v = _(); if (!v.valid) return { success: !1, error: v.error }; r({ status: "loading", error: null, transactionId: null }); try { console.log("🔍 [useX402Payment] Fetching fresh quote for resource:", f); const c = await e.requestQuote({ resource: f, couponCode: h }); console.log("✅ [useX402Payment] Got quote:", { payTo: c.payTo, amount: c.maxAmountRequired }), d(c), console.log("⚙️ [useX402Payment] Executing payment flow with fresh requirement"); const u = await y(c, f, h, i, "regular"); return u.success ? r({ status: "success", error: null, transactionId: u.transactionId || "payment-success" }) : r({ status: "error", error: u.error || "Payment failed", transactionId: null }), u; } catch (c) { const u = se(c, "Payment failed"); return r({ status: "error", error: u, transactionId: null }), { success: !1, error: u }; } }, [_, e, y] ), D = x( async (f, h, i) => { const v = _(); if (!v.valid) return { success: !1, error: v.error }; r({ status: "loading", error: null, transactionId: null }); try { const c = Oe(f), u = await e.requestCartQuote({ items: c, metadata: h, couponCode: i }), C = u.cartId, I = u.quote; if (!e.validateRequirement(I)) throw new Error("Invalid cart quote received from server"); d(I); const k = await y(I, C, i, h, "cart"); return k.success ? r({ status: "success", error: null, transactionId: k.transactionId || "cart-payment-success" }) : r({ status: "error", error: k.error || "Cart payment failed", transactionId: null }), k; } catch (c) { const u = se(c, "Cart payment failed"); return r({ status: "error", error: u, transactionId: null }), { success: !1, error: u }; } }, [_, e, y] ), H = x(() => { r({ status: "idle", error: null, transactionId: null }), d(null), g(null); }, []); return { ...a, requirement: l, settlement: N, fetchQuote: w, processPayment: b, processCartPayment: D, reset: H }; } function dt({ resource: e, items: t, label: n, disabled: o = !1, onAttempt: a, onSuccess: r, onError: l, className: d = "", testPageUrl: N, hideMessages: g = !1, metadata: _, couponCode: w }) { const { connected: y, connecting: b, connect: D, disconnect: H, select: f, wallets: h, wallet: i, publicKey: v } = De(), { status: c, error: u, transactionId: C, processPayment: I, processCartPayment: k } = ut(), p = me(), { solanaError: A } = fe(), { isCartMode: O, effectiveResource: P } = Fe(e, t), { t: U, translations: Q } = ye(), Z = n || U("ui.pay_with_crypto"), oe = u && typeof u != "string" ? u?.code ?? null : null, L = A && typeof A != "string" ? A?.code ?? null : null, R = (s) => { if (!s || !Q) return ""; const T = Q.errors[s]; return T ? T.action ? `${T.message} ${T.action}` : T.message : ""; }, Y = u ? typeof u == "string" ? u : R(oe) : null, he = A ? typeof A == "string" ? A : R(L) : null, _e = Ce(I), we = Ce(k); B(() => { _e.current = I, we.current = k; }, [I, k]); const Ue = W( () => h.map((s) => `${s.adapter.name}-${s.readyState}`).join(","), [h] ), J = W( () => h.filter( ({ readyState: s }) => s === ke.Installed || s === ke.Loadable ), // walletStateKey is derived from availableWallets, so we only need availableWallets as dependency // eslint-disable-next-line react-hooks/exhaustive-deps [Ue] ); B(() => { if (c === "success" && C) { const s = O && t ? K(t) : void 0; He("crypto", C, P, s), r && r(C); } }, [c, C, r, O, t, P]), B(() => { if (c === "error" && u) { const s = O && t ? K(t) : void 0; ae("crypto", u, P, s), l && l(u); } }, [c, u, l, O, t, P]); const be = typeof window < "u" && window.top !== window.self, [ve, G] = F(!1), [Ie, re] = F(!1), [V, q] = F(null), X = A; B(() => { let s = !1; return s || (async () => { if (Ie && i && !y && !b) { m().debug("[CryptoButton] Wallet detected, attempting auto-connect:", i.adapter.name), re(!1), Se(i.adapter.name); try { await D(), s || m().debug("[CryptoButton] Auto-connect successful"); } catch (j) { if (!s) { m().error("[CryptoButton] Auto-connect failed:", j); const ee = j instanceof Error ? j.message : "Failed to connect wallet"; ie(ee, i.adapter.name), q(null); } } } })(), () => { s = !0; }; }, [i, Ie, y, b, D]), B(() => { if (m().debug("[CryptoButton] Payment useEffect triggered", { connected: y, hasPendingPayment: !!V, hasPublicKey: !!v, pendingPaymentType: V?.type }), y && V && v && i) { at(i.adapter.name, v.toString()), m().debug("[CryptoButton] All conditions met! Processing pending payment:", V); const s = V; q(null), G(!1); const T = s.type === "cart" && s.items ? K(s.items) : void 0; de("crypto", s.resource, T), s.type === "cart" && s.items ? (m().debug("[CryptoButton] Auto-processing cart payment"), we.current(s.items, s.metadata, s.couponCode)) : s.type === "single" && s.resource && (m().debug("[CryptoButton] Auto-processing single payment"), _e.current(s.resource, s.couponCode, s.metadata)); } }, [y, V, v, i]); const Te = x(async () => { m().debug("[CryptoButton] executePaymentFlow called", { connected: y, wallet: i?.adapter.name, couponCode: w, isCartMode: O, hasItems: !!t, effectiveResource: P }); const s = O && t ? K(t) : void 0; if (Me("crypto", P, s), a && a("crypto"), X) { m().error("[CryptoButton] Solana dependencies missing:", X), ae("crypto", X, P, s), l && l(X); return; } if (be) { const T = N || window.location.href; window.open(T, "_blank", "noopener,noreferrer"); return; } if (y) de("crypto", P, s), O && t ? (m().debug("[CryptoButton] Processing cart payment with coupon:", w), await k(t, _, w)) : P && (m().debug("[CryptoButton] Processing single payment with coupon:", w), await I(P, w, _)); else { let T = !1; if (O && t ? (m().debug("[CryptoButton] Setting pending cart payment with coupon:", w), q({ type: "cart", items: t, metadata: _, couponCode: w }), T = !0) : P && (m().debug("[CryptoButton] Setting pending single payment with coupon:", w), q({ type: "single", resource: P, metadata: _, couponCode: w }), T = !0), !T) { m().error("[CryptoButton] No valid payment to process"); return; } try { if (i) m().debug("[CryptoButton] Wallet already selected, connecting:", i.adapter.name), Se(i.adapter.name), await D(); else { if (m().debug( "[CryptoButton] No wallet selected, showing selector. Available wallets:", J.map((j) => j.adapter.name) ), J.length === 0) { q(null); const j = "No wallets available"; throw ie(j), new Error(j); } G(!0); } } catch (j) { q(null); const ee = j instanceof Error ? j.message : "Failed to connect wallet"; m().error("[CryptoButton] Connection error:", ee), ie(ee, i?.adapter.name); } } }, [y, i, w, O, t, P, be, N, J, D, _, k, I, X, a, l]), Re = W(() => O && t ? `crypto-cart-${t.map((s) => s.resource).join("-")}` : `crypto-${P || "unknown"}`, [O, t, P]), Be = W( () => Le(Re, Te, { cooldownMs: 200, deduplicationWindowMs: 0 // MUST be 0 for crypto - each payment needs fresh transaction }), [Re, Te] ), Ne = c === "loading", We = o || Ne || b || !!X, qe = Ne ? U("ui.processing") : Z, $e = x(async () => { try { re(!1), y && await H(), f(null), G(!0); } catch (s) { m().error("Failed to change wallet:", s); } }, [y, H, f]), ze = x((s) => { m().debug("[CryptoButton] Wallet clicked:", s), G(!1), f(s), re(!0), m().debug("[CryptoButton] Wallet selected, useEffect will auto-connect"); }, [f]), Ye = x(async () => { try { await H(), q(null), typeof window < "u" && window.localStorage && window.localStorage.removeItem("walletName"); } catch (s) { m().error("Failed to disconnect wallet:", s); } }, [H]); return /* @__PURE__ */ E("div", { className: p.unstyled ? d : `${p.className} cedros-theme__crypto-button ${d || ""}`, style: p.unstyled ? {} : p.style, children: [ /* @__PURE__ */ S( "button", { onClick: Be, disabled: We, className: p.unstyled ? d : "cedros-theme__button cedros-theme__crypto", type: "button", children: qe } ), ve && !g && /* @__PURE__ */ S( "div", { className: "cedros-modal-overlay", style: { position: "fixed", top: 0, left: 0, right: 0, bottom: 0, backgroundColor: p.tokens.modalOverlay, display: "flex", alignItems: "center", justifyContent: "center", zIndex: 9999, padding: "1rem" }, onClick: () => G(!1), children: /* @__PURE__ */ E( "div", { className: "cedros-modal-content", style: { backgroundColor: p.tokens.modalBackground, borderRadius: "12px", padding: "2rem", maxWidth: "400px", width: "100%", boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)", border: `1px solid ${p.tokens.modalBorder}` }, onClick: (s) => s.stopPropagation(), children: [ /* @__PURE__ */ E( "div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "1.5rem" }, children: [ /* @__PURE__ */ S( "h3", { style: { margin: 0, fontSize: "1.25rem", fontWeight: 600, color: p.tokens.surfaceText }, children: U("wallet.select_wallet") } ), /* @__PURE__ */ S( "button", { onClick: () => G(!1), style: je(p.tokens.surfaceText), "aria-label": "Close modal", type: "button", children: "×" } ) ] } ), /* @__PURE__ */ S("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: J.map((s) => /* @__PURE__ */ E( "button", { onClick: () => ze(s.adapter.name), style: { width: "100%", padding: "1rem", backgroundColor: p.tokens.surfaceBackground, border: `1px solid ${p.tokens.surfaceBorder}`, borderRadius: "0.5rem", cursor: "pointer", fontSize: "1rem", textAlign: "left", color: p.tokens.surfaceText, display: "flex", alignItems: "center", gap: "1rem", transition: "all 0.2s ease" }, onMouseEnter: (T) => { T.currentTarget.style.backgroundColor = p.tokens.modalBackground, T.currentTarget.style.borderColor = p.tokens.surfaceText, T.currentTarget.style.transform = "translateY(-2px)"; }, onMouseLeave: (T) => { T.currentTarget.style.backgroundColor = p.tokens.surfaceBackground, T.currentTarget.style.borderColor = p.tokens.surfaceBorder, T.currentTarget.style.transform = "translateY(0)"; }, type: "button", children: [ /* @__PURE__ */ S(Ge, { wallet: s, style: { width: "24px", height: "24px" } }), /* @__PURE__ */ S("span", { style: { fontWeight: 500 }, children: s.adapter.name }) ] }, s.adapter.name )) }) ] } ) } ), y && !g && !ve && /* @__PURE__ */ E("div", { style: { display: "flex", justifyContent: "space-between", marginTop: "0.5rem", fontSize: "0.75rem", color: p.tokens.surfaceText, opacity: 0.7 }, children: [ /* @__PURE__ */ S( "button", { onClick: $e, style: { background: "none", border: "none", padding: 0, color: "inherit", textDecoration: "none", cursor: "pointer", fontSize: "inherit" }, type: "button", children: "Change Wallet" } ), /* @__PURE__ */ S( "button", { onClick: Ye, style: { background: "none", border: "none", padding: 0, color: "inherit", textDecoration: "none", cursor: "pointer", fontSize: "inherit" }, type: "button", children: U("ui.disconnect") } ) ] }), !g && he && /* @__PURE__ */ S("div", { className: p.unstyled ? "" : "cedros-theme__error", children: he }), !g && Y && /* @__PURE__ */ S("div", { className: p.unstyled ? "" : "cedros-theme__error", children: Y }), !g && C && /* @__PURE__ */ S("div", { className: p.unstyled ? "" : "cedros-theme__success", children: U("ui.payment_successful") }) ] }); } const Dt = ({ isOpen: e, onClose: t, resource: n, items: o, cardLabel: a = "Card", cryptoLabel: r = "USDC (Solana)", showCard: l = !0, showCrypto: d = !0, onPaymentAttempt: N, onPaymentSuccess: g, onPaymentError: _, onStripeSuccess: w, onCryptoSuccess: y, onStripeError: b, onCryptoError: D, customerEmail: H, successUrl: f, cancelUrl: h, metadata: i, couponCode: v, testPageUrl: c, hideMessages: u = !1 }) => { const { tokens: C } = me(); return B(() => { const I = (k) => { k.key === "Escape" && e && t(); }; return window.addEventListener("keydown", I), () => window.removeEventListener("keydown", I); }, [e, t]), B(() => { if (e) { const I = window.scrollY; re