@morefin/cashier-bootstrapper 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 +147 -0
- package/dist/example-usage.d.ts +9 -0
- package/dist/example-usage.js +73 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +194 -0
- package/dist/types.d.ts +97 -0
- package/dist/types.js +1 -0
- package/package.json +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Cashier Bootstrapper
|
|
2
|
+
|
|
3
|
+
Lightweight iframe bootstrapper for the Morefin cashier. It builds the cashier URL from request params and mounts the cashier inside an iframe to keep host styles isolated.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @morefin/cashier-bootstrapper
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Throughout the examples below, set a host variable once and reuse it:
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
const CASHIER_HOST = 'http://localhost:7082'; // change per environment
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Basic Embed
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { CashierBootstrapper } from '@morefin/cashier-bootstrapper';
|
|
23
|
+
|
|
24
|
+
new CashierBootstrapper('#cashier-root', {
|
|
25
|
+
properties: { host: CASHIER_HOST }
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Custom Request Params and Iframe Options
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { CashierBootstrapper } from '@morefin/cashier-bootstrapper';
|
|
33
|
+
|
|
34
|
+
new CashierBootstrapper('#cashier-root', {
|
|
35
|
+
requestParams: {
|
|
36
|
+
merchantId: 'merchant-123',
|
|
37
|
+
terminalId: 'terminal-456',
|
|
38
|
+
userId: 'user-789',
|
|
39
|
+
sessionId: 'session-abc',
|
|
40
|
+
predefinedAmounts: [100, 200, 300],
|
|
41
|
+
layout: 'default'
|
|
42
|
+
},
|
|
43
|
+
properties: {
|
|
44
|
+
host: CASHIER_HOST,
|
|
45
|
+
cashierPath: '/cashier',
|
|
46
|
+
iframe: {
|
|
47
|
+
height: '720px',
|
|
48
|
+
minHeight: '640px',
|
|
49
|
+
title: 'Morefin Cashier'
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}, api => {
|
|
53
|
+
console.log('Cashier iframe ready', api.iframe);
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Provide Container via Config
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { CashierBootstrapper } from '@morefin/cashier-bootstrapper';
|
|
61
|
+
|
|
62
|
+
new CashierBootstrapper(null, {
|
|
63
|
+
properties: {
|
|
64
|
+
host: CASHIER_HOST,
|
|
65
|
+
container: '#cashier-root'
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Runtime Controls (CSS + Data)
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { CashierBootstrapper } from '@morefin/cashier-bootstrapper';
|
|
74
|
+
|
|
75
|
+
new CashierBootstrapper('#cashier-root', {
|
|
76
|
+
properties: { host: CASHIER_HOST }
|
|
77
|
+
}, api => {
|
|
78
|
+
api.setCss(`
|
|
79
|
+
.payment-layout-root .payment-container {
|
|
80
|
+
border: 2px dashed hotpink;
|
|
81
|
+
}
|
|
82
|
+
`);
|
|
83
|
+
|
|
84
|
+
api.updateData({ userId: 'updated-user' });
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Examples Folder
|
|
89
|
+
|
|
90
|
+
- `examples/npm` contains a minimal app that installs the package from npm and bundles it with esbuild.
|
|
91
|
+
- `src/example-usage.ts` contains additional snippets for reference.
|
|
92
|
+
|
|
93
|
+
## API
|
|
94
|
+
|
|
95
|
+
### `new CashierBootstrapper(container, config?, onReady?)`
|
|
96
|
+
|
|
97
|
+
Iframe-based embed that loads the cashier URL and exposes runtime controls once ready.
|
|
98
|
+
|
|
99
|
+
**Parameters:**
|
|
100
|
+
- `container: string | HTMLElement | null | undefined` - Where the iframe is appended. If omitted, `config.properties.container` is used (falling back to `document.body`).
|
|
101
|
+
- `config?: CashierIframeConfig` - Request params and iframe properties. `properties.host` is required.
|
|
102
|
+
- `onReady?: (api: CashierIframeApi) => void` - Called when the iframe loads; exposes helpers:
|
|
103
|
+
- `api.setCss(css: string)` – inject CSS inside the cashier iframe
|
|
104
|
+
- `api.updateData(data: object)` – post updated `APP_DATA` to the cashier
|
|
105
|
+
- `api.pause()` / `api.resume()` – forward pause/resume signals
|
|
106
|
+
|
|
107
|
+
## Types
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
interface CashierRequestParams {
|
|
111
|
+
merchantId?: string;
|
|
112
|
+
terminalId?: string;
|
|
113
|
+
userId?: string;
|
|
114
|
+
sessionId?: string;
|
|
115
|
+
predefinedAmounts?: number[];
|
|
116
|
+
layout?: string;
|
|
117
|
+
fingerprint?: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
interface CashierIframeOptions {
|
|
121
|
+
width?: string;
|
|
122
|
+
height?: string;
|
|
123
|
+
minHeight?: string;
|
|
124
|
+
title?: string;
|
|
125
|
+
allow?: string;
|
|
126
|
+
sandbox?: string;
|
|
127
|
+
attributes?: Record<string, string>;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
interface CashierIframeProperties {
|
|
131
|
+
host: string;
|
|
132
|
+
container?: string | HTMLElement;
|
|
133
|
+
cashierPath?: string;
|
|
134
|
+
iframe?: CashierIframeOptions;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
interface CashierIframeConfig {
|
|
138
|
+
requestParams?: CashierRequestParams;
|
|
139
|
+
properties?: CashierIframeProperties;
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Defaults
|
|
144
|
+
|
|
145
|
+
- `cashierPath`: `/cashier`
|
|
146
|
+
- `iframe.width`/`iframe.height`: `100%`
|
|
147
|
+
- `iframe.allow`: `geolocation *;camera *;payment *;clipboard-read *;clipboard-write *;autoplay *;microphone *;fullscreen *;accelerometer *;magnetometer *;gyroscope *;picture-in-picture *;otp-credentials *;`
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example usage file - demonstrates how to use the cashier bootstrapper.
|
|
3
|
+
* This file is not included in the npm package, it's just for reference.
|
|
4
|
+
*/
|
|
5
|
+
export declare function example1(): void;
|
|
6
|
+
export declare function example2(container: string | HTMLElement): void;
|
|
7
|
+
export declare function example3(): void;
|
|
8
|
+
export declare function example4(container: string | HTMLElement): void;
|
|
9
|
+
export declare function example5(container: string | HTMLElement): void;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example usage file - demonstrates how to use the cashier bootstrapper.
|
|
3
|
+
* This file is not included in the npm package, it's just for reference.
|
|
4
|
+
*/
|
|
5
|
+
import { CashierBootstrapper } from './index';
|
|
6
|
+
const CASHIER_HOST = 'http://localhost:7082'; // change per environment
|
|
7
|
+
// Example 1: Minimal configuration with selector
|
|
8
|
+
export function example1() {
|
|
9
|
+
new CashierBootstrapper('#cashier-root', {
|
|
10
|
+
properties: { host: CASHIER_HOST }
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
// Example 2: Custom request params + iframe options
|
|
14
|
+
export function example2(container) {
|
|
15
|
+
new CashierBootstrapper(container, {
|
|
16
|
+
requestParams: {
|
|
17
|
+
merchantId: 'merchant-123',
|
|
18
|
+
terminalId: 'terminal-456',
|
|
19
|
+
userId: 'user-789',
|
|
20
|
+
sessionId: 'session-abc',
|
|
21
|
+
predefinedAmounts: [100, 200, 300],
|
|
22
|
+
layout: 'default'
|
|
23
|
+
},
|
|
24
|
+
properties: {
|
|
25
|
+
host: CASHIER_HOST,
|
|
26
|
+
cashierPath: '/cashier',
|
|
27
|
+
iframe: {
|
|
28
|
+
height: '720px',
|
|
29
|
+
minHeight: '640px',
|
|
30
|
+
title: 'Morefin Cashier'
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}, api => {
|
|
34
|
+
console.log('Cashier iframe ready', api.iframe);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
// Example 3: Provide container via config instead of constructor
|
|
38
|
+
export function example3() {
|
|
39
|
+
new CashierBootstrapper(null, {
|
|
40
|
+
properties: { host: CASHIER_HOST, container: '#cashier-root' }
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// Example 4: Update CSS at runtime after iframe is ready
|
|
44
|
+
export function example4(container) {
|
|
45
|
+
new CashierBootstrapper(container, {
|
|
46
|
+
requestParams: {
|
|
47
|
+
merchantId: 'merchant-123',
|
|
48
|
+
terminalId: 'terminal-456',
|
|
49
|
+
userId: 'user-789',
|
|
50
|
+
predefinedAmounts: [100, 200, 300],
|
|
51
|
+
layout: 'default'
|
|
52
|
+
},
|
|
53
|
+
properties: {
|
|
54
|
+
host: CASHIER_HOST
|
|
55
|
+
}
|
|
56
|
+
}, api => {
|
|
57
|
+
api.setCss(`
|
|
58
|
+
.payment-layout-root .payment-container {
|
|
59
|
+
border: 2px dashed hotpink;
|
|
60
|
+
}
|
|
61
|
+
`);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// Example 5: Updating data via the postMessage API
|
|
65
|
+
export function example5(container) {
|
|
66
|
+
new CashierBootstrapper(container, {
|
|
67
|
+
properties: { host: CASHIER_HOST }
|
|
68
|
+
}, api => {
|
|
69
|
+
api.updateData({
|
|
70
|
+
userId: 'updated-user'
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { CashierIframeApi, CashierIframeConfig } from './types';
|
|
2
|
+
export type { CashierRequestParams, CashierIframeApi, CashierIframeConfig, CashierIframeProperties } from './types';
|
|
3
|
+
type FingerprintJSGlobal = {
|
|
4
|
+
load: () => Promise<{
|
|
5
|
+
get: () => Promise<{
|
|
6
|
+
visitorId: string;
|
|
7
|
+
}>;
|
|
8
|
+
}>;
|
|
9
|
+
};
|
|
10
|
+
declare global {
|
|
11
|
+
interface Window {
|
|
12
|
+
FingerprintJS?: FingerprintJSGlobal;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export declare class CashierBootstrapper {
|
|
16
|
+
private iframe?;
|
|
17
|
+
private origin;
|
|
18
|
+
private ready;
|
|
19
|
+
private readonly fullConfig;
|
|
20
|
+
private readonly onReady?;
|
|
21
|
+
constructor(container: string | HTMLElement | null | undefined, config?: CashierIframeConfig, onReady?: (api: CashierIframeApi) => void);
|
|
22
|
+
private bootstrapIframe;
|
|
23
|
+
private createIframeShell;
|
|
24
|
+
private handleLoad;
|
|
25
|
+
private postMessage;
|
|
26
|
+
/**
|
|
27
|
+
* API exposed to host pages for runtime control.
|
|
28
|
+
*/
|
|
29
|
+
api(): CashierIframeApi;
|
|
30
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
const DEFAULT_IFRAME_ALLOW = 'geolocation *;camera *;payment *;clipboard-read *;clipboard-write *;autoplay *;microphone *;fullscreen *;accelerometer *;magnetometer *;gyroscope *;picture-in-picture *;otp-credentials *;';
|
|
2
|
+
const FINGERPRINT_CDN = 'https://cdn.jsdelivr.net/npm/@fingerprintjs/fingerprintjs@4/dist/fp.min.js';
|
|
3
|
+
let fpLoaderPromise;
|
|
4
|
+
function loadFingerprintLibrary() {
|
|
5
|
+
if (typeof window === 'undefined') {
|
|
6
|
+
return Promise.reject(new Error('FingerprintJS requires a browser environment'));
|
|
7
|
+
}
|
|
8
|
+
if (window.FingerprintJS) {
|
|
9
|
+
return Promise.resolve(window.FingerprintJS);
|
|
10
|
+
}
|
|
11
|
+
if (fpLoaderPromise) {
|
|
12
|
+
return fpLoaderPromise;
|
|
13
|
+
}
|
|
14
|
+
fpLoaderPromise = new Promise((resolve, reject) => {
|
|
15
|
+
const script = document.createElement('script');
|
|
16
|
+
script.src = FINGERPRINT_CDN;
|
|
17
|
+
script.async = true;
|
|
18
|
+
script.onload = () => {
|
|
19
|
+
if (window.FingerprintJS) {
|
|
20
|
+
resolve(window.FingerprintJS);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
reject(new Error('FingerprintJS did not register on window'));
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
script.onerror = () => reject(new Error('Failed to load FingerprintJS from CDN'));
|
|
27
|
+
document.head.appendChild(script);
|
|
28
|
+
});
|
|
29
|
+
return fpLoaderPromise;
|
|
30
|
+
}
|
|
31
|
+
async function generateFingerprint() {
|
|
32
|
+
try {
|
|
33
|
+
const fpLib = await loadFingerprintLibrary();
|
|
34
|
+
const fp = await fpLib.load();
|
|
35
|
+
const result = await fp.get();
|
|
36
|
+
return result.visitorId;
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
console.warn('Fingerprint generation failed; continuing without it', err);
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function buildQueryString(requestParams) {
|
|
44
|
+
const query = new URLSearchParams();
|
|
45
|
+
if (requestParams.merchantId != null) {
|
|
46
|
+
query.append('merchantId', String(requestParams.merchantId));
|
|
47
|
+
}
|
|
48
|
+
if (requestParams.terminalId != null) {
|
|
49
|
+
query.append('terminalId', String(requestParams.terminalId));
|
|
50
|
+
}
|
|
51
|
+
if (requestParams.userId != null) {
|
|
52
|
+
query.append('userId', String(requestParams.userId));
|
|
53
|
+
}
|
|
54
|
+
if (requestParams.sessionId != null) {
|
|
55
|
+
query.append('sessionId', String(requestParams.sessionId));
|
|
56
|
+
}
|
|
57
|
+
if (Array.isArray(requestParams.predefinedAmounts)) {
|
|
58
|
+
requestParams.predefinedAmounts.forEach(amount => {
|
|
59
|
+
query.append('predefinedAmounts', String(amount));
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (requestParams.layout != null) {
|
|
63
|
+
query.append('layout', requestParams.layout);
|
|
64
|
+
}
|
|
65
|
+
if (requestParams.fingerprint) {
|
|
66
|
+
query.append('fingerprint', requestParams.fingerprint);
|
|
67
|
+
}
|
|
68
|
+
const qs = query.toString();
|
|
69
|
+
return qs ? `?${qs}` : '';
|
|
70
|
+
}
|
|
71
|
+
function normalizePath(path) {
|
|
72
|
+
if (!path) {
|
|
73
|
+
return '/cashier';
|
|
74
|
+
}
|
|
75
|
+
return path.startsWith('/') ? path : `/${path}`;
|
|
76
|
+
}
|
|
77
|
+
function resolveContainer(container) {
|
|
78
|
+
if (container instanceof HTMLElement) {
|
|
79
|
+
return container;
|
|
80
|
+
}
|
|
81
|
+
if (typeof container === 'string') {
|
|
82
|
+
const target = document.querySelector(container);
|
|
83
|
+
if (target) {
|
|
84
|
+
return target;
|
|
85
|
+
}
|
|
86
|
+
console.warn(`Container selector "${container}" not found, defaulting to body`);
|
|
87
|
+
}
|
|
88
|
+
return document.body;
|
|
89
|
+
}
|
|
90
|
+
function buildIframeUrl(host, cashierPath, requestParams) {
|
|
91
|
+
const trimmedHost = host.endsWith('/') ? host.slice(0, -1) : host;
|
|
92
|
+
const path = normalizePath(cashierPath);
|
|
93
|
+
return `${trimmedHost}${path}${buildQueryString(requestParams)}`;
|
|
94
|
+
}
|
|
95
|
+
function getOriginFromUrl(url) {
|
|
96
|
+
try {
|
|
97
|
+
return new URL(url).origin;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return '*';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export class CashierBootstrapper {
|
|
104
|
+
constructor(container, config = {}, onReady) {
|
|
105
|
+
this.origin = '*';
|
|
106
|
+
this.ready = false;
|
|
107
|
+
this.onReady = onReady;
|
|
108
|
+
const host = config.properties?.host;
|
|
109
|
+
if (!host) {
|
|
110
|
+
throw new Error('Cashier host is required to bootstrap the iframe');
|
|
111
|
+
}
|
|
112
|
+
this.fullConfig = {
|
|
113
|
+
requestParams: { ...config.requestParams },
|
|
114
|
+
properties: {
|
|
115
|
+
...config.properties,
|
|
116
|
+
host,
|
|
117
|
+
cashierPath: normalizePath(config.properties?.cashierPath),
|
|
118
|
+
iframe: {
|
|
119
|
+
width: '100%',
|
|
120
|
+
height: '100%',
|
|
121
|
+
allow: DEFAULT_IFRAME_ALLOW,
|
|
122
|
+
...config.properties?.iframe
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const target = resolveContainer(container ?? this.fullConfig.properties.container);
|
|
127
|
+
this.iframe = this.createIframeShell(target);
|
|
128
|
+
void this.bootstrapIframe();
|
|
129
|
+
}
|
|
130
|
+
async bootstrapIframe() {
|
|
131
|
+
const fp = await generateFingerprint();
|
|
132
|
+
if (fp) {
|
|
133
|
+
this.fullConfig.requestParams.fingerprint = fp;
|
|
134
|
+
}
|
|
135
|
+
const src = buildIframeUrl(this.fullConfig.properties.host, this.fullConfig.properties.cashierPath ?? '/cashier', this.fullConfig.requestParams);
|
|
136
|
+
this.origin = getOriginFromUrl(src);
|
|
137
|
+
if (this.iframe) {
|
|
138
|
+
this.iframe.src = src;
|
|
139
|
+
this.iframe.onload = () => this.handleLoad();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
createIframeShell(container) {
|
|
143
|
+
const iframe = document.createElement('iframe');
|
|
144
|
+
const { iframe: iframeOptions } = this.fullConfig.properties;
|
|
145
|
+
iframe.style.border = 'none';
|
|
146
|
+
iframe.style.width = iframeOptions?.width ?? '100%';
|
|
147
|
+
iframe.style.height = iframeOptions?.height ?? '100%';
|
|
148
|
+
if (iframeOptions?.minHeight) {
|
|
149
|
+
iframe.style.minHeight = iframeOptions.minHeight;
|
|
150
|
+
}
|
|
151
|
+
iframe.title = iframeOptions?.title ?? 'Cashier';
|
|
152
|
+
iframe.allow = iframeOptions?.allow ?? DEFAULT_IFRAME_ALLOW;
|
|
153
|
+
if (iframeOptions?.sandbox) {
|
|
154
|
+
iframe.setAttribute('sandbox', iframeOptions.sandbox);
|
|
155
|
+
}
|
|
156
|
+
if (iframeOptions?.attributes) {
|
|
157
|
+
Object.entries(iframeOptions.attributes).forEach(([key, value]) => iframe.setAttribute(key, value));
|
|
158
|
+
}
|
|
159
|
+
iframe.setAttribute('data-cashier-iframe', 'true');
|
|
160
|
+
iframe.setAttribute('data-cy', 'cashier-iframe');
|
|
161
|
+
container.innerHTML = '';
|
|
162
|
+
container.appendChild(iframe);
|
|
163
|
+
return iframe;
|
|
164
|
+
}
|
|
165
|
+
handleLoad() {
|
|
166
|
+
if (this.ready)
|
|
167
|
+
return;
|
|
168
|
+
this.ready = true;
|
|
169
|
+
if (this.onReady) {
|
|
170
|
+
this.onReady(this.api());
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
postMessage(eventType, payload) {
|
|
174
|
+
if (!this.iframe?.contentWindow) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
this.iframe.contentWindow.postMessage({ eventType, payload }, this.origin);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* API exposed to host pages for runtime control.
|
|
181
|
+
*/
|
|
182
|
+
api() {
|
|
183
|
+
if (!this.iframe) {
|
|
184
|
+
throw new Error('Cashier iframe not initialized');
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
iframe: this.iframe,
|
|
188
|
+
setCss: (css) => this.postMessage('SET_CSS', css),
|
|
189
|
+
updateData: (data) => this.postMessage('UPDATE_DATA', data),
|
|
190
|
+
pause: () => this.postMessage('CASHIER_PAUSE', {}),
|
|
191
|
+
resume: () => this.postMessage('CASHIER_RESUME', {})
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cashier request parameters
|
|
3
|
+
*/
|
|
4
|
+
export interface CashierRequestParams {
|
|
5
|
+
merchantId?: string;
|
|
6
|
+
terminalId?: string;
|
|
7
|
+
userId?: string;
|
|
8
|
+
sessionId?: string;
|
|
9
|
+
predefinedAmounts?: number[];
|
|
10
|
+
layout?: string;
|
|
11
|
+
fingerprint?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Bootstrap properties configuration
|
|
15
|
+
*/
|
|
16
|
+
export interface BootstrapProperties {
|
|
17
|
+
host: string;
|
|
18
|
+
/**
|
|
19
|
+
* Selector or element where HTML should be rendered
|
|
20
|
+
* Default: 'body' (replaces entire body)
|
|
21
|
+
*/
|
|
22
|
+
container?: string | HTMLElement;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Bootstrap configuration combining request params and properties
|
|
26
|
+
*/
|
|
27
|
+
export interface CashierBootstrapConfig {
|
|
28
|
+
requestParams: CashierRequestParams;
|
|
29
|
+
properties: BootstrapProperties;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Additional iframe options for isolated embedding.
|
|
33
|
+
*/
|
|
34
|
+
export interface CashierIframeOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Width of the iframe element. Default: '100%'.
|
|
37
|
+
*/
|
|
38
|
+
width?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Height of the iframe element. Default: '100%'.
|
|
41
|
+
*/
|
|
42
|
+
height?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Min height used to avoid layout jumps while cashier loads.
|
|
45
|
+
*/
|
|
46
|
+
minHeight?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Title attribute for accessibility.
|
|
49
|
+
*/
|
|
50
|
+
title?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Allow attribute controlling available browser features.
|
|
53
|
+
*/
|
|
54
|
+
allow?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Sandbox attribute if stricter isolation is desired.
|
|
57
|
+
*/
|
|
58
|
+
sandbox?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Extra attributes applied to the iframe element.
|
|
61
|
+
*/
|
|
62
|
+
attributes?: Record<string, string>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Properties for iframe embedding.
|
|
66
|
+
*/
|
|
67
|
+
export interface CashierIframeProperties extends BootstrapProperties {
|
|
68
|
+
/**
|
|
69
|
+
* Optional DOM container (selector or element) where the iframe is appended.
|
|
70
|
+
*/
|
|
71
|
+
container?: string | HTMLElement;
|
|
72
|
+
/**
|
|
73
|
+
* Path to the cashier page. Default: '/cashier'.
|
|
74
|
+
*/
|
|
75
|
+
cashierPath?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Iframe tuning options (dimensions, attributes).
|
|
78
|
+
*/
|
|
79
|
+
iframe?: CashierIframeOptions;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Config used by the iframe-based bootstrapper class.
|
|
83
|
+
*/
|
|
84
|
+
export interface CashierIframeConfig {
|
|
85
|
+
requestParams?: CashierRequestParams;
|
|
86
|
+
properties?: CashierIframeProperties;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Minimal API surface returned to hosts after iframe creation.
|
|
90
|
+
*/
|
|
91
|
+
export interface CashierIframeApi {
|
|
92
|
+
iframe: HTMLIFrameElement;
|
|
93
|
+
setCss: (css: string) => void;
|
|
94
|
+
updateData: (data: Record<string, unknown>) => void;
|
|
95
|
+
pause: () => void;
|
|
96
|
+
resume: () => void;
|
|
97
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@morefin/cashier-bootstrapper",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Bootstrap service for initializing cashier payment page data from API",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"prepublishOnly": "npm run build",
|
|
11
|
+
"clean": "rm -rf dist"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"morefin",
|
|
15
|
+
"cashier",
|
|
16
|
+
"payment",
|
|
17
|
+
"bootstrap",
|
|
18
|
+
"hosted-payment-page"
|
|
19
|
+
],
|
|
20
|
+
"author": "",
|
|
21
|
+
"license": "ISC",
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"README.md"
|
|
28
|
+
],
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^20.11.17",
|
|
31
|
+
"typescript": "^5.8.3"
|
|
32
|
+
}
|
|
33
|
+
}
|