@alphadevs_labs/upay-sdk 0.0.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.
@@ -0,0 +1,57 @@
1
+ import React from 'react';
2
+
3
+ interface UPayPayment {
4
+ id: string;
5
+ sessionId: string;
6
+ payerAddress: string;
7
+ settleToken: string;
8
+ settleChain: string;
9
+ amount: string;
10
+ txHashes: string[];
11
+ settledAt: string;
12
+ }
13
+ interface UPayCheckoutSession {
14
+ id: string;
15
+ checkoutUrl: string;
16
+ amount: string;
17
+ settleToken: string;
18
+ settleChain: string;
19
+ status: "pending" | "paid" | "failed" | "expired";
20
+ expiresAt: string;
21
+ }
22
+ interface UPayButtonProps {
23
+ apiKey: string;
24
+ baseUrl?: string;
25
+ amount: string;
26
+ token?: string;
27
+ chain?: string;
28
+ metadata?: Record<string, unknown>;
29
+ onSuccess?: (payment: UPayPayment) => void;
30
+ onError?: (err: Error) => void;
31
+ label?: string;
32
+ className?: string;
33
+ }
34
+ interface UPayClientOptions {
35
+ apiKey: string;
36
+ baseUrl?: string;
37
+ }
38
+ interface CreateCheckoutOptions {
39
+ amount: string;
40
+ token?: string;
41
+ chain?: string;
42
+ metadata?: Record<string, unknown>;
43
+ successUrl?: string;
44
+ cancelUrl?: string;
45
+ }
46
+
47
+ declare function UPayButton({ apiKey, baseUrl, amount, token, chain, metadata, onSuccess, onError, label, className, }: UPayButtonProps): React.JSX.Element;
48
+
49
+ declare class UPay {
50
+ private apiKey;
51
+ private baseUrl;
52
+ constructor(options: UPayClientOptions);
53
+ createCheckout(options: CreateCheckoutOptions): Promise<UPayCheckoutSession>;
54
+ openCheckout(sessionId: string): void;
55
+ }
56
+
57
+ export { type CreateCheckoutOptions, UPay, UPayButton, type UPayButtonProps, type UPayCheckoutSession, type UPayClientOptions, type UPayPayment };
@@ -0,0 +1,57 @@
1
+ import React from 'react';
2
+
3
+ interface UPayPayment {
4
+ id: string;
5
+ sessionId: string;
6
+ payerAddress: string;
7
+ settleToken: string;
8
+ settleChain: string;
9
+ amount: string;
10
+ txHashes: string[];
11
+ settledAt: string;
12
+ }
13
+ interface UPayCheckoutSession {
14
+ id: string;
15
+ checkoutUrl: string;
16
+ amount: string;
17
+ settleToken: string;
18
+ settleChain: string;
19
+ status: "pending" | "paid" | "failed" | "expired";
20
+ expiresAt: string;
21
+ }
22
+ interface UPayButtonProps {
23
+ apiKey: string;
24
+ baseUrl?: string;
25
+ amount: string;
26
+ token?: string;
27
+ chain?: string;
28
+ metadata?: Record<string, unknown>;
29
+ onSuccess?: (payment: UPayPayment) => void;
30
+ onError?: (err: Error) => void;
31
+ label?: string;
32
+ className?: string;
33
+ }
34
+ interface UPayClientOptions {
35
+ apiKey: string;
36
+ baseUrl?: string;
37
+ }
38
+ interface CreateCheckoutOptions {
39
+ amount: string;
40
+ token?: string;
41
+ chain?: string;
42
+ metadata?: Record<string, unknown>;
43
+ successUrl?: string;
44
+ cancelUrl?: string;
45
+ }
46
+
47
+ declare function UPayButton({ apiKey, baseUrl, amount, token, chain, metadata, onSuccess, onError, label, className, }: UPayButtonProps): React.JSX.Element;
48
+
49
+ declare class UPay {
50
+ private apiKey;
51
+ private baseUrl;
52
+ constructor(options: UPayClientOptions);
53
+ createCheckout(options: CreateCheckoutOptions): Promise<UPayCheckoutSession>;
54
+ openCheckout(sessionId: string): void;
55
+ }
56
+
57
+ export { type CreateCheckoutOptions, UPay, UPayButton, type UPayButtonProps, type UPayCheckoutSession, type UPayClientOptions, type UPayPayment };
package/dist/index.js ADDED
@@ -0,0 +1,289 @@
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
+ UPay: () => UPay,
34
+ UPayButton: () => UPayButton
35
+ });
36
+ module.exports = __toCommonJS(index_exports);
37
+
38
+ // src/UPayButton.tsx
39
+ var import_react = __toESM(require("react"));
40
+
41
+ // src/client.ts
42
+ var DEFAULT_BASE_URL = typeof window !== "undefined" ? window.location.origin : "http://localhost:3000";
43
+ var UPay = class {
44
+ apiKey;
45
+ baseUrl;
46
+ constructor(options) {
47
+ this.apiKey = options.apiKey;
48
+ this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
49
+ }
50
+ async createCheckout(options) {
51
+ const res = await fetch(`${this.baseUrl}/api/v1/sessions`, {
52
+ method: "POST",
53
+ headers: {
54
+ "Content-Type": "application/json",
55
+ Authorization: `Bearer ${this.apiKey}`
56
+ },
57
+ body: JSON.stringify({
58
+ amount: options.amount,
59
+ token: options.token,
60
+ chain: options.chain,
61
+ metadata: options.metadata,
62
+ success_url: options.successUrl,
63
+ cancel_url: options.cancelUrl
64
+ })
65
+ });
66
+ if (!res.ok) {
67
+ const err = await res.json().catch(() => ({ error: "Unknown error" }));
68
+ throw new Error(err.error ?? `HTTP ${res.status}`);
69
+ }
70
+ return res.json();
71
+ }
72
+ openCheckout(sessionId) {
73
+ const url = `${this.baseUrl}/checkout/${sessionId}`;
74
+ if (typeof window === "undefined") return;
75
+ const existingModal = document.getElementById("upay-modal-container");
76
+ if (existingModal) existingModal.remove();
77
+ const container = document.createElement("div");
78
+ container.id = "upay-modal-container";
79
+ container.style.cssText = [
80
+ "position:fixed",
81
+ "inset:0",
82
+ "z-index:2147483647",
83
+ "display:flex",
84
+ "align-items:center",
85
+ "justify-content:center",
86
+ "background:rgba(0,0,0,0.6)",
87
+ "backdrop-filter:blur(4px)"
88
+ ].join(";");
89
+ const spinner = document.createElement("div");
90
+ spinner.style.cssText = [
91
+ "width:min(480px,100vw)",
92
+ "height:min(700px,100vh)",
93
+ "display:flex",
94
+ "align-items:center",
95
+ "justify-content:center",
96
+ "border-radius:16px",
97
+ "background:#fff"
98
+ ].join(";");
99
+ spinner.innerHTML = `
100
+ <style>@keyframes upay-modal-spin{to{transform:rotate(360deg)}}</style>
101
+ <svg width="36" height="36" viewBox="0 0 36 36" fill="none"
102
+ style="animation:upay-modal-spin 0.8s linear infinite">
103
+ <circle cx="18" cy="18" r="14" stroke="#e5e7eb" stroke-width="3"/>
104
+ <path d="M18 4a14 14 0 0 1 14 14" stroke="#6366f1"
105
+ stroke-width="3" stroke-linecap="round"/>
106
+ </svg>`;
107
+ const iframe = document.createElement("iframe");
108
+ iframe.src = url;
109
+ iframe.style.cssText = [
110
+ "display:none",
111
+ "width:min(480px,100vw)",
112
+ "height:0",
113
+ "max-height:90vh",
114
+ "border:none",
115
+ "border-radius:16px",
116
+ "box-shadow:0 25px 50px rgba(0,0,0,0.4)",
117
+ "transition:height 0.2s ease",
118
+ "overflow:hidden"
119
+ ].join(";");
120
+ iframe.allow = "payment";
121
+ iframe.onload = () => {
122
+ spinner.remove();
123
+ iframe.style.display = "block";
124
+ };
125
+ const close = () => container.remove();
126
+ container.addEventListener("click", (e) => {
127
+ if (e.target === container) close();
128
+ });
129
+ window.addEventListener(
130
+ "message",
131
+ (e) => {
132
+ if (e.data?.type === "upay:close") close();
133
+ if (e.data?.type === "upay:height") {
134
+ const maxPx = window.innerHeight * 0.9;
135
+ iframe.style.height = `${Math.min(e.data.height, maxPx)}px`;
136
+ }
137
+ if (e.data?.type === "upay:success") {
138
+ close();
139
+ window.dispatchEvent(
140
+ new CustomEvent("upay:payment-success", { detail: e.data.payment })
141
+ );
142
+ }
143
+ },
144
+ { once: false }
145
+ );
146
+ container.appendChild(spinner);
147
+ container.appendChild(iframe);
148
+ document.body.appendChild(container);
149
+ }
150
+ };
151
+
152
+ // src/UPayButton.tsx
153
+ var defaultStyles = {
154
+ button: {
155
+ display: "inline-flex",
156
+ alignItems: "center",
157
+ gap: "8px",
158
+ padding: "12px 24px",
159
+ background: "linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)",
160
+ color: "#fff",
161
+ border: "none",
162
+ borderRadius: "10px",
163
+ fontSize: "15px",
164
+ fontWeight: "600",
165
+ fontFamily: "inherit",
166
+ cursor: "pointer",
167
+ transition: "opacity 0.15s, transform 0.1s",
168
+ minHeight: "44px",
169
+ letterSpacing: "-0.01em"
170
+ },
171
+ loading: {
172
+ opacity: 0.7,
173
+ cursor: "not-allowed"
174
+ }
175
+ };
176
+ var UPayLogo = () => /* @__PURE__ */ import_react.default.createElement(
177
+ "svg",
178
+ {
179
+ width: "18",
180
+ height: "18",
181
+ viewBox: "0 0 18 18",
182
+ fill: "none",
183
+ xmlns: "http://www.w3.org/2000/svg",
184
+ "aria-hidden": "true"
185
+ },
186
+ /* @__PURE__ */ import_react.default.createElement("circle", { cx: "9", cy: "9", r: "8.5", stroke: "rgba(255,255,255,0.6)" }),
187
+ /* @__PURE__ */ import_react.default.createElement(
188
+ "path",
189
+ {
190
+ d: "M5.5 6.5L9 11.5L12.5 6.5",
191
+ stroke: "white",
192
+ strokeWidth: "1.8",
193
+ strokeLinecap: "round",
194
+ strokeLinejoin: "round"
195
+ }
196
+ )
197
+ );
198
+ var Spinner = () => /* @__PURE__ */ import_react.default.createElement(
199
+ "svg",
200
+ {
201
+ width: "16",
202
+ height: "16",
203
+ viewBox: "0 0 16 16",
204
+ fill: "none",
205
+ "aria-hidden": "true",
206
+ style: { animation: "upay-spin 0.8s linear infinite" }
207
+ },
208
+ /* @__PURE__ */ import_react.default.createElement(
209
+ "circle",
210
+ {
211
+ cx: "8",
212
+ cy: "8",
213
+ r: "6",
214
+ stroke: "rgba(255,255,255,0.35)",
215
+ strokeWidth: "2"
216
+ }
217
+ ),
218
+ /* @__PURE__ */ import_react.default.createElement(
219
+ "path",
220
+ {
221
+ d: "M8 2a6 6 0 0 1 6 6",
222
+ stroke: "white",
223
+ strokeWidth: "2",
224
+ strokeLinecap: "round"
225
+ }
226
+ ),
227
+ /* @__PURE__ */ import_react.default.createElement("style", null, `@keyframes upay-spin{to{transform:rotate(360deg)}}`)
228
+ );
229
+ function UPayButton({
230
+ apiKey,
231
+ baseUrl,
232
+ amount,
233
+ token,
234
+ chain,
235
+ metadata,
236
+ onSuccess,
237
+ onError,
238
+ label = "Pay with UPay",
239
+ className
240
+ }) {
241
+ const [loading, setLoading] = (0, import_react.useState)(false);
242
+ const handleClick = (0, import_react.useCallback)(async () => {
243
+ if (loading) return;
244
+ setLoading(true);
245
+ try {
246
+ const client = new UPay({ apiKey, baseUrl });
247
+ const session = await client.createCheckout({
248
+ amount,
249
+ token,
250
+ chain,
251
+ metadata
252
+ });
253
+ client.openCheckout(session.id);
254
+ const handleSuccess = (e) => {
255
+ const payment = e.detail;
256
+ onSuccess?.(payment);
257
+ window.removeEventListener("upay:payment-success", handleSuccess);
258
+ };
259
+ window.addEventListener("upay:payment-success", handleSuccess);
260
+ } catch (err) {
261
+ const error = err instanceof Error ? err : new Error(String(err));
262
+ onError?.(error);
263
+ } finally {
264
+ setLoading(false);
265
+ }
266
+ }, [loading, apiKey, amount, token, chain, metadata, onSuccess, onError]);
267
+ return /* @__PURE__ */ import_react.default.createElement(
268
+ "button",
269
+ {
270
+ onClick: handleClick,
271
+ disabled: loading,
272
+ className,
273
+ style: className ? void 0 : {
274
+ ...defaultStyles.button,
275
+ ...loading ? defaultStyles.loading : {}
276
+ },
277
+ "aria-label": loading ? "Processing payment\u2026" : label,
278
+ "aria-busy": loading
279
+ },
280
+ loading ? /* @__PURE__ */ import_react.default.createElement(Spinner, null) : /* @__PURE__ */ import_react.default.createElement(UPayLogo, null),
281
+ /* @__PURE__ */ import_react.default.createElement("span", null, loading ? "Opening checkout\u2026" : label)
282
+ );
283
+ }
284
+ // Annotate the CommonJS export names for ESM import in node:
285
+ 0 && (module.exports = {
286
+ UPay,
287
+ UPayButton
288
+ });
289
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/UPayButton.tsx","../src/client.ts"],"sourcesContent":["export { UPayButton } from \"./UPayButton\";\nexport { UPay } from \"./client\";\nexport type {\n UPayButtonProps,\n UPayPayment,\n UPayCheckoutSession,\n UPayClientOptions,\n CreateCheckoutOptions,\n} from \"./types\";\n","\"use client\";\n\nimport React, { useState, useCallback } from \"react\";\nimport { UPay } from \"./client\";\nimport type { UPayButtonProps, UPayPayment } from \"./types\";\n\nconst defaultStyles = {\n button: {\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"8px\",\n padding: \"12px 24px\",\n background: \"linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)\",\n color: \"#fff\",\n border: \"none\",\n borderRadius: \"10px\",\n fontSize: \"15px\",\n fontWeight: \"600\",\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n transition: \"opacity 0.15s, transform 0.1s\",\n minHeight: \"44px\",\n letterSpacing: \"-0.01em\",\n } as React.CSSProperties,\n loading: {\n opacity: 0.7,\n cursor: \"not-allowed\",\n } as React.CSSProperties,\n};\n\nconst UPayLogo = () => (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle cx=\"9\" cy=\"9\" r=\"8.5\" stroke=\"rgba(255,255,255,0.6)\" />\n <path\n d=\"M5.5 6.5L9 11.5L12.5 6.5\"\n stroke=\"white\"\n strokeWidth=\"1.8\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nconst Spinner = () => (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n aria-hidden=\"true\"\n style={{ animation: \"upay-spin 0.8s linear infinite\" }}\n >\n <circle\n cx=\"8\"\n cy=\"8\"\n r=\"6\"\n stroke=\"rgba(255,255,255,0.35)\"\n strokeWidth=\"2\"\n />\n <path\n d=\"M8 2a6 6 0 0 1 6 6\"\n stroke=\"white\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n <style>{`@keyframes upay-spin{to{transform:rotate(360deg)}}`}</style>\n </svg>\n);\n\nexport function UPayButton({\n apiKey,\n baseUrl,\n amount,\n token,\n chain,\n metadata,\n onSuccess,\n onError,\n label = \"Pay with UPay\",\n className,\n}: UPayButtonProps) {\n const [loading, setLoading] = useState(false);\n\n const handleClick = useCallback(async () => {\n if (loading) return;\n setLoading(true);\n\n try {\n const client = new UPay({ apiKey, baseUrl });\n const session = await client.createCheckout({\n amount,\n token,\n chain,\n metadata,\n });\n client.openCheckout(session.id);\n\n const handleSuccess = (e: Event) => {\n const payment = (e as CustomEvent<UPayPayment>).detail;\n onSuccess?.(payment);\n window.removeEventListener(\"upay:payment-success\", handleSuccess);\n };\n window.addEventListener(\"upay:payment-success\", handleSuccess);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error);\n } finally {\n setLoading(false);\n }\n }, [loading, apiKey, amount, token, chain, metadata, onSuccess, onError]);\n\n return (\n <button\n onClick={handleClick}\n disabled={loading}\n className={className}\n style={\n className\n ? undefined\n : {\n ...defaultStyles.button,\n ...(loading ? defaultStyles.loading : {}),\n }\n }\n aria-label={loading ? \"Processing payment…\" : label}\n aria-busy={loading}\n >\n {loading ? <Spinner /> : <UPayLogo />}\n <span>{loading ? \"Opening checkout…\" : label}</span>\n </button>\n );\n}\n","import type {\n UPayClientOptions,\n CreateCheckoutOptions,\n UPayCheckoutSession,\n} from \"./types\";\n\nconst DEFAULT_BASE_URL =\n typeof window !== \"undefined\"\n ? window.location.origin\n : \"http://localhost:3000\";\n\nexport class UPay {\n private apiKey: string;\n private baseUrl: string;\n\n constructor(options: UPayClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n }\n\n async createCheckout(\n options: CreateCheckoutOptions\n ): Promise<UPayCheckoutSession> {\n const res = await fetch(`${this.baseUrl}/api/v1/sessions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n amount: options.amount,\n token: options.token,\n chain: options.chain,\n metadata: options.metadata,\n success_url: options.successUrl,\n cancel_url: options.cancelUrl,\n }),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ error: \"Unknown error\" }));\n throw new Error(err.error ?? `HTTP ${res.status}`);\n }\n\n return res.json();\n }\n\n openCheckout(sessionId: string): void {\n const url = `${this.baseUrl}/checkout/${sessionId}`;\n\n if (typeof window === \"undefined\") return;\n\n const existingModal = document.getElementById(\"upay-modal-container\");\n if (existingModal) existingModal.remove();\n\n const container = document.createElement(\"div\");\n container.id = \"upay-modal-container\";\n container.style.cssText = [\n \"position:fixed\",\n \"inset:0\",\n \"z-index:2147483647\",\n \"display:flex\",\n \"align-items:center\",\n \"justify-content:center\",\n \"background:rgba(0,0,0,0.6)\",\n \"backdrop-filter:blur(4px)\",\n ].join(\";\");\n\n // Spinner shown while iframe loads\n const spinner = document.createElement(\"div\");\n spinner.style.cssText = [\n \"width:min(480px,100vw)\",\n \"height:min(700px,100vh)\",\n \"display:flex\",\n \"align-items:center\",\n \"justify-content:center\",\n \"border-radius:16px\",\n \"background:#fff\",\n ].join(\";\");\n spinner.innerHTML = `\n <style>@keyframes upay-modal-spin{to{transform:rotate(360deg)}}</style>\n <svg width=\"36\" height=\"36\" viewBox=\"0 0 36 36\" fill=\"none\"\n style=\"animation:upay-modal-spin 0.8s linear infinite\">\n <circle cx=\"18\" cy=\"18\" r=\"14\" stroke=\"#e5e7eb\" stroke-width=\"3\"/>\n <path d=\"M18 4a14 14 0 0 1 14 14\" stroke=\"#6366f1\"\n stroke-width=\"3\" stroke-linecap=\"round\"/>\n </svg>`;\n\n const iframe = document.createElement(\"iframe\");\n iframe.src = url;\n iframe.style.cssText = [\n \"display:none\",\n \"width:min(480px,100vw)\",\n \"height:0\",\n \"max-height:90vh\",\n \"border:none\",\n \"border-radius:16px\",\n \"box-shadow:0 25px 50px rgba(0,0,0,0.4)\",\n \"transition:height 0.2s ease\",\n \"overflow:hidden\",\n ].join(\";\");\n iframe.allow = \"payment\";\n iframe.onload = () => {\n spinner.remove();\n iframe.style.display = \"block\";\n };\n\n const close = (): void => container.remove();\n\n container.addEventListener(\"click\", (e) => {\n if (e.target === container) close();\n });\n\n window.addEventListener(\n \"message\",\n (e) => {\n if (e.data?.type === \"upay:close\") close();\n if (e.data?.type === \"upay:height\") {\n const maxPx = window.innerHeight * 0.9;\n iframe.style.height = `${Math.min(e.data.height, maxPx)}px`;\n }\n if (e.data?.type === \"upay:success\") {\n close();\n window.dispatchEvent(\n new CustomEvent(\"upay:payment-success\", { detail: e.data.payment })\n );\n }\n },\n { once: false }\n );\n\n container.appendChild(spinner);\n container.appendChild(iframe);\n document.body.appendChild(container);\n }\n}\n"],"mappings":"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","names":["React"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,251 @@
1
+ // src/UPayButton.tsx
2
+ import React, { useState, useCallback } from "react";
3
+
4
+ // src/client.ts
5
+ var DEFAULT_BASE_URL = typeof window !== "undefined" ? window.location.origin : "http://localhost:3000";
6
+ var UPay = class {
7
+ apiKey;
8
+ baseUrl;
9
+ constructor(options) {
10
+ this.apiKey = options.apiKey;
11
+ this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
12
+ }
13
+ async createCheckout(options) {
14
+ const res = await fetch(`${this.baseUrl}/api/v1/sessions`, {
15
+ method: "POST",
16
+ headers: {
17
+ "Content-Type": "application/json",
18
+ Authorization: `Bearer ${this.apiKey}`
19
+ },
20
+ body: JSON.stringify({
21
+ amount: options.amount,
22
+ token: options.token,
23
+ chain: options.chain,
24
+ metadata: options.metadata,
25
+ success_url: options.successUrl,
26
+ cancel_url: options.cancelUrl
27
+ })
28
+ });
29
+ if (!res.ok) {
30
+ const err = await res.json().catch(() => ({ error: "Unknown error" }));
31
+ throw new Error(err.error ?? `HTTP ${res.status}`);
32
+ }
33
+ return res.json();
34
+ }
35
+ openCheckout(sessionId) {
36
+ const url = `${this.baseUrl}/checkout/${sessionId}`;
37
+ if (typeof window === "undefined") return;
38
+ const existingModal = document.getElementById("upay-modal-container");
39
+ if (existingModal) existingModal.remove();
40
+ const container = document.createElement("div");
41
+ container.id = "upay-modal-container";
42
+ container.style.cssText = [
43
+ "position:fixed",
44
+ "inset:0",
45
+ "z-index:2147483647",
46
+ "display:flex",
47
+ "align-items:center",
48
+ "justify-content:center",
49
+ "background:rgba(0,0,0,0.6)",
50
+ "backdrop-filter:blur(4px)"
51
+ ].join(";");
52
+ const spinner = document.createElement("div");
53
+ spinner.style.cssText = [
54
+ "width:min(480px,100vw)",
55
+ "height:min(700px,100vh)",
56
+ "display:flex",
57
+ "align-items:center",
58
+ "justify-content:center",
59
+ "border-radius:16px",
60
+ "background:#fff"
61
+ ].join(";");
62
+ spinner.innerHTML = `
63
+ <style>@keyframes upay-modal-spin{to{transform:rotate(360deg)}}</style>
64
+ <svg width="36" height="36" viewBox="0 0 36 36" fill="none"
65
+ style="animation:upay-modal-spin 0.8s linear infinite">
66
+ <circle cx="18" cy="18" r="14" stroke="#e5e7eb" stroke-width="3"/>
67
+ <path d="M18 4a14 14 0 0 1 14 14" stroke="#6366f1"
68
+ stroke-width="3" stroke-linecap="round"/>
69
+ </svg>`;
70
+ const iframe = document.createElement("iframe");
71
+ iframe.src = url;
72
+ iframe.style.cssText = [
73
+ "display:none",
74
+ "width:min(480px,100vw)",
75
+ "height:0",
76
+ "max-height:90vh",
77
+ "border:none",
78
+ "border-radius:16px",
79
+ "box-shadow:0 25px 50px rgba(0,0,0,0.4)",
80
+ "transition:height 0.2s ease",
81
+ "overflow:hidden"
82
+ ].join(";");
83
+ iframe.allow = "payment";
84
+ iframe.onload = () => {
85
+ spinner.remove();
86
+ iframe.style.display = "block";
87
+ };
88
+ const close = () => container.remove();
89
+ container.addEventListener("click", (e) => {
90
+ if (e.target === container) close();
91
+ });
92
+ window.addEventListener(
93
+ "message",
94
+ (e) => {
95
+ if (e.data?.type === "upay:close") close();
96
+ if (e.data?.type === "upay:height") {
97
+ const maxPx = window.innerHeight * 0.9;
98
+ iframe.style.height = `${Math.min(e.data.height, maxPx)}px`;
99
+ }
100
+ if (e.data?.type === "upay:success") {
101
+ close();
102
+ window.dispatchEvent(
103
+ new CustomEvent("upay:payment-success", { detail: e.data.payment })
104
+ );
105
+ }
106
+ },
107
+ { once: false }
108
+ );
109
+ container.appendChild(spinner);
110
+ container.appendChild(iframe);
111
+ document.body.appendChild(container);
112
+ }
113
+ };
114
+
115
+ // src/UPayButton.tsx
116
+ var defaultStyles = {
117
+ button: {
118
+ display: "inline-flex",
119
+ alignItems: "center",
120
+ gap: "8px",
121
+ padding: "12px 24px",
122
+ background: "linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)",
123
+ color: "#fff",
124
+ border: "none",
125
+ borderRadius: "10px",
126
+ fontSize: "15px",
127
+ fontWeight: "600",
128
+ fontFamily: "inherit",
129
+ cursor: "pointer",
130
+ transition: "opacity 0.15s, transform 0.1s",
131
+ minHeight: "44px",
132
+ letterSpacing: "-0.01em"
133
+ },
134
+ loading: {
135
+ opacity: 0.7,
136
+ cursor: "not-allowed"
137
+ }
138
+ };
139
+ var UPayLogo = () => /* @__PURE__ */ React.createElement(
140
+ "svg",
141
+ {
142
+ width: "18",
143
+ height: "18",
144
+ viewBox: "0 0 18 18",
145
+ fill: "none",
146
+ xmlns: "http://www.w3.org/2000/svg",
147
+ "aria-hidden": "true"
148
+ },
149
+ /* @__PURE__ */ React.createElement("circle", { cx: "9", cy: "9", r: "8.5", stroke: "rgba(255,255,255,0.6)" }),
150
+ /* @__PURE__ */ React.createElement(
151
+ "path",
152
+ {
153
+ d: "M5.5 6.5L9 11.5L12.5 6.5",
154
+ stroke: "white",
155
+ strokeWidth: "1.8",
156
+ strokeLinecap: "round",
157
+ strokeLinejoin: "round"
158
+ }
159
+ )
160
+ );
161
+ var Spinner = () => /* @__PURE__ */ React.createElement(
162
+ "svg",
163
+ {
164
+ width: "16",
165
+ height: "16",
166
+ viewBox: "0 0 16 16",
167
+ fill: "none",
168
+ "aria-hidden": "true",
169
+ style: { animation: "upay-spin 0.8s linear infinite" }
170
+ },
171
+ /* @__PURE__ */ React.createElement(
172
+ "circle",
173
+ {
174
+ cx: "8",
175
+ cy: "8",
176
+ r: "6",
177
+ stroke: "rgba(255,255,255,0.35)",
178
+ strokeWidth: "2"
179
+ }
180
+ ),
181
+ /* @__PURE__ */ React.createElement(
182
+ "path",
183
+ {
184
+ d: "M8 2a6 6 0 0 1 6 6",
185
+ stroke: "white",
186
+ strokeWidth: "2",
187
+ strokeLinecap: "round"
188
+ }
189
+ ),
190
+ /* @__PURE__ */ React.createElement("style", null, `@keyframes upay-spin{to{transform:rotate(360deg)}}`)
191
+ );
192
+ function UPayButton({
193
+ apiKey,
194
+ baseUrl,
195
+ amount,
196
+ token,
197
+ chain,
198
+ metadata,
199
+ onSuccess,
200
+ onError,
201
+ label = "Pay with UPay",
202
+ className
203
+ }) {
204
+ const [loading, setLoading] = useState(false);
205
+ const handleClick = useCallback(async () => {
206
+ if (loading) return;
207
+ setLoading(true);
208
+ try {
209
+ const client = new UPay({ apiKey, baseUrl });
210
+ const session = await client.createCheckout({
211
+ amount,
212
+ token,
213
+ chain,
214
+ metadata
215
+ });
216
+ client.openCheckout(session.id);
217
+ const handleSuccess = (e) => {
218
+ const payment = e.detail;
219
+ onSuccess?.(payment);
220
+ window.removeEventListener("upay:payment-success", handleSuccess);
221
+ };
222
+ window.addEventListener("upay:payment-success", handleSuccess);
223
+ } catch (err) {
224
+ const error = err instanceof Error ? err : new Error(String(err));
225
+ onError?.(error);
226
+ } finally {
227
+ setLoading(false);
228
+ }
229
+ }, [loading, apiKey, amount, token, chain, metadata, onSuccess, onError]);
230
+ return /* @__PURE__ */ React.createElement(
231
+ "button",
232
+ {
233
+ onClick: handleClick,
234
+ disabled: loading,
235
+ className,
236
+ style: className ? void 0 : {
237
+ ...defaultStyles.button,
238
+ ...loading ? defaultStyles.loading : {}
239
+ },
240
+ "aria-label": loading ? "Processing payment\u2026" : label,
241
+ "aria-busy": loading
242
+ },
243
+ loading ? /* @__PURE__ */ React.createElement(Spinner, null) : /* @__PURE__ */ React.createElement(UPayLogo, null),
244
+ /* @__PURE__ */ React.createElement("span", null, loading ? "Opening checkout\u2026" : label)
245
+ );
246
+ }
247
+ export {
248
+ UPay,
249
+ UPayButton
250
+ };
251
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/UPayButton.tsx","../src/client.ts"],"sourcesContent":["\"use client\";\n\nimport React, { useState, useCallback } from \"react\";\nimport { UPay } from \"./client\";\nimport type { UPayButtonProps, UPayPayment } from \"./types\";\n\nconst defaultStyles = {\n button: {\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"8px\",\n padding: \"12px 24px\",\n background: \"linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)\",\n color: \"#fff\",\n border: \"none\",\n borderRadius: \"10px\",\n fontSize: \"15px\",\n fontWeight: \"600\",\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n transition: \"opacity 0.15s, transform 0.1s\",\n minHeight: \"44px\",\n letterSpacing: \"-0.01em\",\n } as React.CSSProperties,\n loading: {\n opacity: 0.7,\n cursor: \"not-allowed\",\n } as React.CSSProperties,\n};\n\nconst UPayLogo = () => (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle cx=\"9\" cy=\"9\" r=\"8.5\" stroke=\"rgba(255,255,255,0.6)\" />\n <path\n d=\"M5.5 6.5L9 11.5L12.5 6.5\"\n stroke=\"white\"\n strokeWidth=\"1.8\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nconst Spinner = () => (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n aria-hidden=\"true\"\n style={{ animation: \"upay-spin 0.8s linear infinite\" }}\n >\n <circle\n cx=\"8\"\n cy=\"8\"\n r=\"6\"\n stroke=\"rgba(255,255,255,0.35)\"\n strokeWidth=\"2\"\n />\n <path\n d=\"M8 2a6 6 0 0 1 6 6\"\n stroke=\"white\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n <style>{`@keyframes upay-spin{to{transform:rotate(360deg)}}`}</style>\n </svg>\n);\n\nexport function UPayButton({\n apiKey,\n baseUrl,\n amount,\n token,\n chain,\n metadata,\n onSuccess,\n onError,\n label = \"Pay with UPay\",\n className,\n}: UPayButtonProps) {\n const [loading, setLoading] = useState(false);\n\n const handleClick = useCallback(async () => {\n if (loading) return;\n setLoading(true);\n\n try {\n const client = new UPay({ apiKey, baseUrl });\n const session = await client.createCheckout({\n amount,\n token,\n chain,\n metadata,\n });\n client.openCheckout(session.id);\n\n const handleSuccess = (e: Event) => {\n const payment = (e as CustomEvent<UPayPayment>).detail;\n onSuccess?.(payment);\n window.removeEventListener(\"upay:payment-success\", handleSuccess);\n };\n window.addEventListener(\"upay:payment-success\", handleSuccess);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error);\n } finally {\n setLoading(false);\n }\n }, [loading, apiKey, amount, token, chain, metadata, onSuccess, onError]);\n\n return (\n <button\n onClick={handleClick}\n disabled={loading}\n className={className}\n style={\n className\n ? undefined\n : {\n ...defaultStyles.button,\n ...(loading ? defaultStyles.loading : {}),\n }\n }\n aria-label={loading ? \"Processing payment…\" : label}\n aria-busy={loading}\n >\n {loading ? <Spinner /> : <UPayLogo />}\n <span>{loading ? \"Opening checkout…\" : label}</span>\n </button>\n );\n}\n","import type {\n UPayClientOptions,\n CreateCheckoutOptions,\n UPayCheckoutSession,\n} from \"./types\";\n\nconst DEFAULT_BASE_URL =\n typeof window !== \"undefined\"\n ? window.location.origin\n : \"http://localhost:3000\";\n\nexport class UPay {\n private apiKey: string;\n private baseUrl: string;\n\n constructor(options: UPayClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n }\n\n async createCheckout(\n options: CreateCheckoutOptions\n ): Promise<UPayCheckoutSession> {\n const res = await fetch(`${this.baseUrl}/api/v1/sessions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n amount: options.amount,\n token: options.token,\n chain: options.chain,\n metadata: options.metadata,\n success_url: options.successUrl,\n cancel_url: options.cancelUrl,\n }),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ error: \"Unknown error\" }));\n throw new Error(err.error ?? `HTTP ${res.status}`);\n }\n\n return res.json();\n }\n\n openCheckout(sessionId: string): void {\n const url = `${this.baseUrl}/checkout/${sessionId}`;\n\n if (typeof window === \"undefined\") return;\n\n const existingModal = document.getElementById(\"upay-modal-container\");\n if (existingModal) existingModal.remove();\n\n const container = document.createElement(\"div\");\n container.id = \"upay-modal-container\";\n container.style.cssText = [\n \"position:fixed\",\n \"inset:0\",\n \"z-index:2147483647\",\n \"display:flex\",\n \"align-items:center\",\n \"justify-content:center\",\n \"background:rgba(0,0,0,0.6)\",\n \"backdrop-filter:blur(4px)\",\n ].join(\";\");\n\n // Spinner shown while iframe loads\n const spinner = document.createElement(\"div\");\n spinner.style.cssText = [\n \"width:min(480px,100vw)\",\n \"height:min(700px,100vh)\",\n \"display:flex\",\n \"align-items:center\",\n \"justify-content:center\",\n \"border-radius:16px\",\n \"background:#fff\",\n ].join(\";\");\n spinner.innerHTML = `\n <style>@keyframes upay-modal-spin{to{transform:rotate(360deg)}}</style>\n <svg width=\"36\" height=\"36\" viewBox=\"0 0 36 36\" fill=\"none\"\n style=\"animation:upay-modal-spin 0.8s linear infinite\">\n <circle cx=\"18\" cy=\"18\" r=\"14\" stroke=\"#e5e7eb\" stroke-width=\"3\"/>\n <path d=\"M18 4a14 14 0 0 1 14 14\" stroke=\"#6366f1\"\n stroke-width=\"3\" stroke-linecap=\"round\"/>\n </svg>`;\n\n const iframe = document.createElement(\"iframe\");\n iframe.src = url;\n iframe.style.cssText = [\n \"display:none\",\n \"width:min(480px,100vw)\",\n \"height:0\",\n \"max-height:90vh\",\n \"border:none\",\n \"border-radius:16px\",\n \"box-shadow:0 25px 50px rgba(0,0,0,0.4)\",\n \"transition:height 0.2s ease\",\n \"overflow:hidden\",\n ].join(\";\");\n iframe.allow = \"payment\";\n iframe.onload = () => {\n spinner.remove();\n iframe.style.display = \"block\";\n };\n\n const close = (): void => container.remove();\n\n container.addEventListener(\"click\", (e) => {\n if (e.target === container) close();\n });\n\n window.addEventListener(\n \"message\",\n (e) => {\n if (e.data?.type === \"upay:close\") close();\n if (e.data?.type === \"upay:height\") {\n const maxPx = window.innerHeight * 0.9;\n iframe.style.height = `${Math.min(e.data.height, maxPx)}px`;\n }\n if (e.data?.type === \"upay:success\") {\n close();\n window.dispatchEvent(\n new CustomEvent(\"upay:payment-success\", { detail: e.data.payment })\n );\n }\n },\n { once: false }\n );\n\n container.appendChild(spinner);\n container.appendChild(iframe);\n document.body.appendChild(container);\n }\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@alphadevs_labs/upay-sdk",
3
+ "version": "0.0.1",
4
+ "description": "UPay SDK — UPayButton React component and imperative client",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/0xyshv/upay"
12
+ },
13
+ "main": "./dist/index.js",
14
+ "module": "./dist/index.mjs",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.mjs",
20
+ "require": "./dist/index.js"
21
+ }
22
+ },
23
+ "files": ["dist"],
24
+ "scripts": {
25
+ "build": "tsup",
26
+ "dev": "tsup --watch",
27
+ "type-check": "tsc --noEmit"
28
+ },
29
+ "peerDependencies": {
30
+ "react": ">=18",
31
+ "react-dom": ">=18"
32
+ },
33
+ "devDependencies": {
34
+ "@types/react": "^18.2.0",
35
+ "@types/react-dom": "^18.2.0",
36
+ "react": "^18.2.0",
37
+ "react-dom": "^18.2.0",
38
+ "tsup": "^8.0.0",
39
+ "typescript": "^5.3.3"
40
+ }
41
+ }