@yuno-payments/dashboard-embed-sdk 1.0.0 → 1.2.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 +102 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +36 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -70,10 +70,13 @@ destroyDashboard();
|
|
|
70
70
|
| `token` | `string` | No | JWT auth token — sent via PostMessage after the iframe is ready |
|
|
71
71
|
| `theme` | `DashboardTheme` | No | Initial theme configuration |
|
|
72
72
|
| `lang` | `string` | No | Language code (default: `"en"`) |
|
|
73
|
-
| `path` | `string` | No | Initial navigation path (default: `"/"`) |
|
|
73
|
+
| `path` | `string` | No | Initial navigation path (default: `"/"`). Pass a clean route with no query string — see [Test mode](#test-mode) for why a `?test=` path breaks the embed |
|
|
74
|
+
| `testMode` | `boolean` | No | When set, the dashboard mounts in test/sandbox mode (`true`) or live mode (`false`). Omit to inherit the dashboard's own default. See [Test mode](#test-mode) |
|
|
74
75
|
| `onReady` | `() => void` | No | Callback invoked when the dashboard is fully loaded and authenticated |
|
|
75
76
|
| `onSessionExpired` | `() => void` | No | Callback invoked when the embedded session has expired. The host should re-authenticate and call `setToken(newToken)` to resume. |
|
|
77
|
+
| `onCheckoutPublished` | `(event: CheckoutPublishedEvent) => void \| Promise<void>` | No | Callback invoked when the user publishes the checkout configuration or styling. `event.source` is `"checkout"` or `"styling"`, `event.status` reports the publish call state (`"loading"` → `"success"` or `"error"`), and `event.payload` contains the configuration object that was published. |
|
|
76
78
|
| `loading` | `HTMLElement` | No | Custom loading overlay element. If omitted, a default spinner is shown |
|
|
79
|
+
| `autoHeight` | `boolean` | No | When `true`, the iframe is resized to match the dashboard content height (no inner scroll). Default `false` (iframe fills its container at `100%`). See [Auto height](#auto-height) |
|
|
77
80
|
|
|
78
81
|
### Methods
|
|
79
82
|
|
|
@@ -81,6 +84,7 @@ destroyDashboard();
|
|
|
81
84
|
- **`setLang(lang)`** — Change display language
|
|
82
85
|
- **`setToken(token)`** — Update the auth token via PostMessage
|
|
83
86
|
- **`navigate(path)`** — Navigate to a dashboard route
|
|
87
|
+
- **`setTestMode(enabled)`** — Toggle test/sandbox mode at runtime via PostMessage. See [Test mode](#test-mode)
|
|
84
88
|
- **`destroy()`** — Remove iframe and clean up event listeners
|
|
85
89
|
|
|
86
90
|
### Types
|
|
@@ -128,6 +132,16 @@ interface DashboardTheme {
|
|
|
128
132
|
mode?: "light" | "dark";
|
|
129
133
|
styles?: string; // Custom CSS injected into the dashboard
|
|
130
134
|
}
|
|
135
|
+
|
|
136
|
+
type CheckoutPublishedSource = "checkout" | "styling";
|
|
137
|
+
|
|
138
|
+
type CheckoutPublishedStatus = "loading" | "success" | "error";
|
|
139
|
+
|
|
140
|
+
interface CheckoutPublishedEvent {
|
|
141
|
+
source: CheckoutPublishedSource;
|
|
142
|
+
status: CheckoutPublishedStatus;
|
|
143
|
+
payload?: unknown; // The configuration object that was published
|
|
144
|
+
}
|
|
131
145
|
```
|
|
132
146
|
|
|
133
147
|
## Session timeouts
|
|
@@ -157,10 +171,97 @@ const sdk = initDashboard({
|
|
|
157
171
|
})
|
|
158
172
|
```
|
|
159
173
|
|
|
174
|
+
## Checkout published events
|
|
175
|
+
|
|
176
|
+
Whenever the user publishes from the embedded Checkout Builder (payment method
|
|
177
|
+
configuration) or the Styling editor, the iframe emits a message to the host.
|
|
178
|
+
Subscribe via `onCheckoutPublished`:
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
const sdk = initDashboard({
|
|
182
|
+
baseUrl: "https://dashboard.y.uno",
|
|
183
|
+
container: document.getElementById("dashboard")!,
|
|
184
|
+
token: initialToken,
|
|
185
|
+
onCheckoutPublished: (event) => {
|
|
186
|
+
// event.source is "checkout" | "styling"
|
|
187
|
+
// event.status is "loading" | "success" | "error"
|
|
188
|
+
// event.payload is the configuration object that was published
|
|
189
|
+
switch (event.status) {
|
|
190
|
+
case "loading":
|
|
191
|
+
console.log(`Publish loading from ${event.source}`)
|
|
192
|
+
break
|
|
193
|
+
case "success":
|
|
194
|
+
console.log(`Checkout published from ${event.source}`, event.payload)
|
|
195
|
+
break
|
|
196
|
+
case "error":
|
|
197
|
+
console.log("Publish failed — please try again")
|
|
198
|
+
break
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
})
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The callback fires once per state transition of the publish call: first with
|
|
205
|
+
`status: "loading"` when the user triggers the publish, then a second time with
|
|
206
|
+
either `"success"` or `"error"` once the dashboard's publish endpoint responds.
|
|
207
|
+
`event.payload` is only meaningful on the `"success"` event.
|
|
208
|
+
|
|
209
|
+
## Test mode
|
|
210
|
+
|
|
211
|
+
The dashboard can run in **test/sandbox** mode or **live** mode. Set it at mount time
|
|
212
|
+
via the `testMode` option, or toggle it at runtime via `setTestMode(enabled)`:
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
const sdk = initDashboard({
|
|
216
|
+
baseUrl: "https://dashboard.y.uno",
|
|
217
|
+
container: document.getElementById("dashboard")!,
|
|
218
|
+
token,
|
|
219
|
+
path: "/connections", // clean route — no query string
|
|
220
|
+
testMode: false, // mount in live mode
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// Later — flip to test mode without remounting
|
|
224
|
+
sdk.setTestMode(true);
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Do not pass test mode through `path`.** The SDK builds the iframe URL by appending its
|
|
228
|
+
own query string (`embed`, `theme`, `lang`, and `test` when `testMode` is set) to the route:
|
|
229
|
+
`${baseUrl}${path}?embed=true&…`. A `path` that already carries a query (e.g.
|
|
230
|
+
`"/connections?test=false"`) produces a malformed double-`?` URL that swallows `embed` and
|
|
231
|
+
breaks the embed (the dashboard never mounts). Always pass a query-free `path` and use the
|
|
232
|
+
`testMode` option / `setTestMode()` method instead.
|
|
233
|
+
|
|
234
|
+
**Host/iframe contract:** when `testMode` is provided, the SDK appends `test=<bool>` to the
|
|
235
|
+
initial iframe URL — the embedded dashboard reads it from its own URL on load. For the runtime
|
|
236
|
+
toggle, `setTestMode(enabled)` sends `postMessage({ action: "setTestMode", testMode })` (accepted
|
|
237
|
+
only from the configured `baseUrl` origin); the embedded dashboard must handle that action to
|
|
238
|
+
switch mode without a reload.
|
|
239
|
+
|
|
160
240
|
## Loading overlay
|
|
161
241
|
|
|
162
242
|
A loading overlay covers the iframe while initialization completes. You can provide a custom element via the `loading` config option, or the SDK renders a default spinner. The overlay fades out automatically (300ms transition) once the dashboard is authenticated and ready.
|
|
163
243
|
|
|
244
|
+
## Auto height
|
|
245
|
+
|
|
246
|
+
By default the iframe fills its container (`height: 100%`) and the dashboard content
|
|
247
|
+
scrolls inside it. Pass `autoHeight: true` to size the iframe to the dashboard's content
|
|
248
|
+
height instead, so the whole host page scrolls naturally with no inner scrollbar:
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
initDashboard({
|
|
252
|
+
baseUrl: "https://dashboard.y.uno",
|
|
253
|
+
container: document.getElementById("dashboard")!,
|
|
254
|
+
token,
|
|
255
|
+
autoHeight: true,
|
|
256
|
+
});
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Host/iframe contract:** when `autoHeight` is enabled, the embedded dashboard reports its
|
|
260
|
+
content height to the host via `postMessage({ action: "resize", height })` whenever the
|
|
261
|
+
content resizes; the SDK applies that height to the iframe and its wrapper. Messages are
|
|
262
|
+
accepted only from the configured `baseUrl` origin. Your container must allow vertical growth
|
|
263
|
+
(avoid a fixed `height` / `overflow: hidden`) for the effect to be visible.
|
|
264
|
+
|
|
164
265
|
## Migrating from 0.x to 1.0
|
|
165
266
|
|
|
166
267
|
`1.0.0` drops the `Yuno` brand prefix from the public API so the SDK reads cleanly
|
package/dist/index.d.ts
CHANGED
|
@@ -37,6 +37,13 @@ interface DashboardTheme {
|
|
|
37
37
|
mode?: "light" | "dark";
|
|
38
38
|
styles?: string;
|
|
39
39
|
}
|
|
40
|
+
type CheckoutPublishedSource = "checkout" | "styling";
|
|
41
|
+
type CheckoutPublishedStatus = "loading" | "success" | "error";
|
|
42
|
+
interface CheckoutPublishedEvent {
|
|
43
|
+
source: CheckoutPublishedSource;
|
|
44
|
+
status: CheckoutPublishedStatus;
|
|
45
|
+
payload?: unknown;
|
|
46
|
+
}
|
|
40
47
|
interface DashboardConfig {
|
|
41
48
|
baseUrl: string;
|
|
42
49
|
container: HTMLElement;
|
|
@@ -44,9 +51,12 @@ interface DashboardConfig {
|
|
|
44
51
|
theme?: DashboardTheme;
|
|
45
52
|
lang?: string;
|
|
46
53
|
path?: string;
|
|
54
|
+
testMode?: boolean;
|
|
47
55
|
onReady?: () => void;
|
|
48
56
|
onSessionExpired?: () => void | Promise<void>;
|
|
57
|
+
onCheckoutPublished?: (event: CheckoutPublishedEvent) => void | Promise<void>;
|
|
49
58
|
loading?: HTMLElement;
|
|
59
|
+
autoHeight?: boolean;
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
declare class Dashboard {
|
|
@@ -60,14 +70,18 @@ declare class Dashboard {
|
|
|
60
70
|
private initialTheme?;
|
|
61
71
|
private initialLang?;
|
|
62
72
|
private initialPath;
|
|
73
|
+
private initialTestMode?;
|
|
63
74
|
private token?;
|
|
64
75
|
private onReadyCallback?;
|
|
65
76
|
private onSessionExpiredCallback?;
|
|
77
|
+
private onCheckoutPublishedCallback?;
|
|
78
|
+
private autoHeight;
|
|
66
79
|
constructor(config: DashboardConfig);
|
|
67
80
|
setTheme(theme: DashboardTheme): void;
|
|
68
81
|
setLang(lang: string): void;
|
|
69
82
|
setToken(token: string): void;
|
|
70
83
|
navigate(path: string): void;
|
|
84
|
+
setTestMode(enabled: boolean): void;
|
|
71
85
|
destroy(): void;
|
|
72
86
|
private post;
|
|
73
87
|
private flush;
|
|
@@ -82,4 +96,4 @@ declare function initDashboard(config: DashboardConfig): Dashboard;
|
|
|
82
96
|
declare function getDashboard(): Dashboard | null;
|
|
83
97
|
declare function destroyDashboard(): void;
|
|
84
98
|
|
|
85
|
-
export { Dashboard, type DashboardConfig, type DashboardTheme, type ModeTokens, type ThemeColors, type ThemeTypography, destroyDashboard, getDashboard, initDashboard };
|
|
99
|
+
export { type CheckoutPublishedEvent, type CheckoutPublishedSource, type CheckoutPublishedStatus, Dashboard, type DashboardConfig, type DashboardTheme, type ModeTokens, type ThemeColors, type ThemeTypography, destroyDashboard, getDashboard, initDashboard };
|
package/dist/index.js
CHANGED
|
@@ -8,9 +8,12 @@ var Dashboard = class {
|
|
|
8
8
|
this.initialTheme = config.theme;
|
|
9
9
|
this.initialLang = config.lang;
|
|
10
10
|
this.initialPath = config.path ?? "/";
|
|
11
|
+
this.initialTestMode = config.testMode;
|
|
11
12
|
this.token = config.token;
|
|
12
13
|
this.onReadyCallback = config.onReady;
|
|
13
14
|
this.onSessionExpiredCallback = config.onSessionExpired;
|
|
15
|
+
this.onCheckoutPublishedCallback = config.onCheckoutPublished;
|
|
16
|
+
this.autoHeight = config.autoHeight ?? false;
|
|
14
17
|
this.wrapper = document.createElement("div");
|
|
15
18
|
this.wrapper.style.position = "relative";
|
|
16
19
|
this.wrapper.style.width = "100%";
|
|
@@ -29,6 +32,11 @@ var Dashboard = class {
|
|
|
29
32
|
this.wrapper.appendChild(this.overlay);
|
|
30
33
|
this.messageHandler = (e) => {
|
|
31
34
|
if (e.origin !== this.baseUrl) return;
|
|
35
|
+
if (this.autoHeight && e.data?.action === "resize" && typeof e.data?.height === "number") {
|
|
36
|
+
this.iframe.style.height = `${e.data.height}px`;
|
|
37
|
+
this.wrapper.style.height = `${e.data.height}px`;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
32
40
|
if (e.data?.type === "yuno-dashboard:session-expired") {
|
|
33
41
|
try {
|
|
34
42
|
const result = this.onSessionExpiredCallback?.();
|
|
@@ -45,6 +53,26 @@ var Dashboard = class {
|
|
|
45
53
|
}
|
|
46
54
|
return;
|
|
47
55
|
}
|
|
56
|
+
if (e.data?.type === "yuno-dashboard:checkout-published") {
|
|
57
|
+
try {
|
|
58
|
+
const result = this.onCheckoutPublishedCallback?.({
|
|
59
|
+
source: e.data?.source,
|
|
60
|
+
status: e.data?.status,
|
|
61
|
+
payload: e.data?.payload
|
|
62
|
+
});
|
|
63
|
+
if (result && typeof result.catch === "function") {
|
|
64
|
+
result.catch(
|
|
65
|
+
(err) => (
|
|
66
|
+
// eslint-disable-next-line no-console
|
|
67
|
+
console.warn("[yuno-dashboard-sdk] onCheckoutPublished async callback rejected", err)
|
|
68
|
+
)
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
} catch (err) {
|
|
72
|
+
console.warn("[yuno-dashboard-sdk] onCheckoutPublished callback threw", err);
|
|
73
|
+
}
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
48
76
|
if (e.data?.action === "ready") {
|
|
49
77
|
this.onReady();
|
|
50
78
|
}
|
|
@@ -79,6 +107,9 @@ var Dashboard = class {
|
|
|
79
107
|
navigate(path) {
|
|
80
108
|
this.post({ action: "navigate", path });
|
|
81
109
|
}
|
|
110
|
+
setTestMode(enabled) {
|
|
111
|
+
this.post({ action: "setTestMode", testMode: enabled });
|
|
112
|
+
}
|
|
82
113
|
destroy() {
|
|
83
114
|
window.removeEventListener("message", this.messageHandler);
|
|
84
115
|
this.wrapper.remove();
|
|
@@ -115,9 +146,6 @@ var Dashboard = class {
|
|
|
115
146
|
}
|
|
116
147
|
onTokenApplied() {
|
|
117
148
|
setTimeout(() => {
|
|
118
|
-
if (this.initialPath !== "/") {
|
|
119
|
-
this.post({ action: "navigate", path: this.initialPath });
|
|
120
|
-
}
|
|
121
149
|
this.hideOverlay();
|
|
122
150
|
this.onReadyCallback?.();
|
|
123
151
|
}, 1e3);
|
|
@@ -153,7 +181,11 @@ var Dashboard = class {
|
|
|
153
181
|
theme: this.initialTheme?.mode ?? "light",
|
|
154
182
|
lang: this.initialLang ?? "en"
|
|
155
183
|
});
|
|
156
|
-
|
|
184
|
+
if (this.initialTestMode !== void 0) {
|
|
185
|
+
params.set("test", String(this.initialTestMode));
|
|
186
|
+
}
|
|
187
|
+
const path = !this.initialPath || this.initialPath === "/" ? "/" : this.initialPath;
|
|
188
|
+
return `${this.baseUrl}${path}?${params.toString()}`;
|
|
157
189
|
}
|
|
158
190
|
};
|
|
159
191
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dashboard.ts","../src/singleton.ts"],"sourcesContent":["import type { DashboardTheme, DashboardConfig } from \"./types\";\n\nexport class Dashboard {\n private iframe: HTMLIFrameElement;\n private wrapper: HTMLDivElement;\n private overlay: HTMLElement | null = null;\n private baseUrl: string;\n private ready = false;\n private queue: Record<string, unknown>[] = [];\n private messageHandler: (e: MessageEvent) => void;\n private initialTheme?: DashboardTheme;\n private initialLang?: string;\n private initialPath: string;\n private token?: string;\n private onReadyCallback?: () => void;\n private onSessionExpiredCallback?: () => void | Promise<void>;\n\n constructor(config: DashboardConfig) {\n this.baseUrl = config.baseUrl;\n this.initialTheme = config.theme;\n this.initialLang = config.lang;\n this.initialPath = config.path ?? \"/\";\n this.token = config.token;\n this.onReadyCallback = config.onReady;\n this.onSessionExpiredCallback = config.onSessionExpired;\n\n this.wrapper = document.createElement(\"div\");\n this.wrapper.style.position = \"relative\";\n this.wrapper.style.width = \"100%\";\n this.wrapper.style.height = \"100%\";\n\n this.iframe = document.createElement(\"iframe\");\n this.iframe.style.width = \"100%\";\n this.iframe.style.height = \"100%\";\n this.iframe.style.border = \"none\";\n this.iframe.title = \"Yuno Dashboard\";\n this.iframe.src = this.buildSrc();\n\n this.wrapper.appendChild(this.iframe);\n\n this.overlay = config.loading instanceof HTMLElement\n ? config.loading\n : this.createDefaultOverlay();\n this.overlay.style.position = \"absolute\";\n this.overlay.style.inset = \"0\";\n this.overlay.style.zIndex = \"1\";\n this.wrapper.appendChild(this.overlay);\n\n this.messageHandler = (e: MessageEvent) => {\n if (e.origin !== this.baseUrl) return;\n if (e.data?.type === \"yuno-dashboard:session-expired\") {\n try {\n const result = this.onSessionExpiredCallback?.();\n if (result && typeof (result as Promise<unknown>).catch === \"function\") {\n (result as Promise<unknown>).catch((err) =>\n // eslint-disable-next-line no-console\n console.warn(\"[yuno-dashboard-sdk] onSessionExpired async callback rejected\", err),\n );\n }\n } catch (err) {\n // eslint-disable-next-line no-console\n console.warn(\"[yuno-dashboard-sdk] onSessionExpired callback threw\", err);\n }\n return;\n }\n if (e.data?.action === \"ready\") {\n this.onReady();\n }\n if (e.data?.action === \"tokenApplied\") {\n this.onTokenApplied();\n }\n };\n window.addEventListener(\"message\", this.messageHandler);\n\n config.container.appendChild(this.wrapper);\n }\n\n setTheme(theme: DashboardTheme): void {\n if (theme.tokens || theme.typography) {\n const themePayload: Record<string, unknown> = {};\n if (theme.tokens) themePayload.colors = theme.tokens;\n if (theme.typography) themePayload.typography = theme.typography;\n this.post({ action: \"setTheme\", theme: themePayload });\n }\n if (theme.mode) {\n this.post({ action: \"setMode\", mode: theme.mode });\n }\n if (theme.styles !== undefined) {\n this.post({ action: \"setExternalStyles\", css: theme.styles });\n }\n }\n\n setLang(lang: string): void {\n this.post({ action: \"setLang\", lang });\n }\n\n setToken(token: string): void {\n this.token = token;\n this.post({ action: \"setToken\", token });\n }\n\n navigate(path: string): void {\n this.post({ action: \"navigate\", path });\n }\n\n destroy(): void {\n window.removeEventListener(\"message\", this.messageHandler);\n this.wrapper.remove();\n this.queue = [];\n this.ready = false;\n }\n\n private post(message: Record<string, unknown>): void {\n if (this.ready && this.iframe.contentWindow) {\n this.iframe.contentWindow.postMessage(message, this.baseUrl);\n } else {\n this.queue.push(message);\n }\n }\n\n private flush(): void {\n const pending = this.queue.splice(0);\n for (const message of pending) {\n if (this.iframe.contentWindow) {\n this.iframe.contentWindow.postMessage(message, this.baseUrl);\n }\n }\n }\n\n private onReady(): void {\n this.ready = true;\n if (this.token) {\n this.post({ action: \"setToken\", token: this.token });\n }\n if (this.initialTheme) {\n this.setTheme(this.initialTheme);\n }\n if (this.initialLang) {\n this.setLang(this.initialLang);\n }\n this.flush();\n }\n\n private onTokenApplied(): void {\n setTimeout(() => {\n if (this.initialPath !== \"/\") {\n this.post({ action: \"navigate\", path: this.initialPath });\n }\n this.hideOverlay();\n this.onReadyCallback?.();\n }, 1000);\n }\n\n private hideOverlay(): void {\n if (!this.overlay) return;\n this.overlay.style.transition = \"opacity 0.3s\";\n this.overlay.style.opacity = \"0\";\n setTimeout(() => this.overlay?.remove(), 300);\n }\n\n private createDefaultOverlay(): HTMLElement {\n const overlay = document.createElement(\"div\");\n overlay.style.background = \"#ffffff\";\n overlay.style.display = \"flex\";\n overlay.style.alignItems = \"center\";\n overlay.style.justifyContent = \"center\";\n\n const spinner = document.createElement(\"div\");\n spinner.style.width = \"32px\";\n spinner.style.height = \"32px\";\n spinner.style.border = \"3px solid #e0e0e0\";\n spinner.style.borderTopColor = \"#666\";\n spinner.style.borderRadius = \"50%\";\n spinner.style.animation = \"yuno-spin 0.8s linear infinite\";\n\n const style = document.createElement(\"style\");\n style.textContent = \"@keyframes yuno-spin { to { transform: rotate(360deg); } }\";\n\n overlay.appendChild(style);\n overlay.appendChild(spinner);\n return overlay;\n }\n\n private buildSrc(): string {\n const params = new URLSearchParams({\n embed: \"true\",\n theme: this.initialTheme?.mode ?? \"light\",\n lang: this.initialLang ?? \"en\",\n });\n return `${this.baseUrl}/?${params.toString()}`;\n }\n}\n","import { Dashboard } from \"./dashboard\";\nimport type { DashboardConfig } from \"./types\";\n\nlet instance: Dashboard | null = null;\n\nexport function initDashboard(config: DashboardConfig): Dashboard {\n if (instance) {\n instance.destroy();\n }\n instance = new Dashboard(config);\n return instance;\n}\n\nexport function getDashboard(): Dashboard | null {\n return instance;\n}\n\nexport function destroyDashboard(): void {\n if (instance) {\n instance.destroy();\n instance = null;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/dashboard.ts","../src/singleton.ts"],"sourcesContent":["import type { DashboardTheme, DashboardConfig, CheckoutPublishedEvent } from \"./types\";\n\nexport class Dashboard {\n private iframe: HTMLIFrameElement;\n private wrapper: HTMLDivElement;\n private overlay: HTMLElement | null = null;\n private baseUrl: string;\n private ready = false;\n private queue: Record<string, unknown>[] = [];\n private messageHandler: (e: MessageEvent) => void;\n private initialTheme?: DashboardTheme;\n private initialLang?: string;\n private initialPath: string;\n private initialTestMode?: boolean;\n private token?: string;\n private onReadyCallback?: () => void;\n private onSessionExpiredCallback?: () => void | Promise<void>;\n private onCheckoutPublishedCallback?: (event: CheckoutPublishedEvent) => void | Promise<void>;\n private autoHeight: boolean;\n\n constructor(config: DashboardConfig) {\n this.baseUrl = config.baseUrl;\n this.initialTheme = config.theme;\n this.initialLang = config.lang;\n this.initialPath = config.path ?? \"/\";\n this.initialTestMode = config.testMode;\n this.token = config.token;\n this.onReadyCallback = config.onReady;\n this.onSessionExpiredCallback = config.onSessionExpired;\n this.onCheckoutPublishedCallback = config.onCheckoutPublished;\n this.autoHeight = config.autoHeight ?? false;\n\n this.wrapper = document.createElement(\"div\");\n this.wrapper.style.position = \"relative\";\n this.wrapper.style.width = \"100%\";\n this.wrapper.style.height = \"100%\";\n\n this.iframe = document.createElement(\"iframe\");\n this.iframe.style.width = \"100%\";\n this.iframe.style.height = \"100%\";\n this.iframe.style.border = \"none\";\n this.iframe.title = \"Yuno Dashboard\";\n this.iframe.src = this.buildSrc();\n\n this.wrapper.appendChild(this.iframe);\n\n this.overlay = config.loading instanceof HTMLElement\n ? config.loading\n : this.createDefaultOverlay();\n this.overlay.style.position = \"absolute\";\n this.overlay.style.inset = \"0\";\n this.overlay.style.zIndex = \"1\";\n this.wrapper.appendChild(this.overlay);\n\n this.messageHandler = (e: MessageEvent) => {\n if (e.origin !== this.baseUrl) return;\n if (\n this.autoHeight &&\n e.data?.action === \"resize\" &&\n typeof e.data?.height === \"number\"\n ) {\n this.iframe.style.height = `${e.data.height}px`;\n this.wrapper.style.height = `${e.data.height}px`;\n return;\n }\n if (e.data?.type === \"yuno-dashboard:session-expired\") {\n try {\n const result = this.onSessionExpiredCallback?.();\n if (result && typeof (result as Promise<unknown>).catch === \"function\") {\n (result as Promise<unknown>).catch((err) =>\n // eslint-disable-next-line no-console\n console.warn(\"[yuno-dashboard-sdk] onSessionExpired async callback rejected\", err),\n );\n }\n } catch (err) {\n // eslint-disable-next-line no-console\n console.warn(\"[yuno-dashboard-sdk] onSessionExpired callback threw\", err);\n }\n return;\n }\n if (e.data?.type === \"yuno-dashboard:checkout-published\") {\n try {\n const result = this.onCheckoutPublishedCallback?.({\n source: e.data?.source,\n status: e.data?.status,\n payload: e.data?.payload,\n });\n if (result && typeof (result as Promise<unknown>).catch === \"function\") {\n (result as Promise<unknown>).catch((err) =>\n // eslint-disable-next-line no-console\n console.warn(\"[yuno-dashboard-sdk] onCheckoutPublished async callback rejected\", err),\n );\n }\n } catch (err) {\n // eslint-disable-next-line no-console\n console.warn(\"[yuno-dashboard-sdk] onCheckoutPublished callback threw\", err);\n }\n return;\n }\n if (e.data?.action === \"ready\") {\n this.onReady();\n }\n if (e.data?.action === \"tokenApplied\") {\n this.onTokenApplied();\n }\n };\n window.addEventListener(\"message\", this.messageHandler);\n\n config.container.appendChild(this.wrapper);\n }\n\n setTheme(theme: DashboardTheme): void {\n if (theme.tokens || theme.typography) {\n const themePayload: Record<string, unknown> = {};\n if (theme.tokens) themePayload.colors = theme.tokens;\n if (theme.typography) themePayload.typography = theme.typography;\n this.post({ action: \"setTheme\", theme: themePayload });\n }\n if (theme.mode) {\n this.post({ action: \"setMode\", mode: theme.mode });\n }\n if (theme.styles !== undefined) {\n this.post({ action: \"setExternalStyles\", css: theme.styles });\n }\n }\n\n setLang(lang: string): void {\n this.post({ action: \"setLang\", lang });\n }\n\n setToken(token: string): void {\n this.token = token;\n this.post({ action: \"setToken\", token });\n }\n\n navigate(path: string): void {\n this.post({ action: \"navigate\", path });\n }\n\n setTestMode(enabled: boolean): void {\n this.post({ action: \"setTestMode\", testMode: enabled });\n }\n\n destroy(): void {\n window.removeEventListener(\"message\", this.messageHandler);\n this.wrapper.remove();\n this.queue = [];\n this.ready = false;\n }\n\n private post(message: Record<string, unknown>): void {\n if (this.ready && this.iframe.contentWindow) {\n this.iframe.contentWindow.postMessage(message, this.baseUrl);\n } else {\n this.queue.push(message);\n }\n }\n\n private flush(): void {\n const pending = this.queue.splice(0);\n for (const message of pending) {\n if (this.iframe.contentWindow) {\n this.iframe.contentWindow.postMessage(message, this.baseUrl);\n }\n }\n }\n\n private onReady(): void {\n this.ready = true;\n if (this.token) {\n this.post({ action: \"setToken\", token: this.token });\n }\n if (this.initialTheme) {\n this.setTheme(this.initialTheme);\n }\n if (this.initialLang) {\n this.setLang(this.initialLang);\n }\n this.flush();\n }\n\n private onTokenApplied(): void {\n setTimeout(() => {\n this.hideOverlay();\n this.onReadyCallback?.();\n }, 1000);\n }\n\n private hideOverlay(): void {\n if (!this.overlay) return;\n this.overlay.style.transition = \"opacity 0.3s\";\n this.overlay.style.opacity = \"0\";\n setTimeout(() => this.overlay?.remove(), 300);\n }\n\n private createDefaultOverlay(): HTMLElement {\n const overlay = document.createElement(\"div\");\n overlay.style.background = \"#ffffff\";\n overlay.style.display = \"flex\";\n overlay.style.alignItems = \"center\";\n overlay.style.justifyContent = \"center\";\n\n const spinner = document.createElement(\"div\");\n spinner.style.width = \"32px\";\n spinner.style.height = \"32px\";\n spinner.style.border = \"3px solid #e0e0e0\";\n spinner.style.borderTopColor = \"#666\";\n spinner.style.borderRadius = \"50%\";\n spinner.style.animation = \"yuno-spin 0.8s linear infinite\";\n\n const style = document.createElement(\"style\");\n style.textContent = \"@keyframes yuno-spin { to { transform: rotate(360deg); } }\";\n\n overlay.appendChild(style);\n overlay.appendChild(spinner);\n return overlay;\n }\n\n private buildSrc(): string {\n const params = new URLSearchParams({\n embed: \"true\",\n theme: this.initialTheme?.mode ?? \"light\",\n lang: this.initialLang ?? \"en\",\n });\n if (this.initialTestMode !== undefined) {\n params.set(\"test\", String(this.initialTestMode));\n }\n const path = !this.initialPath || this.initialPath === \"/\" ? \"/\" : this.initialPath;\n return `${this.baseUrl}${path}?${params.toString()}`;\n }\n}\n","import { Dashboard } from \"./dashboard\";\nimport type { DashboardConfig } from \"./types\";\n\nlet instance: Dashboard | null = null;\n\nexport function initDashboard(config: DashboardConfig): Dashboard {\n if (instance) {\n instance.destroy();\n }\n instance = new Dashboard(config);\n return instance;\n}\n\nexport function getDashboard(): Dashboard | null {\n return instance;\n}\n\nexport function destroyDashboard(): void {\n if (instance) {\n instance.destroy();\n instance = null;\n }\n}\n"],"mappings":"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","names":[]}
|