payluk-escrow-inline-checkout 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,196 @@
1
+ # Escrow Checkout JS/TS SDK
2
+
3
+ A lightweight client SDK that initializes your checkout configuration, creates a session via your API, and launches the escrow checkout widget. Includes a React hook for easy integration in React apps.
4
+
5
+ - Zero manual script tags: the widget script is loaded automatically.
6
+ - Promise-based API.
7
+ - First-class TypeScript types.
8
+ - Optional React hook with loading/error state.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm i payluk-escrow-inline-checkout
14
+ ```
15
+
16
+ ## Quick Start (Vanilla JS/TS)
17
+
18
+ ```ts
19
+ // app.ts
20
+ import { initEscrowCheckout, pay } from 'payluk-escrow-inline-checkout';
21
+
22
+ // 1) Initialize once at app startup
23
+ initEscrowCheckout({
24
+ apiBaseUrl: 'https://api.example.com', // your backend base URL
25
+ publicKey: '<YOUR_PUBLISHABLE_KEY>' // publishable key only
26
+ });
27
+
28
+ // 2) Trigger a payment flow (e.g., on a button click)
29
+ async function onPayClick() {
30
+ try {
31
+ await pay({
32
+ paymentToken: '<PAYMENT_TOKEN_FROM_YOUR_BACKEND_OR_PROVIDER>',
33
+ reference: '<ORDER_OR_REFERENCE_ID>',
34
+ redirectUrl: 'https://your-app.example.com/checkout/complete',
35
+ logoUrl: 'https://your-cdn.example.com/logo.png', // optional
36
+ brand: 'YourBrand', // optional
37
+ extra: { theme: 'dark' }, // optional
38
+ callback: (result) => {
39
+ console.log('Checkout result:', result);
40
+ },
41
+ onClose: () => {
42
+ console.log('Widget closed');
43
+ }
44
+ });
45
+ } catch (err) {
46
+ console.error('Payment failed:', err);
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## React Usage
52
+
53
+ ```tsx
54
+ // CheckoutButton.tsx
55
+ import React from 'react';
56
+ import { useEscrowCheckout } from 'payluk-escrow-inline-checkout/react';
57
+
58
+ export function CheckoutButton() {
59
+ const { pay, loading, error, ready } = useEscrowCheckout();
60
+
61
+ const handleClick = async () => {
62
+ try {
63
+ await pay({
64
+ paymentToken: '<PAYMENT_TOKEN>',
65
+ reference: '<ORDER_OR_REFERENCE_ID>',
66
+ redirectUrl: 'https://your-app.example.com/checkout/complete',
67
+ logoUrl: 'https://your-cdn.example.com/logo.png',
68
+ brand: 'YourBrand',
69
+ extra: { theme: 'light' },
70
+ callback: (result) => console.log(result)
71
+ });
72
+ } catch {
73
+ // error is also exposed via `error` state
74
+ }
75
+ };
76
+
77
+ return (
78
+ <button onClick={handleClick} disabled={loading || !ready}>
79
+ {loading ? 'Processing…' : 'Pay now'}
80
+ {!ready && <span>Preparing checkout…</span>}
81
+ {error && <small style={{ color: 'red' }}>{error.message}</small>}
82
+ </button>
83
+ );
84
+ }
85
+ ```
86
+
87
+ **Note:** In React apps, call `initEscrowCheckout(...)` once in your app bootstrap (e.g., in the root component or an app initializer). The hook uses that configuration.
88
+
89
+ **Important:**
90
+ - Only use publishable keys in the browser. Keep any secret keys on your server.
91
+ - Validate inputs on your backend and return the required session payload.
92
+
93
+ ## API
94
+
95
+ ### `initEscrowCheckout(config)`
96
+
97
+ Initializes the SDK. Must be called before any `pay(...)`.
98
+
99
+ **Required:**
100
+ - `apiBaseUrl`: `string` — your backend base URL (no trailing slash required)
101
+ - `publicKey`: `string` — publishable key only
102
+
103
+ **Advanced (optional):**
104
+ - `scriptUrlOverride?`: `string` — custom widget script URL
105
+ - `globalName?`: `string` — custom global widget function name
106
+ - `crossOrigin?`: `'' | 'anonymous' | 'use-credentials'` — script tag crossOrigin
107
+
108
+ **Example:**
109
+
110
+ ```ts
111
+ import { initEscrowCheckout } from 'payluk-escrow-inline-checkout';
112
+
113
+ initEscrowCheckout({
114
+ apiBaseUrl: 'https://api.example.com',
115
+ publicKey: '<YOUR_PUBLISHABLE_KEY>',
116
+ // scriptUrlOverride: 'https://cdn.example.com/custom-widget.js',
117
+ // globalName: 'EscrowCheckout',
118
+ // crossOrigin: 'anonymous'
119
+ });
120
+ ```
121
+
122
+ ### `pay(input): Promise<void>`
123
+
124
+ Creates a checkout session via your backend and opens the widget.
125
+
126
+ **Required:**
127
+ - `paymentToken`: `string`
128
+ - `reference`: `string`
129
+ - `redirectUrl`: `string`
130
+
131
+ **Optional:**
132
+ - `logoUrl?`: `string`
133
+ - `brand?`: `string`
134
+ - `extra?`: `Record<string, unknown>`
135
+ - `callback?`: `(result: unknown) => void`
136
+ - `onClose?`: `() => void`
137
+
138
+ **Returns:**
139
+ - `Promise<void>` that resolves when the widget is opened (and rejects on errors).
140
+
141
+ ### `useEscrowCheckout(): { ready, loading, error, pay }`
142
+
143
+ React hook that exposes:
144
+ - `ready`: `boolean` — becomes true after a successful load/pay attempt
145
+ - `loading`: `boolean` — true while pay is running
146
+ - `error`: `Error | null` — last error encountered
147
+ - `pay`: same function as `pay(...)`
148
+
149
+ **Import:**
150
+
151
+ ```ts
152
+ import { useEscrowCheckout } from 'payluk-escrow-inline-checkout/react';
153
+ ```
154
+
155
+ ## Framework and SSR Notes
156
+
157
+ - **Browser-only:** `pay(...)` and the widget require `window`. Avoid calling them during server-side rendering.
158
+ - **Initialize on the client:** If using frameworks like Next.js, call `initEscrowCheckout(...)` in a client component or in an effect.
159
+ - **Preloading:** The hook marks `ready` after the first successful `pay`. If you need earlier preloading, you can trigger a preparatory flow (depending on your setup).
160
+
161
+ ## Error Handling
162
+
163
+ Common issues:
164
+ - **Not initialized:** Ensure `initEscrowCheckout({ apiBaseUrl, publicKey })` is called before `pay(...)`.
165
+ - **Browser-only:** Do not call `pay(...)` on the server.
166
+ - **Network/API errors:** If the session endpoint fails, `pay(...)` will reject with the error message from your backend (if any).
167
+
168
+ **Example:**
169
+
170
+ ```ts
171
+ try {
172
+ await pay({ /* ... */ });
173
+ } catch (err) {
174
+ alert((err as Error).message);
175
+ }
176
+ ```
177
+
178
+ ## Security
179
+
180
+ - Use only publishable keys in the client.
181
+ - Keep any secret or private keys on your server.
182
+ - Validate and authorize requests on your backend before creating sessions.
183
+
184
+ ## Types
185
+
186
+ This package ships with TypeScript types. No additional type packages are required.
187
+
188
+ ## Contributing
189
+
190
+ - Install dependencies: `npm install`
191
+ - Build: `npm run build`
192
+ - Lint/Test: add scripts as needed for your project
193
+
194
+ ## License
195
+
196
+ MIT (or your chosen license)
@@ -0,0 +1,87 @@
1
+ // src/index.ts
2
+ var DEFAULT_SCRIPT_URL = "https://checkout.payluk.ng/escrow-checkout.min.js";
3
+ var DEFAULT_GLOBAL_NAME = "EscrowCheckout";
4
+ var CONFIG = null;
5
+ function initEscrowCheckout(config) {
6
+ if (!config?.publicKey) throw new Error('initEscrowCheckout: "publicKey" is required.');
7
+ CONFIG = {
8
+ publicKey: config.publicKey,
9
+ scriptUrl: config.scriptUrlOverride || DEFAULT_SCRIPT_URL,
10
+ globalName: config.globalName || DEFAULT_GLOBAL_NAME,
11
+ crossOrigin: config.crossOrigin ?? "anonymous"
12
+ };
13
+ }
14
+ function assertConfigured(config) {
15
+ if (!config) {
16
+ throw new Error("Escrow checkout not initialized. Call initEscrowCheckout({ apiBaseUrl, publicKey }) first.");
17
+ }
18
+ }
19
+ async function loadWidget() {
20
+ assertConfigured(CONFIG);
21
+ const { scriptUrl, globalName, crossOrigin } = CONFIG;
22
+ if (typeof window === "undefined") {
23
+ throw new Error("EscrowCheckout can only be loaded in the browser.");
24
+ }
25
+ const win = window;
26
+ win.__escrowCheckoutLoader ?? (win.__escrowCheckoutLoader = {});
27
+ if (win.__escrowCheckoutLoader[scriptUrl]) {
28
+ return win.__escrowCheckoutLoader[scriptUrl];
29
+ }
30
+ if (typeof win[globalName] === "function") {
31
+ const fn = win[globalName];
32
+ win.__escrowCheckoutLoader[scriptUrl] = Promise.resolve(fn);
33
+ return fn;
34
+ }
35
+ win.__escrowCheckoutLoader[scriptUrl] = new Promise((resolve, reject) => {
36
+ const script = document.createElement("script");
37
+ script.src = scriptUrl;
38
+ script.async = true;
39
+ if (crossOrigin) script.crossOrigin = crossOrigin;
40
+ script.onload = () => {
41
+ const fn = win[globalName];
42
+ if (typeof fn === "function") resolve(fn);
43
+ else reject(new Error(`Escrow checkout script loaded, but window.${globalName} is not a function.`));
44
+ };
45
+ script.onerror = () => reject(new Error(`Failed to load escrow checkout script: ${scriptUrl}`));
46
+ document.head.appendChild(script);
47
+ });
48
+ return win.__escrowCheckoutLoader[scriptUrl];
49
+ }
50
+ async function createSession(input) {
51
+ assertConfigured(CONFIG);
52
+ const { publicKey } = CONFIG;
53
+ const apiBaseUrl = "https://live.payluk.ng";
54
+ const resp = await fetch(`${apiBaseUrl}/v1/checkout/session`, {
55
+ method: "POST",
56
+ headers: { "Content-Type": "application/json" },
57
+ body: JSON.stringify({
58
+ paymentToken: input.paymentToken,
59
+ redirectUrl: input.redirectUrl,
60
+ reference: input.reference,
61
+ publicKey
62
+ })
63
+ });
64
+ if (!resp.ok) {
65
+ const err = await resp.json().catch(() => ({}));
66
+ throw new Error(err.message || "Failed to create session");
67
+ }
68
+ return await resp.json();
69
+ }
70
+ async function pay(input) {
71
+ if (typeof window === "undefined") {
72
+ throw new Error("pay(...) can only run in the browser.");
73
+ }
74
+ const [{ session }, widget] = await Promise.all([createSession(input), loadWidget()]);
75
+ widget({
76
+ session,
77
+ logoUrl: input.logoUrl,
78
+ brand: input.brand,
79
+ callback: input.callback,
80
+ onClose: input.onClose,
81
+ ...input.extra ?? {}
82
+ });
83
+ }
84
+
85
+ export { initEscrowCheckout, pay };
86
+ //# sourceMappingURL=chunk-D6ZMSUAT.js.map
87
+ //# sourceMappingURL=chunk-D6ZMSUAT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"chunk-D6ZMSUAT.js","sourcesContent":["export type EscrowWidget = (options: Record<string, unknown>) => void;\r\n\r\nexport interface InitConfig {\r\n publicKey: string; // publishable key only\r\n /**\r\n * Optional overrides for experts. End users don't need to set these.\r\n */\r\n scriptUrlOverride?: string;\r\n globalName?: string; // default 'EscrowCheckout'\r\n crossOrigin?: '' | 'anonymous' | 'use-credentials';\r\n}\r\n\r\nexport interface PayInput {\r\n paymentToken: string;\r\n reference: string;\r\n redirectUrl: string;\r\n logoUrl?: string;\r\n brand?: string;\r\n /**\r\n * Extra fields supported by the widget.\r\n */\r\n extra?: Record<string, unknown>;\r\n callback?: (result: any) => void;\r\n onClose?: () => void;\r\n}\r\n\r\nexport interface SessionResponse {\r\n session: unknown;\r\n}\r\n\r\nconst DEFAULT_SCRIPT_URL = 'https://checkout.payluk.ng/escrow-checkout.min.js';\r\nconst DEFAULT_GLOBAL_NAME = 'EscrowCheckout';\r\n\r\ntype ResolvedConfig = Required<Pick<InitConfig, 'publicKey'>> & {\r\n scriptUrl: string;\r\n globalName: string;\r\n crossOrigin: '' | 'anonymous' | 'use-credentials';\r\n};\r\n\r\nlet CONFIG: ResolvedConfig | null = null;\r\n\r\n/**\r\n * Initialize the library once (e.g., in app bootstrap).\r\n * Hides script URL and session creation from consumers.\r\n */\r\nexport function initEscrowCheckout(config: InitConfig): void {\r\n if (!config?.publicKey) throw new Error('initEscrowCheckout: \"publicKey\" is required.');\r\n CONFIG = {\r\n publicKey: config.publicKey,\r\n scriptUrl: config.scriptUrlOverride || DEFAULT_SCRIPT_URL,\r\n globalName: config.globalName || DEFAULT_GLOBAL_NAME,\r\n crossOrigin: config.crossOrigin ?? 'anonymous'\r\n };\r\n}\r\n\r\n/**\r\n * Narrow a provided config to ResolvedConfig or throw if not initialized.\r\n */\r\nfunction assertConfigured(config: ResolvedConfig | null): asserts config is ResolvedConfig {\r\n if (!config) {\r\n throw new Error('Escrow checkout not initialized. Call initEscrowCheckout({ apiBaseUrl, publicKey }) first.');\r\n }\r\n}\r\n\r\n/**\r\n * Internal: load the widget script once and return the global function.\r\n */\r\nasync function loadWidget(): Promise<EscrowWidget> {\r\n assertConfigured(CONFIG);\r\n const { scriptUrl, globalName, crossOrigin } = CONFIG;\r\n\r\n if (typeof window === 'undefined') {\r\n throw new Error('EscrowCheckout can only be loaded in the browser.');\r\n }\r\n\r\n const win = window as any;\r\n win.__escrowCheckoutLoader ??= {};\r\n\r\n if (win.__escrowCheckoutLoader[scriptUrl]) {\r\n return win.__escrowCheckoutLoader[scriptUrl];\r\n }\r\n\r\n if (typeof win[globalName] === 'function') {\r\n const fn = win[globalName] as EscrowWidget;\r\n win.__escrowCheckoutLoader[scriptUrl] = Promise.resolve(fn);\r\n return fn;\r\n }\r\n\r\n win.__escrowCheckoutLoader[scriptUrl] = new Promise<EscrowWidget>((resolve, reject) => {\r\n const script = document.createElement('script');\r\n script.src = scriptUrl;\r\n script.async = true;\r\n if (crossOrigin) script.crossOrigin = crossOrigin;\r\n\r\n script.onload = () => {\r\n const fn = win[globalName];\r\n if (typeof fn === 'function') resolve(fn as EscrowWidget);\r\n else reject(new Error(`Escrow checkout script loaded, but window.${globalName} is not a function.`));\r\n };\r\n\r\n script.onerror = () => reject(new Error(`Failed to load escrow checkout script: ${scriptUrl}`));\r\n\r\n document.head.appendChild(script);\r\n });\r\n\r\n return win.__escrowCheckoutLoader[scriptUrl];\r\n}\r\n\r\n/**\r\n * Internal: create a checkout session by calling your API.\r\n * This is intentionally inside the lib (user doesn't implement it).\r\n */\r\nasync function createSession(input: PayInput): Promise<SessionResponse> {\r\n assertConfigured(CONFIG);\r\n const { publicKey } = CONFIG;\r\n const apiBaseUrl = 'https://live.payluk.ng';\r\n\r\n const resp = await fetch(`${apiBaseUrl}/v1/checkout/session`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n paymentToken: input.paymentToken,\r\n redirectUrl: input.redirectUrl,\r\n reference: input.reference,\r\n publicKey\r\n })\r\n });\r\n\r\n if (!resp.ok) {\r\n const err = await resp.json().catch(() => ({}));\r\n throw new Error(err.message || 'Failed to create session');\r\n }\r\n\r\n return (await resp.json()) as SessionResponse;\r\n}\r\n\r\n/**\r\n * Public API: create the session and open the widget.\r\n * Consumers only supply business inputs (no script URL, no API calls).\r\n */\r\nexport async function pay(input: PayInput): Promise<void> {\r\n if (typeof window === 'undefined') {\r\n throw new Error('pay(...) can only run in the browser.');\r\n }\r\n\r\n const [{ session }, widget] = await Promise.all([createSession(input), loadWidget()]);\r\n\r\n widget({\r\n session,\r\n logoUrl: input.logoUrl,\r\n brand: input.brand,\r\n callback: input.callback,\r\n onClose: input.onClose,\r\n ...(input.extra ?? {})\r\n });\r\n}"]}
package/dist/index.cjs ADDED
@@ -0,0 +1,90 @@
1
+ 'use strict';
2
+
3
+ // src/index.ts
4
+ var DEFAULT_SCRIPT_URL = "https://checkout.payluk.ng/escrow-checkout.min.js";
5
+ var DEFAULT_GLOBAL_NAME = "EscrowCheckout";
6
+ var CONFIG = null;
7
+ function initEscrowCheckout(config) {
8
+ if (!config?.publicKey) throw new Error('initEscrowCheckout: "publicKey" is required.');
9
+ CONFIG = {
10
+ publicKey: config.publicKey,
11
+ scriptUrl: config.scriptUrlOverride || DEFAULT_SCRIPT_URL,
12
+ globalName: config.globalName || DEFAULT_GLOBAL_NAME,
13
+ crossOrigin: config.crossOrigin ?? "anonymous"
14
+ };
15
+ }
16
+ function assertConfigured(config) {
17
+ if (!config) {
18
+ throw new Error("Escrow checkout not initialized. Call initEscrowCheckout({ apiBaseUrl, publicKey }) first.");
19
+ }
20
+ }
21
+ async function loadWidget() {
22
+ assertConfigured(CONFIG);
23
+ const { scriptUrl, globalName, crossOrigin } = CONFIG;
24
+ if (typeof window === "undefined") {
25
+ throw new Error("EscrowCheckout can only be loaded in the browser.");
26
+ }
27
+ const win = window;
28
+ win.__escrowCheckoutLoader ?? (win.__escrowCheckoutLoader = {});
29
+ if (win.__escrowCheckoutLoader[scriptUrl]) {
30
+ return win.__escrowCheckoutLoader[scriptUrl];
31
+ }
32
+ if (typeof win[globalName] === "function") {
33
+ const fn = win[globalName];
34
+ win.__escrowCheckoutLoader[scriptUrl] = Promise.resolve(fn);
35
+ return fn;
36
+ }
37
+ win.__escrowCheckoutLoader[scriptUrl] = new Promise((resolve, reject) => {
38
+ const script = document.createElement("script");
39
+ script.src = scriptUrl;
40
+ script.async = true;
41
+ if (crossOrigin) script.crossOrigin = crossOrigin;
42
+ script.onload = () => {
43
+ const fn = win[globalName];
44
+ if (typeof fn === "function") resolve(fn);
45
+ else reject(new Error(`Escrow checkout script loaded, but window.${globalName} is not a function.`));
46
+ };
47
+ script.onerror = () => reject(new Error(`Failed to load escrow checkout script: ${scriptUrl}`));
48
+ document.head.appendChild(script);
49
+ });
50
+ return win.__escrowCheckoutLoader[scriptUrl];
51
+ }
52
+ async function createSession(input) {
53
+ assertConfigured(CONFIG);
54
+ const { publicKey } = CONFIG;
55
+ const apiBaseUrl = "https://live.payluk.ng";
56
+ const resp = await fetch(`${apiBaseUrl}/v1/checkout/session`, {
57
+ method: "POST",
58
+ headers: { "Content-Type": "application/json" },
59
+ body: JSON.stringify({
60
+ paymentToken: input.paymentToken,
61
+ redirectUrl: input.redirectUrl,
62
+ reference: input.reference,
63
+ publicKey
64
+ })
65
+ });
66
+ if (!resp.ok) {
67
+ const err = await resp.json().catch(() => ({}));
68
+ throw new Error(err.message || "Failed to create session");
69
+ }
70
+ return await resp.json();
71
+ }
72
+ async function pay(input) {
73
+ if (typeof window === "undefined") {
74
+ throw new Error("pay(...) can only run in the browser.");
75
+ }
76
+ const [{ session }, widget] = await Promise.all([createSession(input), loadWidget()]);
77
+ widget({
78
+ session,
79
+ logoUrl: input.logoUrl,
80
+ brand: input.brand,
81
+ callback: input.callback,
82
+ onClose: input.onClose,
83
+ ...input.extra ?? {}
84
+ });
85
+ }
86
+
87
+ exports.initEscrowCheckout = initEscrowCheckout;
88
+ exports.pay = pay;
89
+ //# sourceMappingURL=index.cjs.map
90
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export type EscrowWidget = (options: Record<string, unknown>) => void;\r\n\r\nexport interface InitConfig {\r\n publicKey: string; // publishable key only\r\n /**\r\n * Optional overrides for experts. End users don't need to set these.\r\n */\r\n scriptUrlOverride?: string;\r\n globalName?: string; // default 'EscrowCheckout'\r\n crossOrigin?: '' | 'anonymous' | 'use-credentials';\r\n}\r\n\r\nexport interface PayInput {\r\n paymentToken: string;\r\n reference: string;\r\n redirectUrl: string;\r\n logoUrl?: string;\r\n brand?: string;\r\n /**\r\n * Extra fields supported by the widget.\r\n */\r\n extra?: Record<string, unknown>;\r\n callback?: (result: any) => void;\r\n onClose?: () => void;\r\n}\r\n\r\nexport interface SessionResponse {\r\n session: unknown;\r\n}\r\n\r\nconst DEFAULT_SCRIPT_URL = 'https://checkout.payluk.ng/escrow-checkout.min.js';\r\nconst DEFAULT_GLOBAL_NAME = 'EscrowCheckout';\r\n\r\ntype ResolvedConfig = Required<Pick<InitConfig, 'publicKey'>> & {\r\n scriptUrl: string;\r\n globalName: string;\r\n crossOrigin: '' | 'anonymous' | 'use-credentials';\r\n};\r\n\r\nlet CONFIG: ResolvedConfig | null = null;\r\n\r\n/**\r\n * Initialize the library once (e.g., in app bootstrap).\r\n * Hides script URL and session creation from consumers.\r\n */\r\nexport function initEscrowCheckout(config: InitConfig): void {\r\n if (!config?.publicKey) throw new Error('initEscrowCheckout: \"publicKey\" is required.');\r\n CONFIG = {\r\n publicKey: config.publicKey,\r\n scriptUrl: config.scriptUrlOverride || DEFAULT_SCRIPT_URL,\r\n globalName: config.globalName || DEFAULT_GLOBAL_NAME,\r\n crossOrigin: config.crossOrigin ?? 'anonymous'\r\n };\r\n}\r\n\r\n/**\r\n * Narrow a provided config to ResolvedConfig or throw if not initialized.\r\n */\r\nfunction assertConfigured(config: ResolvedConfig | null): asserts config is ResolvedConfig {\r\n if (!config) {\r\n throw new Error('Escrow checkout not initialized. Call initEscrowCheckout({ apiBaseUrl, publicKey }) first.');\r\n }\r\n}\r\n\r\n/**\r\n * Internal: load the widget script once and return the global function.\r\n */\r\nasync function loadWidget(): Promise<EscrowWidget> {\r\n assertConfigured(CONFIG);\r\n const { scriptUrl, globalName, crossOrigin } = CONFIG;\r\n\r\n if (typeof window === 'undefined') {\r\n throw new Error('EscrowCheckout can only be loaded in the browser.');\r\n }\r\n\r\n const win = window as any;\r\n win.__escrowCheckoutLoader ??= {};\r\n\r\n if (win.__escrowCheckoutLoader[scriptUrl]) {\r\n return win.__escrowCheckoutLoader[scriptUrl];\r\n }\r\n\r\n if (typeof win[globalName] === 'function') {\r\n const fn = win[globalName] as EscrowWidget;\r\n win.__escrowCheckoutLoader[scriptUrl] = Promise.resolve(fn);\r\n return fn;\r\n }\r\n\r\n win.__escrowCheckoutLoader[scriptUrl] = new Promise<EscrowWidget>((resolve, reject) => {\r\n const script = document.createElement('script');\r\n script.src = scriptUrl;\r\n script.async = true;\r\n if (crossOrigin) script.crossOrigin = crossOrigin;\r\n\r\n script.onload = () => {\r\n const fn = win[globalName];\r\n if (typeof fn === 'function') resolve(fn as EscrowWidget);\r\n else reject(new Error(`Escrow checkout script loaded, but window.${globalName} is not a function.`));\r\n };\r\n\r\n script.onerror = () => reject(new Error(`Failed to load escrow checkout script: ${scriptUrl}`));\r\n\r\n document.head.appendChild(script);\r\n });\r\n\r\n return win.__escrowCheckoutLoader[scriptUrl];\r\n}\r\n\r\n/**\r\n * Internal: create a checkout session by calling your API.\r\n * This is intentionally inside the lib (user doesn't implement it).\r\n */\r\nasync function createSession(input: PayInput): Promise<SessionResponse> {\r\n assertConfigured(CONFIG);\r\n const { publicKey } = CONFIG;\r\n const apiBaseUrl = 'https://live.payluk.ng';\r\n\r\n const resp = await fetch(`${apiBaseUrl}/v1/checkout/session`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n paymentToken: input.paymentToken,\r\n redirectUrl: input.redirectUrl,\r\n reference: input.reference,\r\n publicKey\r\n })\r\n });\r\n\r\n if (!resp.ok) {\r\n const err = await resp.json().catch(() => ({}));\r\n throw new Error(err.message || 'Failed to create session');\r\n }\r\n\r\n return (await resp.json()) as SessionResponse;\r\n}\r\n\r\n/**\r\n * Public API: create the session and open the widget.\r\n * Consumers only supply business inputs (no script URL, no API calls).\r\n */\r\nexport async function pay(input: PayInput): Promise<void> {\r\n if (typeof window === 'undefined') {\r\n throw new Error('pay(...) can only run in the browser.');\r\n }\r\n\r\n const [{ session }, widget] = await Promise.all([createSession(input), loadWidget()]);\r\n\r\n widget({\r\n session,\r\n logoUrl: input.logoUrl,\r\n brand: input.brand,\r\n callback: input.callback,\r\n onClose: input.onClose,\r\n ...(input.extra ?? {})\r\n });\r\n}"]}
@@ -0,0 +1,38 @@
1
+ type EscrowWidget = (options: Record<string, unknown>) => void;
2
+ interface InitConfig {
3
+ publicKey: string;
4
+ /**
5
+ * Optional overrides for experts. End users don't need to set these.
6
+ */
7
+ scriptUrlOverride?: string;
8
+ globalName?: string;
9
+ crossOrigin?: '' | 'anonymous' | 'use-credentials';
10
+ }
11
+ interface PayInput {
12
+ paymentToken: string;
13
+ reference: string;
14
+ redirectUrl: string;
15
+ logoUrl?: string;
16
+ brand?: string;
17
+ /**
18
+ * Extra fields supported by the widget.
19
+ */
20
+ extra?: Record<string, unknown>;
21
+ callback?: (result: any) => void;
22
+ onClose?: () => void;
23
+ }
24
+ interface SessionResponse {
25
+ session: unknown;
26
+ }
27
+ /**
28
+ * Initialize the library once (e.g., in app bootstrap).
29
+ * Hides script URL and session creation from consumers.
30
+ */
31
+ declare function initEscrowCheckout(config: InitConfig): void;
32
+ /**
33
+ * Public API: create the session and open the widget.
34
+ * Consumers only supply business inputs (no script URL, no API calls).
35
+ */
36
+ declare function pay(input: PayInput): Promise<void>;
37
+
38
+ export { type EscrowWidget, type InitConfig, type PayInput, type SessionResponse, initEscrowCheckout, pay };
@@ -0,0 +1,38 @@
1
+ type EscrowWidget = (options: Record<string, unknown>) => void;
2
+ interface InitConfig {
3
+ publicKey: string;
4
+ /**
5
+ * Optional overrides for experts. End users don't need to set these.
6
+ */
7
+ scriptUrlOverride?: string;
8
+ globalName?: string;
9
+ crossOrigin?: '' | 'anonymous' | 'use-credentials';
10
+ }
11
+ interface PayInput {
12
+ paymentToken: string;
13
+ reference: string;
14
+ redirectUrl: string;
15
+ logoUrl?: string;
16
+ brand?: string;
17
+ /**
18
+ * Extra fields supported by the widget.
19
+ */
20
+ extra?: Record<string, unknown>;
21
+ callback?: (result: any) => void;
22
+ onClose?: () => void;
23
+ }
24
+ interface SessionResponse {
25
+ session: unknown;
26
+ }
27
+ /**
28
+ * Initialize the library once (e.g., in app bootstrap).
29
+ * Hides script URL and session creation from consumers.
30
+ */
31
+ declare function initEscrowCheckout(config: InitConfig): void;
32
+ /**
33
+ * Public API: create the session and open the widget.
34
+ * Consumers only supply business inputs (no script URL, no API calls).
35
+ */
36
+ declare function pay(input: PayInput): Promise<void>;
37
+
38
+ export { type EscrowWidget, type InitConfig, type PayInput, type SessionResponse, initEscrowCheckout, pay };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { initEscrowCheckout, pay } from './chunk-D6ZMSUAT.js';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,150 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+
6
+ // src/react/useEscrowCheckout.ts
7
+
8
+ // src/index.ts
9
+ var CONFIG = null;
10
+ function assertConfigured(config) {
11
+ {
12
+ throw new Error("Escrow checkout not initialized. Call initEscrowCheckout({ apiBaseUrl, publicKey }) first.");
13
+ }
14
+ }
15
+ async function loadWidget() {
16
+ assertConfigured();
17
+ const { scriptUrl, globalName, crossOrigin } = CONFIG;
18
+ if (typeof window === "undefined") {
19
+ throw new Error("EscrowCheckout can only be loaded in the browser.");
20
+ }
21
+ const win = window;
22
+ win.__escrowCheckoutLoader ?? (win.__escrowCheckoutLoader = {});
23
+ if (win.__escrowCheckoutLoader[scriptUrl]) {
24
+ return win.__escrowCheckoutLoader[scriptUrl];
25
+ }
26
+ if (typeof win[globalName] === "function") {
27
+ const fn = win[globalName];
28
+ win.__escrowCheckoutLoader[scriptUrl] = Promise.resolve(fn);
29
+ return fn;
30
+ }
31
+ win.__escrowCheckoutLoader[scriptUrl] = new Promise((resolve, reject) => {
32
+ const script = document.createElement("script");
33
+ script.src = scriptUrl;
34
+ script.async = true;
35
+ if (crossOrigin) script.crossOrigin = crossOrigin;
36
+ script.onload = () => {
37
+ const fn = win[globalName];
38
+ if (typeof fn === "function") resolve(fn);
39
+ else reject(new Error(`Escrow checkout script loaded, but window.${globalName} is not a function.`));
40
+ };
41
+ script.onerror = () => reject(new Error(`Failed to load escrow checkout script: ${scriptUrl}`));
42
+ document.head.appendChild(script);
43
+ });
44
+ return win.__escrowCheckoutLoader[scriptUrl];
45
+ }
46
+ async function createSession(input) {
47
+ assertConfigured();
48
+ const { publicKey } = CONFIG;
49
+ const apiBaseUrl = "https://live.payluk.ng";
50
+ const resp = await fetch(`${apiBaseUrl}/v1/checkout/session`, {
51
+ method: "POST",
52
+ headers: { "Content-Type": "application/json" },
53
+ body: JSON.stringify({
54
+ paymentToken: input.paymentToken,
55
+ redirectUrl: input.redirectUrl,
56
+ reference: input.reference,
57
+ publicKey
58
+ })
59
+ });
60
+ if (!resp.ok) {
61
+ const err = await resp.json().catch(() => ({}));
62
+ throw new Error(err.message || "Failed to create session");
63
+ }
64
+ return await resp.json();
65
+ }
66
+ async function pay(input) {
67
+ if (typeof window === "undefined") {
68
+ throw new Error("pay(...) can only run in the browser.");
69
+ }
70
+ const [{ session }, widget] = await Promise.all([createSession(input), loadWidget()]);
71
+ widget({
72
+ session,
73
+ logoUrl: input.logoUrl,
74
+ brand: input.brand,
75
+ callback: input.callback,
76
+ onClose: input.onClose,
77
+ ...input.extra ?? {}
78
+ });
79
+ }
80
+
81
+ // src/react/useEscrowCheckout.ts
82
+ function useEscrowCheckout() {
83
+ const [ready, setReady] = react.useState(false);
84
+ const [loading, setLoading] = react.useState(() => typeof window !== "undefined");
85
+ const [error, setError] = react.useState(null);
86
+ const pay2 = react.useCallback(async (input) => {
87
+ setLoading(true);
88
+ try {
89
+ await pay(input);
90
+ setReady(true);
91
+ setError(null);
92
+ } catch (e) {
93
+ setError(e);
94
+ throw e;
95
+ } finally {
96
+ setLoading(false);
97
+ }
98
+ }, []);
99
+ react.useEffect(() => {
100
+ if (typeof window === "undefined") {
101
+ setLoading(false);
102
+ }
103
+ }, []);
104
+ return react.useMemo(() => ({ ready, loading, error, pay: pay2 }), [ready, loading, error, pay2]);
105
+ }
106
+ function EscrowCheckoutButton({
107
+ paymentToken,
108
+ reference,
109
+ redirectUrl,
110
+ brand,
111
+ logoUrl,
112
+ callback,
113
+ onClose,
114
+ extra,
115
+ children = "Pay",
116
+ disabled,
117
+ className,
118
+ title
119
+ }) {
120
+ const { ready, loading, error, pay: pay2 } = useEscrowCheckout();
121
+ const handleClick = react.useCallback(async () => {
122
+ await pay2({
123
+ paymentToken,
124
+ reference,
125
+ redirectUrl,
126
+ brand,
127
+ logoUrl,
128
+ callback,
129
+ onClose,
130
+ extra
131
+ });
132
+ }, [pay2, paymentToken, reference, redirectUrl, brand, logoUrl, callback, onClose, extra]);
133
+ return /* @__PURE__ */ jsxRuntime.jsx(
134
+ "button",
135
+ {
136
+ type: "button",
137
+ onClick: handleClick,
138
+ disabled: disabled || loading || !ready,
139
+ className,
140
+ "aria-disabled": disabled || loading || !ready,
141
+ title: title ?? (error ? error.message : void 0),
142
+ children
143
+ }
144
+ );
145
+ }
146
+
147
+ exports.EscrowCheckoutButton = EscrowCheckoutButton;
148
+ exports.useEscrowCheckout = useEscrowCheckout;
149
+ //# sourceMappingURL=index.cjs.map
150
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/index.ts","../../src/react/useEscrowCheckout.ts","../../src/react/EscrowCheckoutButton.tsx"],"names":["useState","pay","useCallback","useEffect","useMemo","jsx"],"mappings":"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","file":"index.cjs","sourcesContent":["export type EscrowWidget = (options: Record<string, unknown>) => void;\r\n\r\nexport interface InitConfig {\r\n publicKey: string; // publishable key only\r\n /**\r\n * Optional overrides for experts. End users don't need to set these.\r\n */\r\n scriptUrlOverride?: string;\r\n globalName?: string; // default 'EscrowCheckout'\r\n crossOrigin?: '' | 'anonymous' | 'use-credentials';\r\n}\r\n\r\nexport interface PayInput {\r\n paymentToken: string;\r\n reference: string;\r\n redirectUrl: string;\r\n logoUrl?: string;\r\n brand?: string;\r\n /**\r\n * Extra fields supported by the widget.\r\n */\r\n extra?: Record<string, unknown>;\r\n callback?: (result: any) => void;\r\n onClose?: () => void;\r\n}\r\n\r\nexport interface SessionResponse {\r\n session: unknown;\r\n}\r\n\r\nconst DEFAULT_SCRIPT_URL = 'https://checkout.payluk.ng/escrow-checkout.min.js';\r\nconst DEFAULT_GLOBAL_NAME = 'EscrowCheckout';\r\n\r\ntype ResolvedConfig = Required<Pick<InitConfig, 'publicKey'>> & {\r\n scriptUrl: string;\r\n globalName: string;\r\n crossOrigin: '' | 'anonymous' | 'use-credentials';\r\n};\r\n\r\nlet CONFIG: ResolvedConfig | null = null;\r\n\r\n/**\r\n * Initialize the library once (e.g., in app bootstrap).\r\n * Hides script URL and session creation from consumers.\r\n */\r\nexport function initEscrowCheckout(config: InitConfig): void {\r\n if (!config?.publicKey) throw new Error('initEscrowCheckout: \"publicKey\" is required.');\r\n CONFIG = {\r\n publicKey: config.publicKey,\r\n scriptUrl: config.scriptUrlOverride || DEFAULT_SCRIPT_URL,\r\n globalName: config.globalName || DEFAULT_GLOBAL_NAME,\r\n crossOrigin: config.crossOrigin ?? 'anonymous'\r\n };\r\n}\r\n\r\n/**\r\n * Narrow a provided config to ResolvedConfig or throw if not initialized.\r\n */\r\nfunction assertConfigured(config: ResolvedConfig | null): asserts config is ResolvedConfig {\r\n if (!config) {\r\n throw new Error('Escrow checkout not initialized. Call initEscrowCheckout({ apiBaseUrl, publicKey }) first.');\r\n }\r\n}\r\n\r\n/**\r\n * Internal: load the widget script once and return the global function.\r\n */\r\nasync function loadWidget(): Promise<EscrowWidget> {\r\n assertConfigured(CONFIG);\r\n const { scriptUrl, globalName, crossOrigin } = CONFIG;\r\n\r\n if (typeof window === 'undefined') {\r\n throw new Error('EscrowCheckout can only be loaded in the browser.');\r\n }\r\n\r\n const win = window as any;\r\n win.__escrowCheckoutLoader ??= {};\r\n\r\n if (win.__escrowCheckoutLoader[scriptUrl]) {\r\n return win.__escrowCheckoutLoader[scriptUrl];\r\n }\r\n\r\n if (typeof win[globalName] === 'function') {\r\n const fn = win[globalName] as EscrowWidget;\r\n win.__escrowCheckoutLoader[scriptUrl] = Promise.resolve(fn);\r\n return fn;\r\n }\r\n\r\n win.__escrowCheckoutLoader[scriptUrl] = new Promise<EscrowWidget>((resolve, reject) => {\r\n const script = document.createElement('script');\r\n script.src = scriptUrl;\r\n script.async = true;\r\n if (crossOrigin) script.crossOrigin = crossOrigin;\r\n\r\n script.onload = () => {\r\n const fn = win[globalName];\r\n if (typeof fn === 'function') resolve(fn as EscrowWidget);\r\n else reject(new Error(`Escrow checkout script loaded, but window.${globalName} is not a function.`));\r\n };\r\n\r\n script.onerror = () => reject(new Error(`Failed to load escrow checkout script: ${scriptUrl}`));\r\n\r\n document.head.appendChild(script);\r\n });\r\n\r\n return win.__escrowCheckoutLoader[scriptUrl];\r\n}\r\n\r\n/**\r\n * Internal: create a checkout session by calling your API.\r\n * This is intentionally inside the lib (user doesn't implement it).\r\n */\r\nasync function createSession(input: PayInput): Promise<SessionResponse> {\r\n assertConfigured(CONFIG);\r\n const { publicKey } = CONFIG;\r\n const apiBaseUrl = 'https://live.payluk.ng';\r\n\r\n const resp = await fetch(`${apiBaseUrl}/v1/checkout/session`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n paymentToken: input.paymentToken,\r\n redirectUrl: input.redirectUrl,\r\n reference: input.reference,\r\n publicKey\r\n })\r\n });\r\n\r\n if (!resp.ok) {\r\n const err = await resp.json().catch(() => ({}));\r\n throw new Error(err.message || 'Failed to create session');\r\n }\r\n\r\n return (await resp.json()) as SessionResponse;\r\n}\r\n\r\n/**\r\n * Public API: create the session and open the widget.\r\n * Consumers only supply business inputs (no script URL, no API calls).\r\n */\r\nexport async function pay(input: PayInput): Promise<void> {\r\n if (typeof window === 'undefined') {\r\n throw new Error('pay(...) can only run in the browser.');\r\n }\r\n\r\n const [{ session }, widget] = await Promise.all([createSession(input), loadWidget()]);\r\n\r\n widget({\r\n session,\r\n logoUrl: input.logoUrl,\r\n brand: input.brand,\r\n callback: input.callback,\r\n onClose: input.onClose,\r\n ...(input.extra ?? {})\r\n });\r\n}","import { useCallback, useEffect, useMemo, useState } from 'react';\r\nimport { pay as corePay } from '../index';\r\n\r\nexport interface UseEscrowCheckoutResult {\r\n ready: boolean;\r\n loading: boolean;\r\n error: Error | null;\r\n pay: typeof corePay;\r\n}\r\n\r\n/**\r\n * React hook that preloads the widget script (implicitly via pay) and exposes pay(...)\r\n * Since the library abstracts script loading and session creation, the hook is thin.\r\n */\r\nexport function useEscrowCheckout(): UseEscrowCheckoutResult {\r\n const [ready, setReady] = useState(false);\r\n const [loading, setLoading] = useState<boolean>(() => typeof window !== 'undefined');\r\n const [error, setError] = useState<Error | null>(null);\r\n\r\n // Lazy mark \"ready\" after first successful pay or script load attempt.\r\n // If you want to preload the script earlier, you may trigger a no-op pay with a dry-run endpoint on your side.\r\n\r\n // Provide a stable pay function that reports loading state.\r\n const pay = useCallback<typeof corePay>(async (input) => {\r\n setLoading(true);\r\n try {\r\n await corePay(input);\r\n setReady(true);\r\n setError(null);\r\n } catch (e) {\r\n setError(e as Error);\r\n throw e;\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, []);\r\n\r\n // In SSR, mark not loading\r\n useEffect(() => {\r\n if (typeof window === 'undefined') {\r\n setLoading(false);\r\n }\r\n }, []);\r\n\r\n return useMemo(() => ({ ready, loading, error, pay }), [ready, loading, error, pay]);\r\n}","import React, { useCallback } from 'react';\r\nimport { useEscrowCheckout } from './useEscrowCheckout';\r\n\r\nexport interface EscrowCheckoutButtonProps {\r\n paymentToken: string;\r\n reference: string;\r\n redirectUrl: string;\r\n children?: React.ReactNode;\r\n disabled?: boolean;\r\n className?: string;\r\n title?: string;\r\n\r\n brand?: string;\r\n logoUrl?: string;\r\n callback?: (result: any) => void;\r\n onClose?: () => void;\r\n extra?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Button that triggers pay(...) with your provided inputs.\r\n * The library handles both session creation and widget loading.\r\n */\r\nexport function EscrowCheckoutButton({\r\n paymentToken,\r\n reference,\r\n redirectUrl,\r\n brand,\r\n logoUrl,\r\n callback,\r\n onClose,\r\n extra,\r\n children = 'Pay',\r\n disabled,\r\n className,\r\n title\r\n }: EscrowCheckoutButtonProps) {\r\n const { ready, loading, error, pay } = useEscrowCheckout();\r\n\r\n const handleClick = useCallback(async () => {\r\n await pay({\r\n paymentToken,\r\n reference,\r\n redirectUrl,\r\n brand,\r\n logoUrl,\r\n callback,\r\n onClose,\r\n extra\r\n });\r\n }, [pay, paymentToken, reference, redirectUrl, brand, logoUrl, callback, onClose, extra]);\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n onClick={handleClick}\r\n disabled={disabled || loading || !ready /* ready becomes true after first successful load */}\r\n className={className}\r\n aria-disabled={disabled || loading || !ready}\r\n title={title ?? (error ? error.message : undefined)}\r\n >\r\n {children}\r\n </button>\r\n );\r\n}"]}
@@ -0,0 +1,37 @@
1
+ import { pay } from '../index.cjs';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+ import React from 'react';
4
+
5
+ interface UseEscrowCheckoutResult {
6
+ ready: boolean;
7
+ loading: boolean;
8
+ error: Error | null;
9
+ pay: typeof pay;
10
+ }
11
+ /**
12
+ * React hook that preloads the widget script (implicitly via pay) and exposes pay(...)
13
+ * Since the library abstracts script loading and session creation, the hook is thin.
14
+ */
15
+ declare function useEscrowCheckout(): UseEscrowCheckoutResult;
16
+
17
+ interface EscrowCheckoutButtonProps {
18
+ paymentToken: string;
19
+ reference: string;
20
+ redirectUrl: string;
21
+ children?: React.ReactNode;
22
+ disabled?: boolean;
23
+ className?: string;
24
+ title?: string;
25
+ brand?: string;
26
+ logoUrl?: string;
27
+ callback?: (result: any) => void;
28
+ onClose?: () => void;
29
+ extra?: Record<string, unknown>;
30
+ }
31
+ /**
32
+ * Button that triggers pay(...) with your provided inputs.
33
+ * The library handles both session creation and widget loading.
34
+ */
35
+ declare function EscrowCheckoutButton({ paymentToken, reference, redirectUrl, brand, logoUrl, callback, onClose, extra, children, disabled, className, title }: EscrowCheckoutButtonProps): react_jsx_runtime.JSX.Element;
36
+
37
+ export { EscrowCheckoutButton, type EscrowCheckoutButtonProps, useEscrowCheckout };
@@ -0,0 +1,37 @@
1
+ import { pay } from '../index.js';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+ import React from 'react';
4
+
5
+ interface UseEscrowCheckoutResult {
6
+ ready: boolean;
7
+ loading: boolean;
8
+ error: Error | null;
9
+ pay: typeof pay;
10
+ }
11
+ /**
12
+ * React hook that preloads the widget script (implicitly via pay) and exposes pay(...)
13
+ * Since the library abstracts script loading and session creation, the hook is thin.
14
+ */
15
+ declare function useEscrowCheckout(): UseEscrowCheckoutResult;
16
+
17
+ interface EscrowCheckoutButtonProps {
18
+ paymentToken: string;
19
+ reference: string;
20
+ redirectUrl: string;
21
+ children?: React.ReactNode;
22
+ disabled?: boolean;
23
+ className?: string;
24
+ title?: string;
25
+ brand?: string;
26
+ logoUrl?: string;
27
+ callback?: (result: any) => void;
28
+ onClose?: () => void;
29
+ extra?: Record<string, unknown>;
30
+ }
31
+ /**
32
+ * Button that triggers pay(...) with your provided inputs.
33
+ * The library handles both session creation and widget loading.
34
+ */
35
+ declare function EscrowCheckoutButton({ paymentToken, reference, redirectUrl, brand, logoUrl, callback, onClose, extra, children, disabled, className, title }: EscrowCheckoutButtonProps): react_jsx_runtime.JSX.Element;
36
+
37
+ export { EscrowCheckoutButton, type EscrowCheckoutButtonProps, useEscrowCheckout };
@@ -0,0 +1,72 @@
1
+ import { pay } from '../chunk-D6ZMSUAT.js';
2
+ import { useState, useCallback, useEffect, useMemo } from 'react';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ function useEscrowCheckout() {
6
+ const [ready, setReady] = useState(false);
7
+ const [loading, setLoading] = useState(() => typeof window !== "undefined");
8
+ const [error, setError] = useState(null);
9
+ const pay2 = useCallback(async (input) => {
10
+ setLoading(true);
11
+ try {
12
+ await pay(input);
13
+ setReady(true);
14
+ setError(null);
15
+ } catch (e) {
16
+ setError(e);
17
+ throw e;
18
+ } finally {
19
+ setLoading(false);
20
+ }
21
+ }, []);
22
+ useEffect(() => {
23
+ if (typeof window === "undefined") {
24
+ setLoading(false);
25
+ }
26
+ }, []);
27
+ return useMemo(() => ({ ready, loading, error, pay: pay2 }), [ready, loading, error, pay2]);
28
+ }
29
+ function EscrowCheckoutButton({
30
+ paymentToken,
31
+ reference,
32
+ redirectUrl,
33
+ brand,
34
+ logoUrl,
35
+ callback,
36
+ onClose,
37
+ extra,
38
+ children = "Pay",
39
+ disabled,
40
+ className,
41
+ title
42
+ }) {
43
+ const { ready, loading, error, pay: pay2 } = useEscrowCheckout();
44
+ const handleClick = useCallback(async () => {
45
+ await pay2({
46
+ paymentToken,
47
+ reference,
48
+ redirectUrl,
49
+ brand,
50
+ logoUrl,
51
+ callback,
52
+ onClose,
53
+ extra
54
+ });
55
+ }, [pay2, paymentToken, reference, redirectUrl, brand, logoUrl, callback, onClose, extra]);
56
+ return /* @__PURE__ */ jsx(
57
+ "button",
58
+ {
59
+ type: "button",
60
+ onClick: handleClick,
61
+ disabled: disabled || loading || !ready,
62
+ className,
63
+ "aria-disabled": disabled || loading || !ready,
64
+ title: title ?? (error ? error.message : void 0),
65
+ children
66
+ }
67
+ );
68
+ }
69
+
70
+ export { EscrowCheckoutButton, useEscrowCheckout };
71
+ //# sourceMappingURL=index.js.map
72
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/react/useEscrowCheckout.ts","../../src/react/EscrowCheckoutButton.tsx"],"names":["pay","useCallback"],"mappings":";;;;AAcO,SAAS,iBAAA,GAA6C;AACzD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAS,KAAK,CAAA;AACxC,EAAA,MAAM,CAAC,SAAS,UAAU,CAAA,GAAI,SAAkB,MAAM,OAAO,WAAW,WAAW,CAAA;AACnF,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAuB,IAAI,CAAA;AAMrD,EAAA,MAAMA,IAAAA,GAAM,WAAA,CAA4B,OAAO,KAAA,KAAU;AACrD,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,IAAI;AACA,MAAA,MAAM,IAAQ,KAAK,CAAA;AACnB,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA,QAAA,CAAS,IAAI,CAAA;AAAA,IACjB,SAAS,CAAA,EAAG;AACR,MAAA,QAAA,CAAS,CAAU,CAAA;AACnB,MAAA,MAAM,CAAA;AAAA,IACV,CAAA,SAAE;AACE,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IACpB;AAAA,EACJ,CAAA,EAAG,EAAE,CAAA;AAGL,EAAA,SAAA,CAAU,MAAM;AACZ,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AAC/B,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IACpB;AAAA,EACJ,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,OAAA,CAAQ,OAAO,EAAE,KAAA,EAAO,SAAS,KAAA,EAAO,GAAA,EAAAA,IAAAA,EAAI,CAAA,EAAI,CAAC,KAAA,EAAO,OAAA,EAAS,KAAA,EAAOA,IAAG,CAAC,CAAA;AACvF;ACtBO,SAAS,oBAAA,CAAqB;AAAA,EACI,YAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,KAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,QAAA;AAAA,EACA,SAAA;AAAA,EACA;AACJ,CAAA,EAA8B;AAC/D,EAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAS,OAAO,GAAA,EAAAA,IAAAA,KAAQ,iBAAA,EAAkB;AAEzD,EAAA,MAAM,WAAA,GAAcC,YAAY,YAAY;AACxC,IAAA,MAAMD,IAAAA,CAAI;AAAA,MACN,YAAA;AAAA,MACA,SAAA;AAAA,MACA,WAAA;AAAA,MACA,KAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAA;AAAA,MACA,OAAA;AAAA,MACA;AAAA,KACH,CAAA;AAAA,EACL,CAAA,EAAG,CAACA,IAAAA,EAAK,YAAA,EAAc,SAAA,EAAW,WAAA,EAAa,KAAA,EAAO,OAAA,EAAS,QAAA,EAAU,OAAA,EAAS,KAAK,CAAC,CAAA;AAExF,EAAA,uBACI,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACG,IAAA,EAAK,QAAA;AAAA,MACL,OAAA,EAAS,WAAA;AAAA,MACT,QAAA,EAAU,QAAA,IAAY,OAAA,IAAW,CAAC,KAAA;AAAA,MAClC,SAAA;AAAA,MACA,eAAA,EAAe,QAAA,IAAY,OAAA,IAAW,CAAC,KAAA;AAAA,MACvC,KAAA,EAAO,KAAA,KAAU,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,MAAA,CAAA;AAAA,MAExC;AAAA;AAAA,GACL;AAER","file":"index.js","sourcesContent":["import { useCallback, useEffect, useMemo, useState } from 'react';\r\nimport { pay as corePay } from '../index';\r\n\r\nexport interface UseEscrowCheckoutResult {\r\n ready: boolean;\r\n loading: boolean;\r\n error: Error | null;\r\n pay: typeof corePay;\r\n}\r\n\r\n/**\r\n * React hook that preloads the widget script (implicitly via pay) and exposes pay(...)\r\n * Since the library abstracts script loading and session creation, the hook is thin.\r\n */\r\nexport function useEscrowCheckout(): UseEscrowCheckoutResult {\r\n const [ready, setReady] = useState(false);\r\n const [loading, setLoading] = useState<boolean>(() => typeof window !== 'undefined');\r\n const [error, setError] = useState<Error | null>(null);\r\n\r\n // Lazy mark \"ready\" after first successful pay or script load attempt.\r\n // If you want to preload the script earlier, you may trigger a no-op pay with a dry-run endpoint on your side.\r\n\r\n // Provide a stable pay function that reports loading state.\r\n const pay = useCallback<typeof corePay>(async (input) => {\r\n setLoading(true);\r\n try {\r\n await corePay(input);\r\n setReady(true);\r\n setError(null);\r\n } catch (e) {\r\n setError(e as Error);\r\n throw e;\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, []);\r\n\r\n // In SSR, mark not loading\r\n useEffect(() => {\r\n if (typeof window === 'undefined') {\r\n setLoading(false);\r\n }\r\n }, []);\r\n\r\n return useMemo(() => ({ ready, loading, error, pay }), [ready, loading, error, pay]);\r\n}","import React, { useCallback } from 'react';\r\nimport { useEscrowCheckout } from './useEscrowCheckout';\r\n\r\nexport interface EscrowCheckoutButtonProps {\r\n paymentToken: string;\r\n reference: string;\r\n redirectUrl: string;\r\n children?: React.ReactNode;\r\n disabled?: boolean;\r\n className?: string;\r\n title?: string;\r\n\r\n brand?: string;\r\n logoUrl?: string;\r\n callback?: (result: any) => void;\r\n onClose?: () => void;\r\n extra?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Button that triggers pay(...) with your provided inputs.\r\n * The library handles both session creation and widget loading.\r\n */\r\nexport function EscrowCheckoutButton({\r\n paymentToken,\r\n reference,\r\n redirectUrl,\r\n brand,\r\n logoUrl,\r\n callback,\r\n onClose,\r\n extra,\r\n children = 'Pay',\r\n disabled,\r\n className,\r\n title\r\n }: EscrowCheckoutButtonProps) {\r\n const { ready, loading, error, pay } = useEscrowCheckout();\r\n\r\n const handleClick = useCallback(async () => {\r\n await pay({\r\n paymentToken,\r\n reference,\r\n redirectUrl,\r\n brand,\r\n logoUrl,\r\n callback,\r\n onClose,\r\n extra\r\n });\r\n }, [pay, paymentToken, reference, redirectUrl, brand, logoUrl, callback, onClose, extra]);\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n onClick={handleClick}\r\n disabled={disabled || loading || !ready /* ready becomes true after first successful load */}\r\n className={className}\r\n aria-disabled={disabled || loading || !ready}\r\n title={title ?? (error ? error.message : undefined)}\r\n >\r\n {children}\r\n </button>\r\n );\r\n}"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payluk-escrow-inline-checkout",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "TypeScript escrow checkout wrapper with built-in script loader and session creation, ready for React/Next.js",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -34,6 +34,7 @@
34
34
  "scripts": {
35
35
  "clean": "rimraf dist",
36
36
  "build": "tsup",
37
- "typecheck": "tsc --noEmit"
37
+ "typecheck": "tsc --noEmit",
38
+ "prepublishOnly": "npm run clean && npm run build"
38
39
  }
39
40
  }