@yuno-payments/dashboard-embed-sdk 1.1.1 → 1.3.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 +91 -29
- package/dist/index.d.ts +26 -7
- package/dist/index.js +66 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -70,10 +70,11 @@ 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. |
|
|
76
|
-
| `
|
|
77
|
+
| `events` | `DashboardEvents` | No | Business events the dashboard hands off to the host, grouped by MFE (domain) and action — e.g. `events.connections.created`, `events.checkout.published`. Providing a handler also signals that the host owns that action: the dashboard skips its own UI and lets the host decide what happens next. See [Embed events](#embed-events). |
|
|
77
78
|
| `loading` | `HTMLElement` | No | Custom loading overlay element. If omitted, a default spinner is shown |
|
|
78
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) |
|
|
79
80
|
|
|
@@ -83,6 +84,7 @@ destroyDashboard();
|
|
|
83
84
|
- **`setLang(lang)`** — Change display language
|
|
84
85
|
- **`setToken(token)`** — Update the auth token via PostMessage
|
|
85
86
|
- **`navigate(path)`** — Navigate to a dashboard route
|
|
87
|
+
- **`setTestMode(enabled)`** — Toggle test/sandbox mode at runtime via PostMessage. See [Test mode](#test-mode)
|
|
86
88
|
- **`destroy()`** — Remove iframe and clean up event listeners
|
|
87
89
|
|
|
88
90
|
### Types
|
|
@@ -131,15 +133,31 @@ interface DashboardTheme {
|
|
|
131
133
|
styles?: string; // Custom CSS injected into the dashboard
|
|
132
134
|
}
|
|
133
135
|
|
|
134
|
-
type
|
|
136
|
+
type EmbedEventStatus = "loading" | "success" | "error";
|
|
135
137
|
|
|
136
|
-
|
|
138
|
+
interface ConnectionCreatedPayload {
|
|
139
|
+
connectionCode: string;
|
|
140
|
+
providerId: string;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
interface ConnectionCreatedEvent {
|
|
144
|
+
status: EmbedEventStatus;
|
|
145
|
+
payload?: ConnectionCreatedPayload;
|
|
146
|
+
}
|
|
137
147
|
|
|
138
148
|
interface CheckoutPublishedEvent {
|
|
139
|
-
|
|
140
|
-
status: CheckoutPublishedStatus;
|
|
149
|
+
status: EmbedEventStatus;
|
|
141
150
|
payload?: unknown; // The configuration object that was published
|
|
142
151
|
}
|
|
152
|
+
|
|
153
|
+
interface DashboardEvents {
|
|
154
|
+
connections?: {
|
|
155
|
+
created?: (event: ConnectionCreatedEvent) => void | Promise<void>;
|
|
156
|
+
};
|
|
157
|
+
checkout?: {
|
|
158
|
+
published?: (event: CheckoutPublishedEvent) => void | Promise<void>;
|
|
159
|
+
};
|
|
160
|
+
}
|
|
143
161
|
```
|
|
144
162
|
|
|
145
163
|
## Session timeouts
|
|
@@ -169,40 +187,84 @@ const sdk = initDashboard({
|
|
|
169
187
|
})
|
|
170
188
|
```
|
|
171
189
|
|
|
172
|
-
##
|
|
190
|
+
## Embed events
|
|
173
191
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
192
|
+
The embedded dashboard hands business events off to the host through the
|
|
193
|
+
`events` config, grouped by MFE (`domain`) and `action`. Register a handler only
|
|
194
|
+
for what you care about:
|
|
177
195
|
|
|
178
196
|
```ts
|
|
179
197
|
const sdk = initDashboard({
|
|
180
198
|
baseUrl: "https://dashboard.y.uno",
|
|
181
199
|
container: document.getElementById("dashboard")!,
|
|
182
200
|
token: initialToken,
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
201
|
+
events: {
|
|
202
|
+
connections: {
|
|
203
|
+
created: (event) => {
|
|
204
|
+
// event.status is "loading" | "success" | "error"
|
|
205
|
+
// event.payload is { connectionCode, providerId } on success
|
|
206
|
+
if (event.status === "success") {
|
|
207
|
+
router.push(`/integrations/${event.payload!.connectionCode}/done`)
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
checkout: {
|
|
212
|
+
published: (event) => {
|
|
213
|
+
if (event.status === "success") {
|
|
214
|
+
console.log("Checkout published", event.payload)
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
},
|
|
198
218
|
},
|
|
199
219
|
})
|
|
200
220
|
```
|
|
201
221
|
|
|
202
|
-
The
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
222
|
+
### The host owns the moment
|
|
223
|
+
|
|
224
|
+
Providing a handler is also a signal. On init the SDK announces your registered
|
|
225
|
+
handlers to the dashboard, so the dashboard knows the host wants to own those
|
|
226
|
+
moments. For **connection creation**, this means: when a connection is created
|
|
227
|
+
in the embedded dashboard **and** you registered `events.connections.created`,
|
|
228
|
+
the dashboard does **not** show its own success screen or redirect — it hands
|
|
229
|
+
off to your handler and lets you route the user. If you do **not** register the
|
|
230
|
+
handler, the dashboard keeps its built-in success screen unchanged.
|
|
231
|
+
|
|
232
|
+
### Status lifecycle
|
|
233
|
+
|
|
234
|
+
Handlers fire once per state transition: first `status: "loading"` when the
|
|
235
|
+
action starts, then `"success"` or `"error"` once the dashboard's call resolves.
|
|
236
|
+
`event.payload` is only meaningful on `"success"`.
|
|
237
|
+
|
|
238
|
+
## Test mode
|
|
239
|
+
|
|
240
|
+
The dashboard can run in **test/sandbox** mode or **live** mode. Set it at mount time
|
|
241
|
+
via the `testMode` option, or toggle it at runtime via `setTestMode(enabled)`:
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
const sdk = initDashboard({
|
|
245
|
+
baseUrl: "https://dashboard.y.uno",
|
|
246
|
+
container: document.getElementById("dashboard")!,
|
|
247
|
+
token,
|
|
248
|
+
path: "/connections", // clean route — no query string
|
|
249
|
+
testMode: false, // mount in live mode
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// Later — flip to test mode without remounting
|
|
253
|
+
sdk.setTestMode(true);
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Do not pass test mode through `path`.** The SDK builds the iframe URL by appending its
|
|
257
|
+
own query string (`embed`, `theme`, `lang`, and `test` when `testMode` is set) to the route:
|
|
258
|
+
`${baseUrl}${path}?embed=true&…`. A `path` that already carries a query (e.g.
|
|
259
|
+
`"/connections?test=false"`) produces a malformed double-`?` URL that swallows `embed` and
|
|
260
|
+
breaks the embed (the dashboard never mounts). Always pass a query-free `path` and use the
|
|
261
|
+
`testMode` option / `setTestMode()` method instead.
|
|
262
|
+
|
|
263
|
+
**Host/iframe contract:** when `testMode` is provided, the SDK appends `test=<bool>` to the
|
|
264
|
+
initial iframe URL — the embedded dashboard reads it from its own URL on load. For the runtime
|
|
265
|
+
toggle, `setTestMode(enabled)` sends `postMessage({ action: "setTestMode", testMode })` (accepted
|
|
266
|
+
only from the configured `baseUrl` origin); the embedded dashboard must handle that action to
|
|
267
|
+
switch mode without a reload.
|
|
206
268
|
|
|
207
269
|
## Loading overlay
|
|
208
270
|
|
package/dist/index.d.ts
CHANGED
|
@@ -37,13 +37,27 @@ interface DashboardTheme {
|
|
|
37
37
|
mode?: "light" | "dark";
|
|
38
38
|
styles?: string;
|
|
39
39
|
}
|
|
40
|
-
type
|
|
41
|
-
|
|
40
|
+
type EmbedEventStatus = "loading" | "success" | "error";
|
|
41
|
+
interface ConnectionCreatedPayload {
|
|
42
|
+
connectionCode: string;
|
|
43
|
+
providerId: string;
|
|
44
|
+
}
|
|
45
|
+
interface ConnectionCreatedEvent {
|
|
46
|
+
status: EmbedEventStatus;
|
|
47
|
+
payload?: ConnectionCreatedPayload;
|
|
48
|
+
}
|
|
42
49
|
interface CheckoutPublishedEvent {
|
|
43
|
-
|
|
44
|
-
status: CheckoutPublishedStatus;
|
|
50
|
+
status: EmbedEventStatus;
|
|
45
51
|
payload?: unknown;
|
|
46
52
|
}
|
|
53
|
+
interface DashboardEvents {
|
|
54
|
+
connections?: {
|
|
55
|
+
created?: (event: ConnectionCreatedEvent) => void | Promise<void>;
|
|
56
|
+
};
|
|
57
|
+
checkout?: {
|
|
58
|
+
published?: (event: CheckoutPublishedEvent) => void | Promise<void>;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
47
61
|
interface DashboardConfig {
|
|
48
62
|
baseUrl: string;
|
|
49
63
|
container: HTMLElement;
|
|
@@ -51,9 +65,10 @@ interface DashboardConfig {
|
|
|
51
65
|
theme?: DashboardTheme;
|
|
52
66
|
lang?: string;
|
|
53
67
|
path?: string;
|
|
68
|
+
testMode?: boolean;
|
|
54
69
|
onReady?: () => void;
|
|
55
70
|
onSessionExpired?: () => void | Promise<void>;
|
|
56
|
-
|
|
71
|
+
events?: DashboardEvents;
|
|
57
72
|
loading?: HTMLElement;
|
|
58
73
|
autoHeight?: boolean;
|
|
59
74
|
}
|
|
@@ -69,17 +84,21 @@ declare class Dashboard {
|
|
|
69
84
|
private initialTheme?;
|
|
70
85
|
private initialLang?;
|
|
71
86
|
private initialPath;
|
|
87
|
+
private initialTestMode?;
|
|
72
88
|
private token?;
|
|
73
89
|
private onReadyCallback?;
|
|
74
90
|
private onSessionExpiredCallback?;
|
|
75
|
-
private
|
|
91
|
+
private events?;
|
|
76
92
|
private autoHeight;
|
|
77
93
|
constructor(config: DashboardConfig);
|
|
78
94
|
setTheme(theme: DashboardTheme): void;
|
|
79
95
|
setLang(lang: string): void;
|
|
80
96
|
setToken(token: string): void;
|
|
81
97
|
navigate(path: string): void;
|
|
98
|
+
setTestMode(enabled: boolean): void;
|
|
82
99
|
destroy(): void;
|
|
100
|
+
private invokeCallback;
|
|
101
|
+
private dispatchEmbedEvent;
|
|
83
102
|
private post;
|
|
84
103
|
private flush;
|
|
85
104
|
private onReady;
|
|
@@ -93,4 +112,4 @@ declare function initDashboard(config: DashboardConfig): Dashboard;
|
|
|
93
112
|
declare function getDashboard(): Dashboard | null;
|
|
94
113
|
declare function destroyDashboard(): void;
|
|
95
114
|
|
|
96
|
-
export { type CheckoutPublishedEvent, type
|
|
115
|
+
export { type CheckoutPublishedEvent, type ConnectionCreatedEvent, type ConnectionCreatedPayload, Dashboard, type DashboardConfig, type DashboardEvents, type DashboardTheme, type EmbedEventStatus, type ModeTokens, type ThemeColors, type ThemeTypography, destroyDashboard, getDashboard, initDashboard };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
// src/dashboard.ts
|
|
2
|
+
var EMBED_EVENT_MESSAGE_TYPE = "yuno-dashboard:embed-event";
|
|
3
|
+
var HOST_CAPABILITIES_MESSAGE_TYPE = "yuno-dashboard:host-capabilities";
|
|
4
|
+
function buildCapabilities(events) {
|
|
5
|
+
const capabilities = {};
|
|
6
|
+
if (!events) return capabilities;
|
|
7
|
+
const groups = events;
|
|
8
|
+
for (const domain of Object.keys(groups)) {
|
|
9
|
+
const group = groups[domain];
|
|
10
|
+
if (!group) continue;
|
|
11
|
+
for (const action of Object.keys(group)) {
|
|
12
|
+
if (typeof group[action] === "function") {
|
|
13
|
+
capabilities[domain] = capabilities[domain] ?? {};
|
|
14
|
+
capabilities[domain][action] = true;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return capabilities;
|
|
19
|
+
}
|
|
2
20
|
var Dashboard = class {
|
|
3
21
|
constructor(config) {
|
|
4
22
|
this.overlay = null;
|
|
@@ -8,10 +26,11 @@ var Dashboard = class {
|
|
|
8
26
|
this.initialTheme = config.theme;
|
|
9
27
|
this.initialLang = config.lang;
|
|
10
28
|
this.initialPath = config.path ?? "/";
|
|
29
|
+
this.initialTestMode = config.testMode;
|
|
11
30
|
this.token = config.token;
|
|
12
31
|
this.onReadyCallback = config.onReady;
|
|
13
32
|
this.onSessionExpiredCallback = config.onSessionExpired;
|
|
14
|
-
this.
|
|
33
|
+
this.events = config.events;
|
|
15
34
|
this.autoHeight = config.autoHeight ?? false;
|
|
16
35
|
this.wrapper = document.createElement("div");
|
|
17
36
|
this.wrapper.style.position = "relative";
|
|
@@ -37,39 +56,14 @@ var Dashboard = class {
|
|
|
37
56
|
return;
|
|
38
57
|
}
|
|
39
58
|
if (e.data?.type === "yuno-dashboard:session-expired") {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
(err) => (
|
|
45
|
-
// eslint-disable-next-line no-console
|
|
46
|
-
console.warn("[yuno-dashboard-sdk] onSessionExpired async callback rejected", err)
|
|
47
|
-
)
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
} catch (err) {
|
|
51
|
-
console.warn("[yuno-dashboard-sdk] onSessionExpired callback threw", err);
|
|
52
|
-
}
|
|
59
|
+
this.invokeCallback(
|
|
60
|
+
"onSessionExpired",
|
|
61
|
+
() => this.onSessionExpiredCallback?.()
|
|
62
|
+
);
|
|
53
63
|
return;
|
|
54
64
|
}
|
|
55
|
-
if (e.data?.type ===
|
|
56
|
-
|
|
57
|
-
const result = this.onCheckoutPublishedCallback?.({
|
|
58
|
-
source: e.data?.source,
|
|
59
|
-
status: e.data?.status,
|
|
60
|
-
payload: e.data?.payload
|
|
61
|
-
});
|
|
62
|
-
if (result && typeof result.catch === "function") {
|
|
63
|
-
result.catch(
|
|
64
|
-
(err) => (
|
|
65
|
-
// eslint-disable-next-line no-console
|
|
66
|
-
console.warn("[yuno-dashboard-sdk] onCheckoutPublished async callback rejected", err)
|
|
67
|
-
)
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
} catch (err) {
|
|
71
|
-
console.warn("[yuno-dashboard-sdk] onCheckoutPublished callback threw", err);
|
|
72
|
-
}
|
|
65
|
+
if (e.data?.type === EMBED_EVENT_MESSAGE_TYPE) {
|
|
66
|
+
this.dispatchEmbedEvent(e.data);
|
|
73
67
|
return;
|
|
74
68
|
}
|
|
75
69
|
if (e.data?.action === "ready") {
|
|
@@ -106,12 +100,45 @@ var Dashboard = class {
|
|
|
106
100
|
navigate(path) {
|
|
107
101
|
this.post({ action: "navigate", path });
|
|
108
102
|
}
|
|
103
|
+
setTestMode(enabled) {
|
|
104
|
+
this.post({ action: "setTestMode", testMode: enabled });
|
|
105
|
+
}
|
|
109
106
|
destroy() {
|
|
110
107
|
window.removeEventListener("message", this.messageHandler);
|
|
111
108
|
this.wrapper.remove();
|
|
112
109
|
this.queue = [];
|
|
113
110
|
this.ready = false;
|
|
114
111
|
}
|
|
112
|
+
// Runs a host callback, swallowing sync throws and async rejections so a
|
|
113
|
+
// misbehaving host handler can never break the SDK's message loop.
|
|
114
|
+
invokeCallback(name, run) {
|
|
115
|
+
try {
|
|
116
|
+
const result = run();
|
|
117
|
+
if (result && typeof result.catch === "function") {
|
|
118
|
+
result.catch(
|
|
119
|
+
(err) => (
|
|
120
|
+
// eslint-disable-next-line no-console
|
|
121
|
+
console.warn(`[yuno-dashboard-sdk] ${name} async callback rejected`, err)
|
|
122
|
+
)
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
} catch (err) {
|
|
126
|
+
console.warn(`[yuno-dashboard-sdk] ${name} callback threw`, err);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Routes an embed-event envelope to the host's events[domain][action] handler.
|
|
130
|
+
dispatchEmbedEvent(data) {
|
|
131
|
+
const domain = data?.domain;
|
|
132
|
+
const action = data?.action;
|
|
133
|
+
if (typeof domain !== "string" || typeof action !== "string") return;
|
|
134
|
+
const groups = this.events;
|
|
135
|
+
const handler = groups?.[domain]?.[action];
|
|
136
|
+
if (!handler) return;
|
|
137
|
+
this.invokeCallback(
|
|
138
|
+
`events.${domain}.${action}`,
|
|
139
|
+
() => handler({ status: data?.status, payload: data?.payload })
|
|
140
|
+
);
|
|
141
|
+
}
|
|
115
142
|
post(message) {
|
|
116
143
|
if (this.ready && this.iframe.contentWindow) {
|
|
117
144
|
this.iframe.contentWindow.postMessage(message, this.baseUrl);
|
|
@@ -129,6 +156,10 @@ var Dashboard = class {
|
|
|
129
156
|
}
|
|
130
157
|
onReady() {
|
|
131
158
|
this.ready = true;
|
|
159
|
+
const capabilities = buildCapabilities(this.events);
|
|
160
|
+
if (Object.keys(capabilities).length > 0) {
|
|
161
|
+
this.post({ type: HOST_CAPABILITIES_MESSAGE_TYPE, capabilities });
|
|
162
|
+
}
|
|
132
163
|
if (this.token) {
|
|
133
164
|
this.post({ action: "setToken", token: this.token });
|
|
134
165
|
}
|
|
@@ -177,6 +208,9 @@ var Dashboard = class {
|
|
|
177
208
|
theme: this.initialTheme?.mode ?? "light",
|
|
178
209
|
lang: this.initialLang ?? "en"
|
|
179
210
|
});
|
|
211
|
+
if (this.initialTestMode !== void 0) {
|
|
212
|
+
params.set("test", String(this.initialTestMode));
|
|
213
|
+
}
|
|
180
214
|
const path = !this.initialPath || this.initialPath === "/" ? "/" : this.initialPath;
|
|
181
215
|
return `${this.baseUrl}${path}?${params.toString()}`;
|
|
182
216
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 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.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 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 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":[]}
|
|
1
|
+
{"version":3,"sources":["../src/dashboard.ts","../src/singleton.ts"],"sourcesContent":["import type { DashboardTheme, DashboardConfig, DashboardEvents } from \"./types\";\n\nconst EMBED_EVENT_MESSAGE_TYPE = \"yuno-dashboard:embed-event\";\nconst HOST_CAPABILITIES_MESSAGE_TYPE = \"yuno-dashboard:host-capabilities\";\n\ntype EmbedEventHandler = (event: {\n status?: unknown;\n payload?: unknown;\n}) => void | Promise<void>;\n\n// Build the capability map the dashboard reads to decide which actions the\n// host owns: { connections: { created: true }, ... } for every provided handler.\nfunction buildCapabilities(\n events?: DashboardEvents,\n): Record<string, Record<string, boolean>> {\n const capabilities: Record<string, Record<string, boolean>> = {};\n if (!events) return capabilities;\n const groups = events as Record<string, Record<string, unknown> | undefined>;\n for (const domain of Object.keys(groups)) {\n const group = groups[domain];\n if (!group) continue;\n for (const action of Object.keys(group)) {\n if (typeof group[action] === \"function\") {\n capabilities[domain] = capabilities[domain] ?? {};\n capabilities[domain][action] = true;\n }\n }\n }\n return capabilities;\n}\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 events?: DashboardEvents;\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.events = config.events;\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 this.invokeCallback(\"onSessionExpired\", () =>\n this.onSessionExpiredCallback?.(),\n );\n return;\n }\n if (e.data?.type === EMBED_EVENT_MESSAGE_TYPE) {\n this.dispatchEmbedEvent(e.data);\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 // Runs a host callback, swallowing sync throws and async rejections so a\n // misbehaving host handler can never break the SDK's message loop.\n private invokeCallback(\n name: string,\n run: () => void | Promise<void> | undefined,\n ): void {\n try {\n const result = run();\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] ${name} async callback rejected`, err),\n );\n }\n } catch (err) {\n // eslint-disable-next-line no-console\n console.warn(`[yuno-dashboard-sdk] ${name} callback threw`, err);\n }\n }\n\n // Routes an embed-event envelope to the host's events[domain][action] handler.\n private dispatchEmbedEvent(data: Record<string, unknown>): void {\n const domain = data?.domain;\n const action = data?.action;\n if (typeof domain !== \"string\" || typeof action !== \"string\") return;\n\n const groups = this.events as\n | Record<string, Record<string, EmbedEventHandler | undefined> | undefined>\n | undefined;\n const handler = groups?.[domain]?.[action];\n if (!handler) return;\n\n this.invokeCallback(`events.${domain}.${action}`, () =>\n handler({ status: data?.status, payload: data?.payload }),\n );\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 const capabilities = buildCapabilities(this.events);\n if (Object.keys(capabilities).length > 0) {\n this.post({ type: HOST_CAPABILITIES_MESSAGE_TYPE, capabilities });\n }\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":[]}
|