@radokpay/js 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -0
- package/dist/index.d.ts +42 -0
- package/dist/modal.d.ts +20 -0
- package/dist/protocol.d.ts +37 -0
- package/dist/radok.cjs +1 -0
- package/dist/radok.js +2 -0
- package/dist/radok.mjs +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# @radokpay/js
|
|
2
|
+
|
|
3
|
+
Take payments on your own site with [Radok Pay](https://radokpay.com). One script tag opens the
|
|
4
|
+
Radok checkout in a modal over your page — your customer never leaves.
|
|
5
|
+
|
|
6
|
+
```html
|
|
7
|
+
<script src="https://cdn.jsdelivr.net/npm/@radokpay/js"></script>
|
|
8
|
+
<script>
|
|
9
|
+
const radok = Radok();
|
|
10
|
+
|
|
11
|
+
payButton.onclick = () =>
|
|
12
|
+
radok.checkout({
|
|
13
|
+
slug: "order-1042-9f4c1b", // created by YOUR server, see below
|
|
14
|
+
onSuccess: () => (window.location = "/thank-you"),
|
|
15
|
+
});
|
|
16
|
+
</script>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or from a bundler:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @radokpay/js
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
import { Radok } from "@radokpay/js";
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Using React? [`@radokpay/react`](https://www.npmjs.com/package/@radokpay/react) wraps this.
|
|
30
|
+
|
|
31
|
+
## How it fits together
|
|
32
|
+
|
|
33
|
+
The amount is set by your server, never by the browser — so a customer cannot change what they
|
|
34
|
+
are charged.
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
1. Your server POST /v1/payment-links (with your SECRET key)
|
|
38
|
+
-> { slug: "order-1042-9f4c1b" }
|
|
39
|
+
|
|
40
|
+
2. Your page radok.checkout({ slug }) modal opens over your site
|
|
41
|
+
|
|
42
|
+
3. Radok POST your webhook endpoint collection.success
|
|
43
|
+
|
|
44
|
+
4. Your server ships the order
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Step 3 is the one that matters.** `onSuccess` tells your page to show a thank-you screen. It is
|
|
48
|
+
not proof of payment: it runs in the customer's browser, where anything can happen to it. Ship
|
|
49
|
+
goods, grant access and credit accounts from the `collection.success` webhook, server to server.
|
|
50
|
+
|
|
51
|
+
Creating the link, from your server:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
curl -X POST https://api.radokpay.com/v1/payment-links \
|
|
55
|
+
-H "Authorization: Bearer $RADOK_SECRET_KEY" \
|
|
56
|
+
-H "Content-Type: application/json" \
|
|
57
|
+
-d '{
|
|
58
|
+
"title": "Order #1042",
|
|
59
|
+
"amountType": "fixed",
|
|
60
|
+
"amount": { "value": 500000, "currency": "NGN" },
|
|
61
|
+
"linkType": "one_time"
|
|
62
|
+
}'
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`value` is in kobo — `500000` is ₦5,000.00.
|
|
66
|
+
|
|
67
|
+
## Before it will render
|
|
68
|
+
|
|
69
|
+
Add your site under **Settings → Embedding** in the Radok dashboard. The checkout sends a
|
|
70
|
+
`frame-ancestors` header built from that list, so a site you have not registered cannot frame your
|
|
71
|
+
checkout — and neither can anyone else's. A merchant with no registered origins is not embeddable;
|
|
72
|
+
the modal opens and stays blank.
|
|
73
|
+
|
|
74
|
+
Register the exact origin, scheme and port included: `https://shop.example.com`,
|
|
75
|
+
`http://localhost:3000`.
|
|
76
|
+
|
|
77
|
+
## API
|
|
78
|
+
|
|
79
|
+
### `Radok(options?)`
|
|
80
|
+
|
|
81
|
+
| Option | Default | |
|
|
82
|
+
| --- | --- | --- |
|
|
83
|
+
| `payOrigin` | `https://pay.radokpay.com` | Override the checkout host, for local development. |
|
|
84
|
+
|
|
85
|
+
### `radok.checkout(options)`
|
|
86
|
+
|
|
87
|
+
| Option | | |
|
|
88
|
+
| --- | --- | --- |
|
|
89
|
+
| `slug` | required | From your server's payment-link response. |
|
|
90
|
+
| `onSuccess` | `({ reference }) => void` | The payment settled. A UI signal — fulfil from the webhook. |
|
|
91
|
+
| `onClose` | `() => void` | The modal closed, for any reason, including after a success. Always called exactly once. |
|
|
92
|
+
| `onError` | `({ code, message }) => void` | Terminal failure, or the transfer window lapsed. |
|
|
93
|
+
|
|
94
|
+
Returns `{ close() }` to dismiss it yourself.
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
const handle = radok.checkout({ slug });
|
|
98
|
+
handle.close();
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Testing
|
|
102
|
+
|
|
103
|
+
Create the link with a **test** secret key (`sk_test_…`). The checkout shows a TEST banner and a
|
|
104
|
+
stub bank account, and **I've sent the transfer** settles it immediately — no real money, and no
|
|
105
|
+
need to make an actual bank transfer.
|
|
106
|
+
|
|
107
|
+
Run against a local stack with `Radok({ payOrigin: "http://localhost:3003" })`, and add
|
|
108
|
+
`http://localhost:3000` (or whichever port your site is on) to your embedding allowlist.
|
|
109
|
+
|
|
110
|
+
## Notes
|
|
111
|
+
|
|
112
|
+
- No dependencies, ~4.7 KB minified.
|
|
113
|
+
- Needs a browser. Calling `checkout()` during SSR throws.
|
|
114
|
+
- The modal is keyboard accessible: Escape closes it, Tab is trapped inside, and focus returns to
|
|
115
|
+
wherever it was when it closes.
|
|
116
|
+
|
|
117
|
+
## Licence
|
|
118
|
+
|
|
119
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @radokpay/js — opens the Radok hosted checkout in a modal over your own page.
|
|
3
|
+
*
|
|
4
|
+
* const radok = Radok();
|
|
5
|
+
* radok.checkout({ slug, onSuccess: ({ reference }) => ... });
|
|
6
|
+
*
|
|
7
|
+
* The slug comes from YOUR server, which creates the payment link with your secret key. The
|
|
8
|
+
* browser never names an amount, so a customer cannot change what they are charged.
|
|
9
|
+
*
|
|
10
|
+
* Treat onSuccess as a UI signal, not proof of payment. Anything that ships goods, grants access
|
|
11
|
+
* or credits an account belongs behind the `collection.success` webhook, server to server.
|
|
12
|
+
*/
|
|
13
|
+
export declare const DEFAULT_PAY_ORIGIN = "https://pay.radokpay.com";
|
|
14
|
+
export type CheckoutResult = {
|
|
15
|
+
reference: string;
|
|
16
|
+
};
|
|
17
|
+
export type CheckoutOptions = {
|
|
18
|
+
/** From your server's POST /v1/payment-links response. */
|
|
19
|
+
slug: string;
|
|
20
|
+
/** The payment settled. A UI signal — fulfil from the webhook, not from here. */
|
|
21
|
+
onSuccess?: (result: CheckoutResult) => void;
|
|
22
|
+
/** The modal closed, for any reason, including after a success. Always called exactly once. */
|
|
23
|
+
onClose?: () => void;
|
|
24
|
+
/** Terminal failure, or the transfer window lapsed. */
|
|
25
|
+
onError?: (error: {
|
|
26
|
+
code: string;
|
|
27
|
+
message: string;
|
|
28
|
+
}) => void;
|
|
29
|
+
};
|
|
30
|
+
export type RadokOptions = {
|
|
31
|
+
/** Override the checkout host. For local development against a dev server. */
|
|
32
|
+
payOrigin?: string;
|
|
33
|
+
};
|
|
34
|
+
export type CheckoutHandle = {
|
|
35
|
+
/** Close the modal early. Safe to call more than once. */
|
|
36
|
+
close: () => void;
|
|
37
|
+
};
|
|
38
|
+
export type RadokClient = {
|
|
39
|
+
checkout: (options: CheckoutOptions) => CheckoutHandle;
|
|
40
|
+
};
|
|
41
|
+
export declare function Radok(options?: RadokOptions): RadokClient;
|
|
42
|
+
export default Radok;
|
package/dist/modal.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The overlay. Kept apart from the message handling so each is readable on its own.
|
|
3
|
+
*
|
|
4
|
+
* Every style is inline. This renders on a stranger's page, where a stylesheet we do not control
|
|
5
|
+
* would otherwise reach in — and a merchant's `iframe { width: 100% }` or `* { box-sizing }` is
|
|
6
|
+
* enough to break the layout. Inline styles cannot be overridden by an author stylesheet without
|
|
7
|
+
* !important, which is as close to isolation as is worth getting without a shadow root.
|
|
8
|
+
*/
|
|
9
|
+
export type Modal = {
|
|
10
|
+
iframe: HTMLIFrameElement;
|
|
11
|
+
/** Reveal the frame. Held back until the checkout says it is ready, to avoid a white flash. */
|
|
12
|
+
reveal: () => void;
|
|
13
|
+
setHeight: (height: number) => void;
|
|
14
|
+
destroy: () => void;
|
|
15
|
+
};
|
|
16
|
+
export declare function createModal(options: {
|
|
17
|
+
src: string;
|
|
18
|
+
title: string;
|
|
19
|
+
onRequestClose: () => void;
|
|
20
|
+
}): Modal;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wire contract with the embedded checkout.
|
|
3
|
+
*
|
|
4
|
+
* Duplicated, deliberately, from apps/pay/features/checkout/lib/embed.ts. A merchant's cached copy
|
|
5
|
+
* of this widget will meet a newer checkout, so the two sides deploy independently and this is a
|
|
6
|
+
* versioned wire format rather than shared code. Keep old shapes working; bump PROTOCOL_VERSION.
|
|
7
|
+
*/
|
|
8
|
+
export declare const MESSAGE_SOURCE = "radok-checkout";
|
|
9
|
+
export declare const PROTOCOL_VERSION = 1;
|
|
10
|
+
export type EmbedMessage = {
|
|
11
|
+
type: "ready";
|
|
12
|
+
} | {
|
|
13
|
+
type: "resize";
|
|
14
|
+
height: number;
|
|
15
|
+
} | {
|
|
16
|
+
type: "success";
|
|
17
|
+
reference: string;
|
|
18
|
+
} | {
|
|
19
|
+
type: "error";
|
|
20
|
+
code: string;
|
|
21
|
+
message: string;
|
|
22
|
+
} | {
|
|
23
|
+
type: "close";
|
|
24
|
+
} | {
|
|
25
|
+
type: "redirect";
|
|
26
|
+
url: string;
|
|
27
|
+
};
|
|
28
|
+
export type EmbedEnvelope = EmbedMessage & {
|
|
29
|
+
source: typeof MESSAGE_SOURCE;
|
|
30
|
+
v: number;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Anything arriving on `message` is attacker-controlled until proven otherwise — any script on the
|
|
34
|
+
* merchant's page, and any other frame, can post to this window. Origin and source are checked by
|
|
35
|
+
* the caller, which has the iframe to compare against; this only vouches for the shape.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isEmbedEnvelope(data: unknown): data is EmbedEnvelope;
|
package/dist/radok.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var u=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var E=Object.prototype.hasOwnProperty;var x=(t,e)=>{for(var o in e)u(t,o,{get:e[o],enumerable:!0})},v=(t,e,o,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of k(e))!E.call(t,s)&&s!==o&&u(t,s,{get:()=>e[s],enumerable:!(i=b(e,s))||i.enumerable});return t};var w=t=>v(u({},"__esModule",{value:!0}),t);var O={};x(O,{DEFAULT_PAY_ORIGIN:()=>m,Radok:()=>h,default:()=>M});module.exports=w(O);var C='a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';function f(t){let e=document.activeElement,o=document.createElement("div");o.setAttribute("role","dialog"),o.setAttribute("aria-modal","true"),o.setAttribute("aria-label",t.title),Object.assign(o.style,{position:"fixed",inset:"0",zIndex:String(2147483e3),display:"flex",alignItems:"flex-start",justifyContent:"center",padding:"24px 16px",overflowY:"auto",background:"rgba(15, 18, 24, 0.55)",opacity:"0",transition:"opacity 160ms ease"}),o.style.setProperty("-webkit-tap-highlight-color","transparent");let i=document.createElement("div");Object.assign(i.style,{position:"relative",width:"100%",maxWidth:"420px",margin:"auto",borderRadius:"14px",background:"#ffffff",boxShadow:"0 24px 60px rgba(0,0,0,0.28)",overflow:"hidden",height:"560px",transition:"height 180ms ease"});let s=document.createElement("button");s.type="button",s.setAttribute("aria-label","Close checkout"),s.innerHTML='<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true" focusable="false"><path d="M1 1l12 12M13 1L1 13" stroke="currentColor" stroke-width="1.6" fill="none" stroke-linecap="round"/></svg>',Object.assign(s.style,{position:"absolute",top:"10px",right:"10px",zIndex:"2",display:"inline-flex",alignItems:"center",justifyContent:"center",width:"28px",height:"28px",padding:"0",border:"none",borderRadius:"999px",background:"rgba(15,18,24,0.06)",color:"#4a4f57",cursor:"pointer",font:"inherit",lineHeight:"0"}),s.addEventListener("click",t.onRequestClose);let r=document.createElement("iframe");r.src=t.src,r.title=t.title,r.setAttribute("allow","clipboard-write"),r.setAttribute("referrerpolicy","origin"),Object.assign(r.style,{display:"block",width:"100%",height:"100%",border:"0",opacity:"0",transition:"opacity 120ms ease"}),i.append(s,r),o.append(i);let l=n=>{n.target===o&&t.onRequestClose()};o.addEventListener("click",l);let c=n=>{if(n.key==="Escape"){n.stopPropagation(),t.onRequestClose();return}if(n.key!=="Tab")return;let a=Array.from(o.querySelectorAll(C));if(a.length===0)return;let p=a[0],y=a[a.length-1];n.shiftKey&&document.activeElement===p?(n.preventDefault(),y.focus()):!n.shiftKey&&document.activeElement===y&&(n.preventDefault(),p.focus())};document.addEventListener("keydown",c,!0);let d=document.body.style.overflow;return document.body.style.overflow="hidden",document.body.append(o),requestAnimationFrame(()=>{o.style.opacity="1"}),s.focus(),{iframe:r,reveal:()=>{r.style.opacity="1"},setHeight:n=>{let a=Math.max(320,window.innerHeight-48);i.style.height=`${Math.min(Math.max(n,320),a)}px`},destroy:()=>{document.removeEventListener("keydown",c,!0),o.removeEventListener("click",l),document.body.style.overflow=d,o.remove(),e?.focus?.()}}}var S="radok-checkout";function g(t){if(typeof t!="object"||t===null)return!1;let e=t;if(e.source!==S||typeof e.type!="string")return!1;switch(e.type){case"ready":case"close":return!0;case"resize":return typeof e.height=="number"&&Number.isFinite(e.height);case"success":return typeof e.reference=="string";case"error":return typeof e.code=="string"&&typeof e.message=="string";case"redirect":return typeof e.url=="string";default:return!0}}var m="https://pay.radokpay.com";function R(t){return new URL(t).origin}function h(t={}){let e=R(t.payOrigin??m);function o(i){if(typeof window>"u"||typeof document>"u")throw new Error("Radok checkout can only be opened in a browser.");if(!i.slug)throw new Error("Radok checkout needs a payment link slug.");let s=`${e}/pl/${encodeURIComponent(i.slug)}?embed=1&origin=${encodeURIComponent(window.location.origin)}`,r=null,l=!1,c=()=>{l||(l=!0,window.removeEventListener("message",d),r?.destroy(),r=null,i.onClose?.())};function d(n){if(n.origin!==e||!r||n.source!==r.iframe.contentWindow||!g(n.data))return;let a=n.data;switch(a.type){case"ready":r.reveal();break;case"resize":r.setHeight(a.height);break;case"success":i.onSuccess?.({reference:a.reference}),c();break;case"error":i.onError?.({code:a.code,message:a.message});break;case"redirect":c(),window.location.assign(a.url);break;case"close":c();break}}return window.addEventListener("message",d),r=f({src:s,title:"Secure checkout",onRequestClose:c}),{close:c}}return{checkout:o}}var M=h;
|
package/dist/radok.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var Radok=(()=>{var u=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var E=Object.prototype.hasOwnProperty;var x=(t,e)=>{for(var o in e)u(t,o,{get:e[o],enumerable:!0})},v=(t,e,o,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of k(e))!E.call(t,s)&&s!==o&&u(t,s,{get:()=>e[s],enumerable:!(i=b(e,s))||i.enumerable});return t};var w=t=>v(u({},"__esModule",{value:!0}),t);var O={};x(O,{DEFAULT_PAY_ORIGIN:()=>m,Radok:()=>h,default:()=>M});var C='a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';function f(t){let e=document.activeElement,o=document.createElement("div");o.setAttribute("role","dialog"),o.setAttribute("aria-modal","true"),o.setAttribute("aria-label",t.title),Object.assign(o.style,{position:"fixed",inset:"0",zIndex:String(2147483e3),display:"flex",alignItems:"flex-start",justifyContent:"center",padding:"24px 16px",overflowY:"auto",background:"rgba(15, 18, 24, 0.55)",opacity:"0",transition:"opacity 160ms ease"}),o.style.setProperty("-webkit-tap-highlight-color","transparent");let i=document.createElement("div");Object.assign(i.style,{position:"relative",width:"100%",maxWidth:"420px",margin:"auto",borderRadius:"14px",background:"#ffffff",boxShadow:"0 24px 60px rgba(0,0,0,0.28)",overflow:"hidden",height:"560px",transition:"height 180ms ease"});let s=document.createElement("button");s.type="button",s.setAttribute("aria-label","Close checkout"),s.innerHTML='<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true" focusable="false"><path d="M1 1l12 12M13 1L1 13" stroke="currentColor" stroke-width="1.6" fill="none" stroke-linecap="round"/></svg>',Object.assign(s.style,{position:"absolute",top:"10px",right:"10px",zIndex:"2",display:"inline-flex",alignItems:"center",justifyContent:"center",width:"28px",height:"28px",padding:"0",border:"none",borderRadius:"999px",background:"rgba(15,18,24,0.06)",color:"#4a4f57",cursor:"pointer",font:"inherit",lineHeight:"0"}),s.addEventListener("click",t.onRequestClose);let r=document.createElement("iframe");r.src=t.src,r.title=t.title,r.setAttribute("allow","clipboard-write"),r.setAttribute("referrerpolicy","origin"),Object.assign(r.style,{display:"block",width:"100%",height:"100%",border:"0",opacity:"0",transition:"opacity 120ms ease"}),i.append(s,r),o.append(i);let l=n=>{n.target===o&&t.onRequestClose()};o.addEventListener("click",l);let c=n=>{if(n.key==="Escape"){n.stopPropagation(),t.onRequestClose();return}if(n.key!=="Tab")return;let a=Array.from(o.querySelectorAll(C));if(a.length===0)return;let p=a[0],y=a[a.length-1];n.shiftKey&&document.activeElement===p?(n.preventDefault(),y.focus()):!n.shiftKey&&document.activeElement===y&&(n.preventDefault(),p.focus())};document.addEventListener("keydown",c,!0);let d=document.body.style.overflow;return document.body.style.overflow="hidden",document.body.append(o),requestAnimationFrame(()=>{o.style.opacity="1"}),s.focus(),{iframe:r,reveal:()=>{r.style.opacity="1"},setHeight:n=>{let a=Math.max(320,window.innerHeight-48);i.style.height=`${Math.min(Math.max(n,320),a)}px`},destroy:()=>{document.removeEventListener("keydown",c,!0),o.removeEventListener("click",l),document.body.style.overflow=d,o.remove(),e?.focus?.()}}}var S="radok-checkout";function g(t){if(typeof t!="object"||t===null)return!1;let e=t;if(e.source!==S||typeof e.type!="string")return!1;switch(e.type){case"ready":case"close":return!0;case"resize":return typeof e.height=="number"&&Number.isFinite(e.height);case"success":return typeof e.reference=="string";case"error":return typeof e.code=="string"&&typeof e.message=="string";case"redirect":return typeof e.url=="string";default:return!0}}var m="https://pay.radokpay.com";function R(t){return new URL(t).origin}function h(t={}){let e=R(t.payOrigin??m);function o(i){if(typeof window>"u"||typeof document>"u")throw new Error("Radok checkout can only be opened in a browser.");if(!i.slug)throw new Error("Radok checkout needs a payment link slug.");let s=`${e}/pl/${encodeURIComponent(i.slug)}?embed=1&origin=${encodeURIComponent(window.location.origin)}`,r=null,l=!1,c=()=>{l||(l=!0,window.removeEventListener("message",d),r?.destroy(),r=null,i.onClose?.())};function d(n){if(n.origin!==e||!r||n.source!==r.iframe.contentWindow||!g(n.data))return;let a=n.data;switch(a.type){case"ready":r.reveal();break;case"resize":r.setHeight(a.height);break;case"success":i.onSuccess?.({reference:a.reference}),c();break;case"error":i.onError?.({code:a.code,message:a.message});break;case"redirect":c(),window.location.assign(a.url);break;case"close":c();break}}return window.addEventListener("message",d),r=f({src:s,title:"Secure checkout",onRequestClose:c}),{close:c}}return{checkout:o}}var M=h;return w(O);})();
|
|
2
|
+
Radok=Object.assign(Radok.default,Radok);
|
package/dist/radok.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var g='a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';function y(r){let n=document.activeElement,o=document.createElement("div");o.setAttribute("role","dialog"),o.setAttribute("aria-modal","true"),o.setAttribute("aria-label",r.title),Object.assign(o.style,{position:"fixed",inset:"0",zIndex:String(2147483e3),display:"flex",alignItems:"flex-start",justifyContent:"center",padding:"24px 16px",overflowY:"auto",background:"rgba(15, 18, 24, 0.55)",opacity:"0",transition:"opacity 160ms ease"}),o.style.setProperty("-webkit-tap-highlight-color","transparent");let i=document.createElement("div");Object.assign(i.style,{position:"relative",width:"100%",maxWidth:"420px",margin:"auto",borderRadius:"14px",background:"#ffffff",boxShadow:"0 24px 60px rgba(0,0,0,0.28)",overflow:"hidden",height:"560px",transition:"height 180ms ease"});let a=document.createElement("button");a.type="button",a.setAttribute("aria-label","Close checkout"),a.innerHTML='<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true" focusable="false"><path d="M1 1l12 12M13 1L1 13" stroke="currentColor" stroke-width="1.6" fill="none" stroke-linecap="round"/></svg>',Object.assign(a.style,{position:"absolute",top:"10px",right:"10px",zIndex:"2",display:"inline-flex",alignItems:"center",justifyContent:"center",width:"28px",height:"28px",padding:"0",border:"none",borderRadius:"999px",background:"rgba(15,18,24,0.06)",color:"#4a4f57",cursor:"pointer",font:"inherit",lineHeight:"0"}),a.addEventListener("click",r.onRequestClose);let e=document.createElement("iframe");e.src=r.src,e.title=r.title,e.setAttribute("allow","clipboard-write"),e.setAttribute("referrerpolicy","origin"),Object.assign(e.style,{display:"block",width:"100%",height:"100%",border:"0",opacity:"0",transition:"opacity 120ms ease"}),i.append(a,e),o.append(i);let l=t=>{t.target===o&&r.onRequestClose()};o.addEventListener("click",l);let c=t=>{if(t.key==="Escape"){t.stopPropagation(),r.onRequestClose();return}if(t.key!=="Tab")return;let s=Array.from(o.querySelectorAll(g));if(s.length===0)return;let u=s[0],p=s[s.length-1];t.shiftKey&&document.activeElement===u?(t.preventDefault(),p.focus()):!t.shiftKey&&document.activeElement===p&&(t.preventDefault(),u.focus())};document.addEventListener("keydown",c,!0);let d=document.body.style.overflow;return document.body.style.overflow="hidden",document.body.append(o),requestAnimationFrame(()=>{o.style.opacity="1"}),a.focus(),{iframe:e,reveal:()=>{e.style.opacity="1"},setHeight:t=>{let s=Math.max(320,window.innerHeight-48);i.style.height=`${Math.min(Math.max(t,320),s)}px`},destroy:()=>{document.removeEventListener("keydown",c,!0),o.removeEventListener("click",l),document.body.style.overflow=d,o.remove(),n?.focus?.()}}}var m="radok-checkout";function f(r){if(typeof r!="object"||r===null)return!1;let n=r;if(n.source!==m||typeof n.type!="string")return!1;switch(n.type){case"ready":case"close":return!0;case"resize":return typeof n.height=="number"&&Number.isFinite(n.height);case"success":return typeof n.reference=="string";case"error":return typeof n.code=="string"&&typeof n.message=="string";case"redirect":return typeof n.url=="string";default:return!0}}var h="https://pay.radokpay.com";function b(r){return new URL(r).origin}function k(r={}){let n=b(r.payOrigin??h);function o(i){if(typeof window>"u"||typeof document>"u")throw new Error("Radok checkout can only be opened in a browser.");if(!i.slug)throw new Error("Radok checkout needs a payment link slug.");let a=`${n}/pl/${encodeURIComponent(i.slug)}?embed=1&origin=${encodeURIComponent(window.location.origin)}`,e=null,l=!1,c=()=>{l||(l=!0,window.removeEventListener("message",d),e?.destroy(),e=null,i.onClose?.())};function d(t){if(t.origin!==n||!e||t.source!==e.iframe.contentWindow||!f(t.data))return;let s=t.data;switch(s.type){case"ready":e.reveal();break;case"resize":e.setHeight(s.height);break;case"success":i.onSuccess?.({reference:s.reference}),c();break;case"error":i.onError?.({code:s.code,message:s.message});break;case"redirect":c(),window.location.assign(s.url);break;case"close":c();break}}return window.addEventListener("message",d),e=y({src:a,title:"Secure checkout",onRequestClose:c}),{close:c}}return{checkout:o}}var C=k;export{h as DEFAULT_PAY_ORIGIN,k as Radok,C as default};
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@radokpay/js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Drop-in Radok Pay checkout for any website — opens the hosted checkout in a modal over your page.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"radok",
|
|
7
|
+
"radokpay",
|
|
8
|
+
"payments",
|
|
9
|
+
"checkout",
|
|
10
|
+
"nigeria"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://docs.radokpay.com/widget",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "./dist/radok.cjs",
|
|
16
|
+
"module": "./dist/radok.mjs",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"unpkg": "./dist/radok.js",
|
|
19
|
+
"jsdelivr": "./dist/radok.js",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/radok.mjs",
|
|
24
|
+
"require": "./dist/radok.cjs"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=20"
|
|
33
|
+
},
|
|
34
|
+
"sideEffects": false,
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"esbuild": "^0.28.2",
|
|
37
|
+
"typescript": "^5"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "node build.mjs && tsc --emitDeclarationOnly",
|
|
44
|
+
"typecheck": "tsc --noEmit"
|
|
45
|
+
}
|
|
46
|
+
}
|