@moneymq/react 0.1.1

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.js ADDED
@@ -0,0 +1,1567 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ MoneyMQProvider: () => MoneyMQProvider,
34
+ PayButton: () => PayButton,
35
+ PaymentModal: () => PaymentModal,
36
+ useMoneyMQ: () => useMoneyMQ,
37
+ usePayment: () => usePayment,
38
+ useSandbox: () => useSandbox
39
+ });
40
+ module.exports = __toCommonJS(index_exports);
41
+
42
+ // src/provider.tsx
43
+ var import_react3 = require("react");
44
+ var import_wallet_adapter_react2 = require("@solana/wallet-adapter-react");
45
+ var import_wallet_adapter_wallets = require("@solana/wallet-adapter-wallets");
46
+
47
+ // src/wallet-modal-provider.tsx
48
+ var import_react2 = require("react");
49
+
50
+ // src/wallet-modal.tsx
51
+ var import_react = require("react");
52
+ var import_wallet_adapter_react = require("@solana/wallet-adapter-react");
53
+ var import_jsx_runtime = require("react/jsx-runtime");
54
+ var overlayStyle = {
55
+ position: "fixed",
56
+ inset: 0,
57
+ backgroundColor: "rgba(0, 0, 0, 0.6)",
58
+ backdropFilter: "blur(4px)",
59
+ display: "flex",
60
+ alignItems: "center",
61
+ justifyContent: "center",
62
+ zIndex: 9999,
63
+ animation: "fadeIn 150ms ease-out"
64
+ };
65
+ var modalStyle = {
66
+ backgroundColor: "#18181b",
67
+ borderRadius: "1rem",
68
+ padding: "1.5rem",
69
+ width: "100%",
70
+ maxWidth: "400px",
71
+ maxHeight: "90vh",
72
+ overflow: "auto",
73
+ border: "1px solid #27272a",
74
+ boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.5)",
75
+ animation: "slideUp 150ms ease-out"
76
+ };
77
+ var headerStyle = {
78
+ display: "flex",
79
+ alignItems: "center",
80
+ gap: "0.75rem",
81
+ marginBottom: "0.5rem"
82
+ };
83
+ var logoStyle = {
84
+ width: "2.5rem",
85
+ height: "2.5rem",
86
+ borderRadius: "0.5rem",
87
+ objectFit: "contain"
88
+ };
89
+ var titleStyle = {
90
+ fontSize: "1.25rem",
91
+ fontWeight: 600,
92
+ color: "#fafafa",
93
+ margin: 0
94
+ };
95
+ var descriptionStyle = {
96
+ fontSize: "0.875rem",
97
+ color: "#a1a1aa",
98
+ marginBottom: "1.5rem"
99
+ };
100
+ var walletListStyle = {
101
+ display: "flex",
102
+ flexDirection: "column",
103
+ gap: "0.5rem"
104
+ };
105
+ var walletButtonStyle = {
106
+ display: "flex",
107
+ alignItems: "center",
108
+ gap: "0.75rem",
109
+ width: "100%",
110
+ padding: "0.875rem 1rem",
111
+ backgroundColor: "#27272a",
112
+ border: "1px solid #3f3f46",
113
+ borderRadius: "0.75rem",
114
+ cursor: "pointer",
115
+ transition: "all 150ms",
116
+ textAlign: "left"
117
+ };
118
+ var walletIconStyle = {
119
+ width: "2rem",
120
+ height: "2rem",
121
+ borderRadius: "0.375rem"
122
+ };
123
+ var walletNameStyle = {
124
+ flex: 1,
125
+ fontSize: "0.9375rem",
126
+ fontWeight: 500,
127
+ color: "#fafafa"
128
+ };
129
+ var walletTagStyle = {
130
+ fontSize: "0.75rem",
131
+ padding: "0.25rem 0.5rem",
132
+ borderRadius: "9999px",
133
+ backgroundColor: "#3f3f46",
134
+ color: "#a1a1aa"
135
+ };
136
+ var closeButtonStyle = {
137
+ position: "absolute",
138
+ top: "1rem",
139
+ right: "1rem",
140
+ padding: "0.5rem",
141
+ backgroundColor: "transparent",
142
+ border: "none",
143
+ borderRadius: "0.375rem",
144
+ cursor: "pointer",
145
+ color: "#71717a",
146
+ transition: "color 150ms"
147
+ };
148
+ var noWalletsStyle = {
149
+ textAlign: "center",
150
+ padding: "2rem 1rem",
151
+ color: "#a1a1aa",
152
+ fontSize: "0.875rem"
153
+ };
154
+ function WalletModal({ visible, onClose, branding }) {
155
+ const { wallets, select, connecting } = (0, import_wallet_adapter_react.useWallet)();
156
+ const [hoveredWallet, setHoveredWallet] = (0, import_react.useState)(null);
157
+ const accentColor = branding?.accentColor || "#ec4899";
158
+ const sortedWallets = (0, import_react.useMemo)(() => {
159
+ const installed = [];
160
+ const notInstalled = [];
161
+ for (const wallet of wallets) {
162
+ if (wallet.readyState === "Installed") {
163
+ installed.push(wallet);
164
+ } else if (wallet.readyState === "Loadable" || wallet.readyState === "NotDetected") {
165
+ notInstalled.push(wallet);
166
+ }
167
+ }
168
+ return [...installed, ...notInstalled];
169
+ }, [wallets]);
170
+ const handleSelect = (0, import_react.useCallback)((wallet) => {
171
+ select(wallet.adapter.name);
172
+ onClose();
173
+ }, [select, onClose]);
174
+ (0, import_react.useEffect)(() => {
175
+ const handleEscape = (e) => {
176
+ if (e.key === "Escape") onClose();
177
+ };
178
+ if (visible) {
179
+ document.addEventListener("keydown", handleEscape);
180
+ document.body.style.overflow = "hidden";
181
+ }
182
+ return () => {
183
+ document.removeEventListener("keydown", handleEscape);
184
+ document.body.style.overflow = "";
185
+ };
186
+ }, [visible, onClose]);
187
+ if (!visible) return null;
188
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
189
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
190
+ @keyframes fadeIn {
191
+ from { opacity: 0; }
192
+ to { opacity: 1; }
193
+ }
194
+ @keyframes slideUp {
195
+ from { opacity: 0; transform: translateY(10px); }
196
+ to { opacity: 1; transform: translateY(0); }
197
+ }
198
+ ` }),
199
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
200
+ "div",
201
+ {
202
+ style: { ...modalStyle, position: "relative" },
203
+ onClick: (e) => e.stopPropagation(),
204
+ children: [
205
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
206
+ "button",
207
+ {
208
+ style: closeButtonStyle,
209
+ onClick: onClose,
210
+ onMouseEnter: (e) => e.currentTarget.style.color = "#fafafa",
211
+ onMouseLeave: (e) => e.currentTarget.style.color = "#71717a",
212
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M18 6L6 18M6 6l12 12" }) })
213
+ }
214
+ ),
215
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: headerStyle, children: [
216
+ branding?.logo && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: branding.logo, alt: "", style: logoStyle }),
217
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: titleStyle, children: branding?.title || "Connect Wallet" })
218
+ ] }),
219
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: descriptionStyle, children: branding?.description || "Select a wallet to connect and pay securely." }),
220
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: walletListStyle, children: sortedWallets.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: noWalletsStyle, children: "No wallets found. Please install a Solana wallet extension." }) : sortedWallets.map((wallet) => {
221
+ const isInstalled = wallet.readyState === "Installed";
222
+ const isHovered = hoveredWallet === wallet.adapter.name;
223
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
224
+ "button",
225
+ {
226
+ style: {
227
+ ...walletButtonStyle,
228
+ backgroundColor: isHovered ? "#3f3f46" : "#27272a",
229
+ borderColor: isHovered ? accentColor : "#3f3f46"
230
+ },
231
+ onClick: () => handleSelect(wallet),
232
+ onMouseEnter: () => setHoveredWallet(wallet.adapter.name),
233
+ onMouseLeave: () => setHoveredWallet(null),
234
+ disabled: connecting,
235
+ children: [
236
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
237
+ "img",
238
+ {
239
+ src: wallet.adapter.icon,
240
+ alt: wallet.adapter.name,
241
+ style: walletIconStyle
242
+ }
243
+ ),
244
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: walletNameStyle, children: wallet.adapter.name }),
245
+ isInstalled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...walletTagStyle, backgroundColor: accentColor + "20", color: accentColor }, children: "Detected" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: walletTagStyle, children: "Install" })
246
+ ]
247
+ },
248
+ wallet.adapter.name
249
+ );
250
+ }) })
251
+ ]
252
+ }
253
+ ) })
254
+ ] });
255
+ }
256
+
257
+ // src/wallet-modal-provider.tsx
258
+ var import_jsx_runtime2 = require("react/jsx-runtime");
259
+ var WalletModalContext = (0, import_react2.createContext)({
260
+ visible: false,
261
+ setVisible: () => {
262
+ }
263
+ });
264
+ var BrandingContext = (0, import_react2.createContext)(void 0);
265
+ function useWalletModal() {
266
+ return (0, import_react2.useContext)(WalletModalContext);
267
+ }
268
+ function useBranding() {
269
+ return (0, import_react2.useContext)(BrandingContext);
270
+ }
271
+ function CustomWalletModalProvider({ children, branding }) {
272
+ const [visible, setVisible] = (0, import_react2.useState)(false);
273
+ const handleClose = (0, import_react2.useCallback)(() => setVisible(false), []);
274
+ const contextValue = (0, import_react2.useMemo)(
275
+ () => ({ visible, setVisible }),
276
+ [visible]
277
+ );
278
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BrandingContext.Provider, { value: branding, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(WalletModalContext.Provider, { value: contextValue, children: [
279
+ children,
280
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(WalletModal, { visible, onClose: handleClose, branding })
281
+ ] }) });
282
+ }
283
+
284
+ // src/provider.tsx
285
+ var import_jsx_runtime3 = require("react/jsx-runtime");
286
+ var MoneyMQContext = (0, import_react3.createContext)(null);
287
+ var SandboxContext = (0, import_react3.createContext)({
288
+ isSandboxMode: false,
289
+ sandboxAccounts: []
290
+ });
291
+ var DEFAULT_RPC_URL = "https://api.devnet.solana.com";
292
+ var SANDBOX_HASH_PREFIX = "SURFNETxSAFEHASH";
293
+ function normalizeRpcUrl(url) {
294
+ return url.replace("0.0.0.0", "localhost").replace("127.0.0.1", "localhost");
295
+ }
296
+ async function getRpcUrl(apiUrl) {
297
+ try {
298
+ console.log("[MoneyMQ] Fetching config from:", `${apiUrl}/config`);
299
+ const response = await fetch(`${apiUrl}/config`);
300
+ const config = await response.json();
301
+ const rawRpcUrl = config.x402?.validator?.rpcUrl || DEFAULT_RPC_URL;
302
+ console.log("[MoneyMQ] Raw RPC URL from config:", rawRpcUrl);
303
+ const normalizedUrl = normalizeRpcUrl(rawRpcUrl);
304
+ console.log("[MoneyMQ] Normalized RPC URL:", normalizedUrl);
305
+ return normalizedUrl;
306
+ } catch (err) {
307
+ console.error("[MoneyMQ] Error fetching config:", err);
308
+ return DEFAULT_RPC_URL;
309
+ }
310
+ }
311
+ async function checkSandboxMode(rpcUrl) {
312
+ try {
313
+ console.log("[MoneyMQ] Checking sandbox mode with RPC:", rpcUrl);
314
+ const response = await fetch(rpcUrl, {
315
+ method: "POST",
316
+ headers: { "Content-Type": "application/json" },
317
+ body: JSON.stringify({
318
+ jsonrpc: "2.0",
319
+ id: 1,
320
+ method: "getLatestBlockhash",
321
+ params: [{ commitment: "finalized" }]
322
+ })
323
+ });
324
+ const data = await response.json();
325
+ const blockhash = data?.result?.value?.blockhash || "";
326
+ const isSandbox = blockhash.startsWith(SANDBOX_HASH_PREFIX);
327
+ console.log("[MoneyMQ] Blockhash:", blockhash, "| Sandbox:", isSandbox);
328
+ return isSandbox;
329
+ } catch (err) {
330
+ console.error("[MoneyMQ] Error checking sandbox mode:", err);
331
+ return false;
332
+ }
333
+ }
334
+ async function fetchTokenBalance(rpcUrl, tokenAccountAddress) {
335
+ try {
336
+ const response = await fetch(rpcUrl, {
337
+ method: "POST",
338
+ headers: { "Content-Type": "application/json" },
339
+ body: JSON.stringify({
340
+ jsonrpc: "2.0",
341
+ id: 1,
342
+ method: "getAccountInfo",
343
+ params: [tokenAccountAddress, { encoding: "jsonParsed" }]
344
+ })
345
+ });
346
+ const data = await response.json();
347
+ if (data.result?.value?.data?.parsed?.info?.tokenAmount) {
348
+ return parseFloat(data.result.value.data.parsed.info.tokenAmount.uiAmountString || "0");
349
+ }
350
+ return 0;
351
+ } catch {
352
+ return 0;
353
+ }
354
+ }
355
+ async function fetchSandboxAccounts(apiUrl, rpcUrl) {
356
+ try {
357
+ console.log("[MoneyMQ] Fetching sandbox accounts from:", `${apiUrl}/sandbox/accounts`);
358
+ const response = await fetch(`${apiUrl}/sandbox/accounts`);
359
+ if (!response.ok) {
360
+ console.log("[MoneyMQ] Sandbox accounts fetch failed:", response.status);
361
+ return [];
362
+ }
363
+ const data = await response.json();
364
+ if (data.solana?.userAccounts) {
365
+ const accounts = await Promise.all(
366
+ data.solana.userAccounts.map(async (acc) => {
367
+ let usdcBalance = 0;
368
+ if (acc.stablecoins?.usdc) {
369
+ usdcBalance = await fetchTokenBalance(rpcUrl, acc.stablecoins.usdc);
370
+ }
371
+ return {
372
+ id: acc.address,
373
+ name: acc.label,
374
+ address: acc.address,
375
+ secretKeyHex: acc.secretKeyHex,
376
+ stablecoins: acc.stablecoins,
377
+ usdcBalance
378
+ };
379
+ })
380
+ );
381
+ console.log("[MoneyMQ] Sandbox accounts loaded:", accounts.length);
382
+ return accounts;
383
+ }
384
+ return [];
385
+ } catch (err) {
386
+ console.error("[MoneyMQ] Error fetching sandbox accounts:", err);
387
+ return [];
388
+ }
389
+ }
390
+ function useMoneyMQ() {
391
+ const client = (0, import_react3.useContext)(MoneyMQContext);
392
+ if (!client) {
393
+ throw new Error("useMoneyMQ must be used within a MoneyMQProvider");
394
+ }
395
+ return client;
396
+ }
397
+ function useSandbox() {
398
+ return (0, import_react3.useContext)(SandboxContext);
399
+ }
400
+ function MoneyMQProvider({
401
+ children,
402
+ client,
403
+ branding
404
+ }) {
405
+ const [rpcEndpoint, setRpcEndpoint] = (0, import_react3.useState)(null);
406
+ const [isSandboxMode, setIsSandboxMode] = (0, import_react3.useState)(false);
407
+ const [sandboxAccounts, setSandboxAccounts] = (0, import_react3.useState)([]);
408
+ (0, import_react3.useEffect)(() => {
409
+ async function initialize() {
410
+ const rpcUrl = await getRpcUrl(client.config.url);
411
+ setRpcEndpoint(rpcUrl);
412
+ const isSandbox = await checkSandboxMode(rpcUrl);
413
+ setIsSandboxMode(isSandbox);
414
+ if (isSandbox) {
415
+ const accounts = await fetchSandboxAccounts(client.config.url, rpcUrl);
416
+ setSandboxAccounts(accounts);
417
+ }
418
+ }
419
+ initialize();
420
+ }, [client.config.url]);
421
+ const wallets = (0, import_react3.useMemo)(
422
+ () => [
423
+ new import_wallet_adapter_wallets.PhantomWalletAdapter(),
424
+ new import_wallet_adapter_wallets.SolflareWalletAdapter()
425
+ ],
426
+ []
427
+ );
428
+ const sandboxContextValue = (0, import_react3.useMemo)(
429
+ () => ({ isSandboxMode, sandboxAccounts }),
430
+ [isSandboxMode, sandboxAccounts]
431
+ );
432
+ if (!rpcEndpoint) {
433
+ return null;
434
+ }
435
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MoneyMQContext.Provider, { value: client, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SandboxContext.Provider, { value: sandboxContextValue, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_wallet_adapter_react2.ConnectionProvider, { endpoint: rpcEndpoint, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_wallet_adapter_react2.WalletProvider, { wallets, autoConnect: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CustomWalletModalProvider, { branding, children }) }) }) }) });
436
+ }
437
+
438
+ // src/pay-button.tsx
439
+ var import_react6 = require("react");
440
+
441
+ // src/payment-modal.tsx
442
+ var import_react4 = require("react");
443
+ var import_wallet_adapter_react3 = require("@solana/wallet-adapter-react");
444
+ var import_react5 = require("@headlessui/react");
445
+ var import_jsx_runtime4 = require("react/jsx-runtime");
446
+ function encodeFormData(data) {
447
+ const params = new URLSearchParams();
448
+ const addParams = (obj, prefix = "") => {
449
+ for (const [key, value] of Object.entries(obj)) {
450
+ const paramKey = prefix ? `${prefix}[${key}]` : key;
451
+ if (value === null || value === void 0) {
452
+ continue;
453
+ } else if (typeof value === "object" && !Array.isArray(value)) {
454
+ addParams(value, paramKey);
455
+ } else {
456
+ params.append(paramKey, String(value));
457
+ }
458
+ }
459
+ };
460
+ addParams(data);
461
+ return params.toString();
462
+ }
463
+ function normalizeRpcUrl2(url) {
464
+ return url.replace("0.0.0.0", "localhost").replace("127.0.0.1", "localhost");
465
+ }
466
+ async function makeRequestWith402Handling(url, method, body, secretKeyHex, rpcUrl, headers = {}) {
467
+ console.log(`[MoneyMQ] Making ${method} request to ${url}`);
468
+ const formData = body ? encodeFormData(body) : void 0;
469
+ let response = await fetch(url, {
470
+ method,
471
+ headers: {
472
+ "Content-Type": "application/x-www-form-urlencoded",
473
+ ...headers
474
+ },
475
+ body: formData
476
+ });
477
+ let data = await response.json();
478
+ console.log(`[MoneyMQ] Response status: ${response.status}`, data);
479
+ if (response.status === 402) {
480
+ console.log("[MoneyMQ] \u{1F4B3} 402 Payment Required - processing payment...");
481
+ const paymentRequirements = data?.payment_requirements || data?.error?.payment_requirements || [];
482
+ if (paymentRequirements.length === 0) {
483
+ console.warn("[MoneyMQ] \u26A0\uFE0F No payment requirements found in 402 response");
484
+ throw new Error("Payment required but no payment requirements provided");
485
+ }
486
+ console.log("[MoneyMQ] Payment requirements:", paymentRequirements);
487
+ const { createPaymentHeader, selectPaymentRequirements } = await import("x402/client");
488
+ const { createSigner } = await import("x402-fetch");
489
+ const signer = await createSigner("solana", secretKeyHex, {
490
+ svmConfig: rpcUrl
491
+ });
492
+ const selectedPaymentRequirement = selectPaymentRequirements(paymentRequirements, "solana", "exact");
493
+ console.log(`[MoneyMQ] \u{1F4B0} Creating payment for ${selectedPaymentRequirement.network}...`);
494
+ const paymentHeaderValue = await createPaymentHeader(
495
+ signer,
496
+ 1,
497
+ // x402Version
498
+ selectedPaymentRequirement,
499
+ {
500
+ svmConfig: {
501
+ rpcUrl
502
+ }
503
+ }
504
+ );
505
+ console.log("[MoneyMQ] \u2705 Payment header created, retrying request...");
506
+ response = await fetch(url, {
507
+ method,
508
+ headers: {
509
+ "Content-Type": "application/x-www-form-urlencoded",
510
+ "X-Payment": paymentHeaderValue,
511
+ ...headers
512
+ },
513
+ body: formData
514
+ });
515
+ data = await response.json();
516
+ console.log(`[MoneyMQ] Retry response status: ${response.status}`, data);
517
+ if (!response.ok) {
518
+ throw new Error(data.error?.message || "Request failed after payment");
519
+ }
520
+ } else if (!response.ok) {
521
+ throw new Error(data.error?.message || "Request failed");
522
+ }
523
+ return data;
524
+ }
525
+ async function createSandboxPayment(apiUrl, rpcUrl, amount, currency, recipient, senderAddress, secretKeyHex, productName) {
526
+ console.log("[MoneyMQ] Creating sandbox payment...", { amount, currency, recipient, senderAddress });
527
+ const paymentIntent = await makeRequestWith402Handling(
528
+ `${apiUrl}/v1/payment_intents`,
529
+ "POST",
530
+ {
531
+ amount: Math.round(amount * 100),
532
+ // Convert to cents (Stripe-style)
533
+ currency: currency.toLowerCase(),
534
+ customer: senderAddress,
535
+ description: productName ? `Purchase - ${productName}` : "Payment",
536
+ metadata: {
537
+ sender_address: senderAddress,
538
+ recipient_address: recipient
539
+ }
540
+ },
541
+ secretKeyHex,
542
+ rpcUrl
543
+ );
544
+ console.log("[MoneyMQ] Payment intent created:", paymentIntent);
545
+ console.log("[MoneyMQ] Confirming payment intent:", paymentIntent.id);
546
+ const confirmedIntent = await makeRequestWith402Handling(
547
+ `${apiUrl}/v1/payment_intents/${paymentIntent.id}/confirm`,
548
+ "POST",
549
+ {},
550
+ secretKeyHex,
551
+ rpcUrl
552
+ );
553
+ console.log("[MoneyMQ] Payment intent confirmed:", confirmedIntent);
554
+ return confirmedIntent.id;
555
+ }
556
+ var truncateAddress = (address) => {
557
+ if (address.length <= 12) return address;
558
+ return `${address.slice(0, 4)}...${address.slice(-4)}`;
559
+ };
560
+ function PaymentModal({
561
+ visible,
562
+ onClose,
563
+ amount,
564
+ currency,
565
+ recipient,
566
+ productName,
567
+ onSuccess,
568
+ onError,
569
+ accentColor = "#ec4899"
570
+ }) {
571
+ const [isSending, setIsSending] = (0, import_react4.useState)(false);
572
+ const [copiedSender, setCopiedSender] = (0, import_react4.useState)(false);
573
+ const [copiedRecipient, setCopiedRecipient] = (0, import_react4.useState)(false);
574
+ const [showDetails, setShowDetails] = (0, import_react4.useState)(false);
575
+ const [selectedWallet, setSelectedWallet] = (0, import_react4.useState)(null);
576
+ const [selectedPaymentMethod, setSelectedPaymentMethod] = (0, import_react4.useState)(null);
577
+ const { publicKey, connected, disconnect, wallets, select, wallet: connectedWallet } = (0, import_wallet_adapter_react3.useWallet)();
578
+ const branding = useBranding();
579
+ const { isSandboxMode, sandboxAccounts } = useSandbox();
580
+ const client = useMoneyMQ();
581
+ const copyToClipboard = (text, type) => {
582
+ navigator.clipboard.writeText(text);
583
+ if (type === "sender") {
584
+ setCopiedSender(true);
585
+ setTimeout(() => setCopiedSender(false), 2e3);
586
+ } else {
587
+ setCopiedRecipient(true);
588
+ setTimeout(() => setCopiedRecipient(false), 2e3);
589
+ }
590
+ };
591
+ const handleSelectWallet = (wallet) => {
592
+ setSelectedWallet(wallet);
593
+ setSelectedPaymentMethod({ type: "browser_extension", wallet });
594
+ select(wallet.adapter.name);
595
+ };
596
+ const handleSelectSandboxAccount = (account) => {
597
+ setSelectedPaymentMethod({ type: "sandbox_account", sandboxAccount: account });
598
+ setSelectedWallet(null);
599
+ };
600
+ const handleDisconnect = async () => {
601
+ await disconnect();
602
+ setSelectedWallet(null);
603
+ setSelectedPaymentMethod(null);
604
+ };
605
+ const availableWallets = wallets.filter(
606
+ (wallet) => wallet.readyState === "Installed" || wallet.readyState === "Loadable"
607
+ );
608
+ const displayedSandboxAccounts = sandboxAccounts.slice(0, 3);
609
+ const currentWalletIcon = connectedWallet?.adapter.icon || selectedWallet?.adapter.icon;
610
+ const currentWalletName = connectedWallet?.adapter.name || selectedWallet?.adapter.name;
611
+ const getCurrentSelectionDisplay = () => {
612
+ if (connected && publicKey) {
613
+ return {
614
+ icon: currentWalletIcon,
615
+ name: currentWalletName,
616
+ address: publicKey.toBase58(),
617
+ type: "browser_extension"
618
+ };
619
+ }
620
+ if (selectedPaymentMethod?.type === "sandbox_account" && selectedPaymentMethod.sandboxAccount) {
621
+ const name = selectedPaymentMethod.sandboxAccount.name;
622
+ return {
623
+ icon: null,
624
+ name: name.charAt(0).toUpperCase() + name.slice(1),
625
+ address: selectedPaymentMethod.sandboxAccount.address,
626
+ type: "sandbox_account"
627
+ };
628
+ }
629
+ return null;
630
+ };
631
+ const currentSelection = getCurrentSelectionDisplay();
632
+ const handlePay = (0, import_react4.useCallback)(async () => {
633
+ if (!recipient) return;
634
+ let senderAddress;
635
+ let secretKeyHex;
636
+ if (selectedPaymentMethod?.type === "sandbox_account" && selectedPaymentMethod.sandboxAccount) {
637
+ senderAddress = selectedPaymentMethod.sandboxAccount.address;
638
+ secretKeyHex = selectedPaymentMethod.sandboxAccount.secretKeyHex;
639
+ } else if (publicKey) {
640
+ senderAddress = publicKey.toBase58();
641
+ } else {
642
+ return;
643
+ }
644
+ setIsSending(true);
645
+ try {
646
+ if (selectedPaymentMethod?.type === "sandbox_account" && secretKeyHex) {
647
+ const apiUrl = normalizeRpcUrl2(client.config.url);
648
+ let rpcUrl = "http://localhost:8899";
649
+ try {
650
+ const configResponse = await fetch(`${apiUrl}/config`);
651
+ const config = await configResponse.json();
652
+ rpcUrl = normalizeRpcUrl2(config.x402?.validator?.rpcUrl || rpcUrl);
653
+ } catch {
654
+ console.log("[MoneyMQ] Using default RPC URL");
655
+ }
656
+ const paymentId = await createSandboxPayment(
657
+ apiUrl,
658
+ rpcUrl,
659
+ amount,
660
+ currency,
661
+ recipient,
662
+ senderAddress,
663
+ secretKeyHex,
664
+ productName
665
+ );
666
+ setIsSending(false);
667
+ onSuccess?.(paymentId);
668
+ onClose();
669
+ return;
670
+ }
671
+ const event = new CustomEvent("moneymq:payment-initiated", {
672
+ detail: {
673
+ amount,
674
+ currency,
675
+ recipient,
676
+ sender: senderAddress,
677
+ paymentMethod: selectedPaymentMethod?.type || "browser_extension"
678
+ },
679
+ bubbles: true
680
+ });
681
+ window.dispatchEvent(event);
682
+ const signature = await new Promise((resolve, reject) => {
683
+ const handleSuccess = (e) => {
684
+ const customEvent = e;
685
+ cleanup();
686
+ resolve(customEvent.detail.signature);
687
+ };
688
+ const handleError = (e) => {
689
+ const customEvent = e;
690
+ cleanup();
691
+ reject(customEvent.detail);
692
+ };
693
+ const cleanup = () => {
694
+ window.removeEventListener("moneymq:payment-success", handleSuccess);
695
+ window.removeEventListener("moneymq:payment-error", handleError);
696
+ };
697
+ window.addEventListener("moneymq:payment-success", handleSuccess);
698
+ window.addEventListener("moneymq:payment-error", handleError);
699
+ setTimeout(() => {
700
+ cleanup();
701
+ reject(new Error("Payment timeout"));
702
+ }, 6e4);
703
+ });
704
+ setIsSending(false);
705
+ onSuccess?.(signature);
706
+ onClose();
707
+ } catch (err) {
708
+ console.error("Payment failed:", err);
709
+ setIsSending(false);
710
+ onError?.(err instanceof Error ? err : new Error(String(err)));
711
+ }
712
+ }, [publicKey, recipient, amount, currency, onSuccess, onError, onClose, selectedPaymentMethod, client.config.url, productName]);
713
+ const canPay = (connected && publicKey || selectedPaymentMethod?.type === "sandbox_account") && recipient && !isSending;
714
+ if (!visible) return null;
715
+ const WalletIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
716
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M21 12V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2h14a2 2 0 002-2v-5z" }),
717
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M16 12h.01", strokeWidth: "2", strokeLinecap: "round" })
718
+ ] });
719
+ const SandboxIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M9.75 3.104v5.714a2.25 2.25 0 0 1-.659 1.591L5 14.5M9.75 3.104c-.251.023-.501.05-.75.082m.75-.082a24.301 24.301 0 0 1 4.5 0m0 0v5.714c0 .597.237 1.17.659 1.591L19.8 15.3M14.25 3.104c.251.023.501.05.75.082M19.8 15.3l-1.57.393A9.065 9.065 0 0 1 12 15a9.065 9.065 0 0 1-6.23.693L5 15.5m14.8-.2a2.25 2.25 0 0 1 .775 2.646l-.972 2.916a2.25 2.25 0 0 1-2.134 1.538H6.532a2.25 2.25 0 0 1-2.135-1.538l-.971-2.916A2.25 2.25 0 0 1 4.2 15.3", strokeLinecap: "round", strokeLinejoin: "round" }) });
720
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
721
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
722
+ @keyframes spin {
723
+ from { transform: rotate(0deg); }
724
+ to { transform: rotate(360deg); }
725
+ }
726
+ ` }),
727
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
728
+ "div",
729
+ {
730
+ style: {
731
+ position: "fixed",
732
+ inset: 0,
733
+ zIndex: 9998,
734
+ backgroundColor: "rgba(0, 0, 0, 0.6)",
735
+ backdropFilter: "blur(8px)"
736
+ },
737
+ onClick: onClose
738
+ }
739
+ ),
740
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
741
+ "div",
742
+ {
743
+ style: {
744
+ position: "fixed",
745
+ inset: 0,
746
+ zIndex: 9999,
747
+ display: "flex",
748
+ alignItems: "center",
749
+ justifyContent: "center",
750
+ padding: "1rem"
751
+ },
752
+ onClick: onClose,
753
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
754
+ "div",
755
+ {
756
+ style: {
757
+ width: "100%",
758
+ maxWidth: "380px",
759
+ backgroundColor: "#2c2c2e",
760
+ borderRadius: "1rem",
761
+ overflow: "hidden",
762
+ boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.5)"
763
+ },
764
+ onClick: (e) => e.stopPropagation(),
765
+ children: [
766
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
767
+ "div",
768
+ {
769
+ style: {
770
+ display: "flex",
771
+ alignItems: "center",
772
+ justifyContent: "space-between",
773
+ padding: "1rem 1.25rem",
774
+ borderBottom: "1px solid #3a3a3c"
775
+ },
776
+ children: [
777
+ branding?.logo ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
778
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
779
+ "img",
780
+ {
781
+ src: branding.logo,
782
+ alt: "Logo",
783
+ style: { height: "24px", width: "auto", filter: "invert(1)" }
784
+ }
785
+ ),
786
+ isSandboxMode && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontSize: "0.75rem", fontWeight: 600, color: "#ff9f0a" }, children: "| SANDBOX" })
787
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
788
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: [
789
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "10", fill: accentColor }),
790
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M8 12l2.5 2.5L16 9", stroke: "white", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })
791
+ ] }),
792
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontSize: "1.125rem", fontWeight: 600, color: "#fff" }, children: "Pay" }),
793
+ isSandboxMode && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontSize: "0.75rem", fontWeight: 600, color: "#ff9f0a" }, children: "| SANDBOX" })
794
+ ] }),
795
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
796
+ "button",
797
+ {
798
+ onClick: onClose,
799
+ style: {
800
+ padding: "0.375rem 0.75rem",
801
+ fontSize: "0.875rem",
802
+ fontWeight: 500,
803
+ color: "#0a84ff",
804
+ background: "none",
805
+ border: "none",
806
+ cursor: "pointer"
807
+ },
808
+ children: "Cancel"
809
+ }
810
+ )
811
+ ]
812
+ }
813
+ ),
814
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { padding: "0.75rem" }, children: currentSelection ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
815
+ "div",
816
+ {
817
+ style: {
818
+ backgroundColor: "#3a3a3c",
819
+ borderRadius: "0.75rem",
820
+ padding: "0.875rem 1rem",
821
+ marginBottom: "0.5rem"
822
+ },
823
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.75rem" }, children: [
824
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
825
+ "div",
826
+ {
827
+ style: {
828
+ width: "40px",
829
+ height: "40px",
830
+ borderRadius: "0.5rem",
831
+ backgroundColor: currentSelection.icon ? "transparent" : "#636366",
832
+ display: "flex",
833
+ alignItems: "center",
834
+ justifyContent: "center",
835
+ color: "#fff",
836
+ overflow: "hidden"
837
+ },
838
+ children: currentSelection.icon ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
839
+ "img",
840
+ {
841
+ src: currentSelection.icon,
842
+ alt: currentSelection.name || "Wallet",
843
+ style: { width: "40px", height: "40px", borderRadius: "0.5rem" }
844
+ }
845
+ ) : currentSelection.type === "sandbox_account" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SandboxIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(WalletIcon, {})
846
+ }
847
+ ),
848
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
849
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.375rem", marginBottom: "0.125rem" }, children: [
850
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { fontSize: "0.75rem", color: "#8e8e93" }, children: [
851
+ "From ",
852
+ truncateAddress(currentSelection.address)
853
+ ] }),
854
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
855
+ "button",
856
+ {
857
+ onClick: () => copyToClipboard(currentSelection.address, "sender"),
858
+ style: {
859
+ padding: 0,
860
+ background: "none",
861
+ border: "none",
862
+ cursor: "pointer",
863
+ color: copiedSender ? "#30d158" : "#8e8e93",
864
+ display: "flex",
865
+ alignItems: "center"
866
+ },
867
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
868
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
869
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1" })
870
+ ] })
871
+ }
872
+ )
873
+ ] }),
874
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
875
+ "span",
876
+ {
877
+ style: {
878
+ fontSize: "0.9375rem",
879
+ fontWeight: 500,
880
+ color: "#fff"
881
+ },
882
+ children: currentSelection.name
883
+ }
884
+ )
885
+ ] }),
886
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
887
+ "button",
888
+ {
889
+ onClick: handleDisconnect,
890
+ style: {
891
+ fontSize: "0.75rem",
892
+ fontWeight: 500,
893
+ color: "#ff453a",
894
+ background: "none",
895
+ border: "none",
896
+ cursor: "pointer",
897
+ padding: "0.25rem 0.5rem"
898
+ },
899
+ children: "unlink"
900
+ }
901
+ )
902
+ ] })
903
+ }
904
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react5.Menu, { as: "div", style: { position: "relative", marginBottom: "0.5rem" }, children: [
905
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
906
+ import_react5.MenuButton,
907
+ {
908
+ style: {
909
+ width: "100%",
910
+ backgroundColor: "#3a3a3c",
911
+ borderRadius: "0.75rem",
912
+ padding: "0.875rem 1rem",
913
+ border: "none",
914
+ cursor: "pointer",
915
+ display: "flex",
916
+ alignItems: "center",
917
+ gap: "0.75rem",
918
+ textAlign: "left"
919
+ },
920
+ children: [
921
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
922
+ "div",
923
+ {
924
+ style: {
925
+ width: "40px",
926
+ height: "40px",
927
+ borderRadius: "0.5rem",
928
+ backgroundColor: currentWalletIcon ? "transparent" : "#636366",
929
+ display: "flex",
930
+ alignItems: "center",
931
+ justifyContent: "center",
932
+ color: "#fff",
933
+ overflow: "hidden",
934
+ flexShrink: 0
935
+ },
936
+ children: currentWalletIcon ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
937
+ "img",
938
+ {
939
+ src: currentWalletIcon,
940
+ alt: currentWalletName || "Wallet",
941
+ style: { width: "40px", height: "40px", borderRadius: "0.5rem" }
942
+ }
943
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(WalletIcon, {})
944
+ }
945
+ ),
946
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
947
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "0.75rem", color: "#8e8e93", marginBottom: "0.125rem" }, children: "From" }),
948
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
949
+ "span",
950
+ {
951
+ style: {
952
+ fontSize: "0.9375rem",
953
+ fontWeight: 500,
954
+ color: "#0a84ff"
955
+ },
956
+ children: selectedWallet ? selectedWallet.adapter.name : "Connect Wallet"
957
+ }
958
+ )
959
+ ] }),
960
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
961
+ "svg",
962
+ {
963
+ width: "16",
964
+ height: "16",
965
+ viewBox: "0 0 16 16",
966
+ fill: "#8e8e93",
967
+ style: { flexShrink: 0 },
968
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { fillRule: "evenodd", d: "M5.22 10.22a.75.75 0 0 1 1.06 0L8 11.94l1.72-1.72a.75.75 0 1 1 1.06 1.06l-2.25 2.25a.75.75 0 0 1-1.06 0l-2.25-2.25a.75.75 0 0 1 0-1.06ZM10.78 5.78a.75.75 0 0 1-1.06 0L8 4.06 6.28 5.78a.75.75 0 0 1-1.06-1.06l2.25-2.25a.75.75 0 0 1 1.06 0l2.25 2.25a.75.75 0 0 1 0 1.06Z", clipRule: "evenodd" })
969
+ }
970
+ )
971
+ ]
972
+ }
973
+ ),
974
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
975
+ import_react5.MenuItems,
976
+ {
977
+ anchor: "bottom start",
978
+ style: {
979
+ backgroundColor: "#2c2c2e",
980
+ borderRadius: "0.75rem",
981
+ padding: "0.25rem",
982
+ boxShadow: "0 10px 25px rgba(0, 0, 0, 0.4)",
983
+ zIndex: 1e4,
984
+ outline: "none",
985
+ border: "1px solid #48484a",
986
+ maxHeight: "300px",
987
+ overflowY: "auto",
988
+ width: "var(--button-width)",
989
+ marginTop: "0.25rem"
990
+ },
991
+ children: [
992
+ isSandboxMode && displayedSandboxAccounts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
993
+ displayedSandboxAccounts.map((account) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react5.MenuItem, { children: ({ focus }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
994
+ "button",
995
+ {
996
+ onClick: () => handleSelectSandboxAccount(account),
997
+ style: {
998
+ display: "flex",
999
+ alignItems: "center",
1000
+ gap: "0.75rem",
1001
+ padding: "0.875rem 1rem",
1002
+ backgroundColor: focus ? "#3a3a3c" : "transparent",
1003
+ borderRadius: "0.5rem",
1004
+ border: "none",
1005
+ cursor: "pointer",
1006
+ width: "100%",
1007
+ textAlign: "left",
1008
+ transition: "background-color 150ms"
1009
+ },
1010
+ children: [
1011
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1012
+ "div",
1013
+ {
1014
+ style: {
1015
+ width: "40px",
1016
+ height: "40px",
1017
+ borderRadius: "0.5rem",
1018
+ backgroundColor: "#636366",
1019
+ display: "flex",
1020
+ alignItems: "center",
1021
+ justifyContent: "center",
1022
+ overflow: "hidden",
1023
+ flexShrink: 0,
1024
+ color: "#fff"
1025
+ },
1026
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SandboxIcon, {})
1027
+ }
1028
+ ),
1029
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
1030
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.375rem", marginBottom: "0.125rem" }, children: [
1031
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { fontSize: "0.75rem", color: "#8e8e93" }, children: [
1032
+ "From ",
1033
+ truncateAddress(account.address)
1034
+ ] }),
1035
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1036
+ "span",
1037
+ {
1038
+ role: "button",
1039
+ tabIndex: 0,
1040
+ onClick: (e) => {
1041
+ e.stopPropagation();
1042
+ navigator.clipboard.writeText(account.address);
1043
+ },
1044
+ onKeyDown: (e) => {
1045
+ if (e.key === "Enter" || e.key === " ") {
1046
+ e.stopPropagation();
1047
+ navigator.clipboard.writeText(account.address);
1048
+ }
1049
+ },
1050
+ style: {
1051
+ padding: 0,
1052
+ background: "none",
1053
+ border: "none",
1054
+ cursor: "pointer",
1055
+ color: "#8e8e93",
1056
+ display: "flex",
1057
+ alignItems: "center"
1058
+ },
1059
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
1060
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
1061
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1" })
1062
+ ] })
1063
+ }
1064
+ )
1065
+ ] }),
1066
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1067
+ "span",
1068
+ {
1069
+ style: {
1070
+ fontSize: "0.9375rem",
1071
+ fontWeight: 500,
1072
+ color: "#fff"
1073
+ },
1074
+ children: account.name.charAt(0).toUpperCase() + account.name.slice(1)
1075
+ }
1076
+ )
1077
+ ] }),
1078
+ account.usdcBalance !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1079
+ "span",
1080
+ {
1081
+ style: {
1082
+ fontSize: "0.6875rem",
1083
+ color: "#ff9f0a",
1084
+ backgroundColor: "rgba(255, 159, 10, 0.15)",
1085
+ padding: "0.25rem 0.5rem",
1086
+ borderRadius: "0.25rem",
1087
+ flexShrink: 0
1088
+ },
1089
+ children: [
1090
+ account.usdcBalance.toLocaleString(),
1091
+ " USDC"
1092
+ ]
1093
+ }
1094
+ )
1095
+ ]
1096
+ }
1097
+ ) }, account.id)),
1098
+ availableWallets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { height: "1px", backgroundColor: "#48484a", margin: "0.25rem 0" } })
1099
+ ] }),
1100
+ availableWallets.length > 0 ? availableWallets.map((wallet) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react5.MenuItem, { children: ({ focus }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1101
+ "button",
1102
+ {
1103
+ onClick: () => handleSelectWallet(wallet),
1104
+ style: {
1105
+ display: "flex",
1106
+ alignItems: "center",
1107
+ gap: "0.75rem",
1108
+ padding: "0.875rem 1rem",
1109
+ backgroundColor: focus ? "#3a3a3c" : "transparent",
1110
+ borderRadius: "0.5rem",
1111
+ border: "none",
1112
+ cursor: "pointer",
1113
+ width: "100%",
1114
+ textAlign: "left",
1115
+ transition: "background-color 150ms"
1116
+ },
1117
+ children: [
1118
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1119
+ "div",
1120
+ {
1121
+ style: {
1122
+ width: "40px",
1123
+ height: "40px",
1124
+ borderRadius: "0.5rem",
1125
+ backgroundColor: "#636366",
1126
+ display: "flex",
1127
+ alignItems: "center",
1128
+ justifyContent: "center",
1129
+ overflow: "hidden",
1130
+ flexShrink: 0
1131
+ },
1132
+ children: wallet.adapter.icon ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1133
+ "img",
1134
+ {
1135
+ src: wallet.adapter.icon,
1136
+ alt: wallet.adapter.name,
1137
+ style: {
1138
+ width: "40px",
1139
+ height: "40px",
1140
+ borderRadius: "0.5rem"
1141
+ }
1142
+ }
1143
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(WalletIcon, {})
1144
+ }
1145
+ ),
1146
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
1147
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "0.75rem", color: "#8e8e93", marginBottom: "0.125rem" }, children: "Browser Extension" }),
1148
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1149
+ "span",
1150
+ {
1151
+ style: {
1152
+ fontSize: "0.9375rem",
1153
+ fontWeight: 500,
1154
+ color: "#fff"
1155
+ },
1156
+ children: wallet.adapter.name
1157
+ }
1158
+ )
1159
+ ] }),
1160
+ wallet.readyState === "Installed" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1161
+ "span",
1162
+ {
1163
+ style: {
1164
+ fontSize: "0.6875rem",
1165
+ color: "#30d158",
1166
+ backgroundColor: "rgba(48, 209, 88, 0.15)",
1167
+ padding: "0.25rem 0.5rem",
1168
+ borderRadius: "0.25rem",
1169
+ flexShrink: 0
1170
+ },
1171
+ children: "Detected"
1172
+ }
1173
+ )
1174
+ ]
1175
+ }
1176
+ ) }, wallet.adapter.name)) : !isSandboxMode || displayedSandboxAccounts.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1177
+ "div",
1178
+ {
1179
+ style: {
1180
+ textAlign: "center",
1181
+ padding: "1.5rem",
1182
+ color: "#8e8e93",
1183
+ fontSize: "0.875rem"
1184
+ },
1185
+ children: "No wallets detected"
1186
+ }
1187
+ ) : null
1188
+ ]
1189
+ }
1190
+ )
1191
+ ] }) }),
1192
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1193
+ "div",
1194
+ {
1195
+ style: {
1196
+ padding: "1rem 1.25rem 1.25rem",
1197
+ borderTop: "1px solid #3a3a3c"
1198
+ },
1199
+ children: [
1200
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "1rem" }, children: [
1201
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "0.875rem", color: "#8e8e93", marginBottom: "0.25rem" }, children: productName ? `Pay ${productName}` : "Total" }),
1202
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
1203
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "baseline", gap: "0.375rem" }, children: [
1204
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontSize: "2rem", fontWeight: 600, color: "#fff" }, children: amount.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }),
1205
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontSize: "1rem", fontWeight: 500, color: "#8e8e93" }, children: currency })
1206
+ ] }),
1207
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1208
+ "button",
1209
+ {
1210
+ onClick: () => setShowDetails(!showDetails),
1211
+ style: {
1212
+ width: "22px",
1213
+ height: "22px",
1214
+ borderRadius: "50%",
1215
+ border: "1.5px solid #8e8e93",
1216
+ background: "none",
1217
+ color: "#8e8e93",
1218
+ fontSize: "0.8125rem",
1219
+ fontWeight: 600,
1220
+ fontStyle: "italic",
1221
+ fontFamily: "Georgia, serif",
1222
+ cursor: "pointer",
1223
+ display: "flex",
1224
+ alignItems: "center",
1225
+ justifyContent: "center",
1226
+ padding: 0,
1227
+ transition: "all 150ms"
1228
+ },
1229
+ title: "Show payment details",
1230
+ children: "i"
1231
+ }
1232
+ )
1233
+ ] }),
1234
+ showDetails && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1235
+ "div",
1236
+ {
1237
+ style: {
1238
+ marginTop: "0.75rem",
1239
+ padding: "0.625rem 0.75rem",
1240
+ backgroundColor: "#3a3a3c",
1241
+ borderRadius: "0.5rem",
1242
+ fontSize: "0.8125rem"
1243
+ },
1244
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
1245
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "#8e8e93" }, children: "Recipient" }),
1246
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.375rem" }, children: [
1247
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1248
+ "span",
1249
+ {
1250
+ style: {
1251
+ color: "#fff",
1252
+ fontFamily: "ui-monospace, monospace",
1253
+ fontSize: "0.75rem"
1254
+ },
1255
+ children: truncateAddress(recipient)
1256
+ }
1257
+ ),
1258
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1259
+ "button",
1260
+ {
1261
+ onClick: () => copyToClipboard(recipient, "recipient"),
1262
+ style: {
1263
+ padding: 0,
1264
+ background: "none",
1265
+ border: "none",
1266
+ cursor: "pointer",
1267
+ color: copiedRecipient ? "#30d158" : "#8e8e93",
1268
+ display: "flex",
1269
+ alignItems: "center"
1270
+ },
1271
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
1272
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
1273
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1" })
1274
+ ] })
1275
+ }
1276
+ )
1277
+ ] })
1278
+ ] })
1279
+ }
1280
+ )
1281
+ ] }),
1282
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1283
+ "button",
1284
+ {
1285
+ onClick: handlePay,
1286
+ disabled: !canPay,
1287
+ style: {
1288
+ width: "100%",
1289
+ padding: "1rem",
1290
+ borderRadius: "0.75rem",
1291
+ border: "none",
1292
+ fontSize: "1.0625rem",
1293
+ fontWeight: 600,
1294
+ cursor: canPay ? "pointer" : "not-allowed",
1295
+ backgroundColor: canPay ? accentColor : "#48484a",
1296
+ color: canPay ? "#fff" : "#8e8e93",
1297
+ display: "flex",
1298
+ alignItems: "center",
1299
+ justifyContent: "center",
1300
+ gap: "0.5rem",
1301
+ transition: "opacity 150ms"
1302
+ },
1303
+ children: isSending ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1304
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1305
+ "div",
1306
+ {
1307
+ style: {
1308
+ width: "1.25rem",
1309
+ height: "1.25rem",
1310
+ border: "2px solid currentColor",
1311
+ borderTopColor: "transparent",
1312
+ borderRadius: "50%",
1313
+ animation: "spin 1s linear infinite"
1314
+ }
1315
+ }
1316
+ ),
1317
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Processing..." })
1318
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1319
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { fillRule: "evenodd", d: "M12.516 2.17a.75.75 0 0 0-1.032 0 11.209 11.209 0 0 1-7.877 3.08.75.75 0 0 0-.722.515A12.74 12.74 0 0 0 2.25 9.75c0 5.942 4.064 10.933 9.563 12.348a.749.749 0 0 0 .374 0c5.499-1.415 9.563-6.406 9.563-12.348 0-1.39-.223-2.73-.635-3.985a.75.75 0 0 0-.722-.516 11.209 11.209 0 0 1-7.877-3.08ZM10.28 10.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.06 0l3.75-3.75a.75.75 0 0 0-1.06-1.06l-3.22 3.22-1.72-1.72Z", clipRule: "evenodd" }) }),
1320
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
1321
+ "Pay ",
1322
+ amount.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 }),
1323
+ " ",
1324
+ currency
1325
+ ] })
1326
+ ] })
1327
+ }
1328
+ )
1329
+ ]
1330
+ }
1331
+ )
1332
+ ]
1333
+ }
1334
+ )
1335
+ }
1336
+ )
1337
+ ] });
1338
+ }
1339
+
1340
+ // src/pay-button.tsx
1341
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1342
+ var baseStyle = {
1343
+ position: "relative",
1344
+ display: "inline-flex",
1345
+ alignItems: "center",
1346
+ justifyContent: "center",
1347
+ gap: "0.5rem",
1348
+ borderRadius: "0.5rem",
1349
+ fontSize: "0.875rem",
1350
+ fontWeight: 600,
1351
+ padding: "0.625rem 1rem",
1352
+ cursor: "pointer",
1353
+ transition: "all 200ms",
1354
+ border: "none"
1355
+ };
1356
+ var solidStyle = {
1357
+ ...baseStyle,
1358
+ backgroundColor: "#ec4899",
1359
+ color: "white",
1360
+ boxShadow: "0 1px 2px 0 rgb(0 0 0 / 0.05)"
1361
+ };
1362
+ var outlineStyle = {
1363
+ ...baseStyle,
1364
+ backgroundColor: "transparent",
1365
+ color: "#ec4899",
1366
+ border: "1px solid #ec4899"
1367
+ };
1368
+ var PayButton = (0, import_react6.forwardRef)(
1369
+ function PayButton2({
1370
+ priceId,
1371
+ price: priceObject,
1372
+ product: productObject,
1373
+ onSuccess,
1374
+ onError,
1375
+ variant = "solid",
1376
+ children,
1377
+ disabled
1378
+ }, ref) {
1379
+ const client = useMoneyMQ();
1380
+ const [isModalOpen, setIsModalOpen] = (0, import_react6.useState)(false);
1381
+ const [isHovered, setIsHovered] = (0, import_react6.useState)(false);
1382
+ const hasPriceObject = priceObject !== void 0;
1383
+ const [isLoading, setIsLoading] = (0, import_react6.useState)(!hasPriceObject);
1384
+ const [error, setError] = (0, import_react6.useState)(null);
1385
+ const [amount, setAmount] = (0, import_react6.useState)(hasPriceObject ? priceObject.unit_amount / 100 : 0);
1386
+ const [currency, setCurrency] = (0, import_react6.useState)(hasPriceObject ? priceObject.currency.toUpperCase() : "USDC");
1387
+ const [recipient, setRecipient] = (0, import_react6.useState)("");
1388
+ const [productName, setProductName] = (0, import_react6.useState)(productObject?.name);
1389
+ (0, import_react6.useEffect)(() => {
1390
+ async function fetchPaymentDetails() {
1391
+ setIsLoading(true);
1392
+ setError(null);
1393
+ try {
1394
+ const apiUrl = client.config.url;
1395
+ const configResponse = await fetch(`${apiUrl}/config`);
1396
+ if (!configResponse.ok) {
1397
+ throw new Error(`Failed to fetch config: ${configResponse.status}`);
1398
+ }
1399
+ const config = await configResponse.json();
1400
+ if (config.x402?.payoutAccount?.address) {
1401
+ setRecipient(config.x402.payoutAccount.address);
1402
+ }
1403
+ if (hasPriceObject) {
1404
+ setAmount(priceObject.unit_amount / 100);
1405
+ setCurrency(priceObject.currency.toUpperCase());
1406
+ if (productObject) {
1407
+ setProductName(productObject.name);
1408
+ } else if (priceObject.product) {
1409
+ try {
1410
+ const productResponse = await fetch(`${apiUrl}/v1/products/${priceObject.product}`);
1411
+ if (productResponse.ok) {
1412
+ const product = await productResponse.json();
1413
+ setProductName(product.name);
1414
+ }
1415
+ } catch {
1416
+ }
1417
+ }
1418
+ } else if (priceId) {
1419
+ const priceResponse = await fetch(`${apiUrl}/v1/prices/${priceId}`);
1420
+ if (!priceResponse.ok) {
1421
+ throw new Error(`Failed to fetch price: ${priceResponse.status}`);
1422
+ }
1423
+ const price = await priceResponse.json();
1424
+ setAmount(price.unit_amount / 100);
1425
+ setCurrency(price.currency.toUpperCase());
1426
+ if (price.product) {
1427
+ try {
1428
+ const productResponse = await fetch(`${apiUrl}/v1/products/${price.product}`);
1429
+ if (productResponse.ok) {
1430
+ const product = await productResponse.json();
1431
+ setProductName(product.name);
1432
+ }
1433
+ } catch {
1434
+ }
1435
+ }
1436
+ } else {
1437
+ throw new Error("Either priceId or price object is required");
1438
+ }
1439
+ } catch (err) {
1440
+ console.error("[PayButton] Error fetching payment details:", err);
1441
+ const errorMessage = err instanceof Error ? err.message : "Failed to load payment details";
1442
+ setError(errorMessage);
1443
+ onError?.(new Error(errorMessage));
1444
+ } finally {
1445
+ setIsLoading(false);
1446
+ }
1447
+ }
1448
+ fetchPaymentDetails();
1449
+ }, [priceId, priceObject, productObject, client.config.url, onError, hasPriceObject]);
1450
+ const handleClick = () => {
1451
+ if (!isLoading && !error) {
1452
+ setIsModalOpen(true);
1453
+ }
1454
+ };
1455
+ const handlePaymentSuccess = (signature) => {
1456
+ const payment = {
1457
+ id: `pay_${Date.now()}`,
1458
+ amount,
1459
+ currency,
1460
+ status: "completed",
1461
+ signature
1462
+ };
1463
+ onSuccess?.(payment);
1464
+ };
1465
+ const handlePaymentError = (error2) => {
1466
+ onError?.(error2);
1467
+ };
1468
+ const isDisabled = disabled || isLoading || !!error;
1469
+ const buttonStyle = {
1470
+ ...variant === "outline" ? outlineStyle : solidStyle,
1471
+ backgroundColor: variant === "solid" ? isHovered && !isDisabled ? "#db2777" : "#ec4899" : isHovered && !isDisabled ? "rgba(236, 72, 153, 0.1)" : "transparent",
1472
+ opacity: isDisabled ? 0.5 : 1,
1473
+ cursor: isDisabled ? "not-allowed" : "pointer"
1474
+ };
1475
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1476
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1477
+ "button",
1478
+ {
1479
+ ref,
1480
+ onClick: handleClick,
1481
+ disabled: isDisabled,
1482
+ style: buttonStyle,
1483
+ title: error || void 0,
1484
+ onMouseEnter: () => setIsHovered(true),
1485
+ onMouseLeave: () => setIsHovered(false),
1486
+ children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Loading..." }) : error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Error" }) : children || /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Pay" })
1487
+ }
1488
+ ),
1489
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1490
+ PaymentModal,
1491
+ {
1492
+ visible: isModalOpen,
1493
+ onClose: () => setIsModalOpen(false),
1494
+ amount,
1495
+ currency,
1496
+ recipient,
1497
+ productName,
1498
+ onSuccess: handlePaymentSuccess,
1499
+ onError: handlePaymentError
1500
+ }
1501
+ )
1502
+ ] });
1503
+ }
1504
+ );
1505
+
1506
+ // src/use-payment.ts
1507
+ var import_react7 = require("react");
1508
+ var import_wallet_adapter_react4 = require("@solana/wallet-adapter-react");
1509
+ function usePayment() {
1510
+ const [isPending, setIsPending] = (0, import_react7.useState)(false);
1511
+ const [lastPayment, setLastPayment] = (0, import_react7.useState)(null);
1512
+ const { publicKey, connected } = (0, import_wallet_adapter_react4.useWallet)();
1513
+ const { setVisible } = useWalletModal();
1514
+ const pay = (0, import_react7.useCallback)(async (priceId) => {
1515
+ if (!connected || !publicKey) {
1516
+ setVisible(true);
1517
+ return null;
1518
+ }
1519
+ setIsPending(true);
1520
+ try {
1521
+ const event = new CustomEvent("moneymq:pay", {
1522
+ detail: { priceId, publicKey: publicKey.toBase58() },
1523
+ bubbles: true
1524
+ });
1525
+ window.dispatchEvent(event);
1526
+ const result = await new Promise((resolve, reject) => {
1527
+ const handleSuccess = (e) => {
1528
+ const customEvent = e;
1529
+ cleanup();
1530
+ resolve(customEvent.detail);
1531
+ };
1532
+ const handleError = (e) => {
1533
+ const customEvent = e;
1534
+ cleanup();
1535
+ reject(customEvent.detail);
1536
+ };
1537
+ const cleanup = () => {
1538
+ window.removeEventListener("moneymq:payment-success", handleSuccess);
1539
+ window.removeEventListener("moneymq:payment-error", handleError);
1540
+ };
1541
+ window.addEventListener("moneymq:payment-success", handleSuccess);
1542
+ window.addEventListener("moneymq:payment-error", handleError);
1543
+ setTimeout(() => {
1544
+ cleanup();
1545
+ reject(new Error("Payment timeout"));
1546
+ }, 6e4);
1547
+ });
1548
+ setLastPayment(result);
1549
+ return result;
1550
+ } catch {
1551
+ return null;
1552
+ } finally {
1553
+ setIsPending(false);
1554
+ }
1555
+ }, [connected, publicKey, setVisible]);
1556
+ return { pay, isPending, lastPayment };
1557
+ }
1558
+ // Annotate the CommonJS export names for ESM import in node:
1559
+ 0 && (module.exports = {
1560
+ MoneyMQProvider,
1561
+ PayButton,
1562
+ PaymentModal,
1563
+ useMoneyMQ,
1564
+ usePayment,
1565
+ useSandbox
1566
+ });
1567
+ //# sourceMappingURL=index.js.map