@emplorium/sdk 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/LICENSE +27 -0
- package/README.md +82 -0
- package/dist/chunk-DYG422DG.mjs +434 -0
- package/dist/chunk-DYG422DG.mjs.map +1 -0
- package/dist/index.d.mts +157 -0
- package/dist/index.d.ts +157 -0
- package/dist/index.js +460 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +7 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react/index.d.mts +28 -0
- package/dist/react/index.d.ts +28 -0
- package/dist/react/index.js +550 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/index.mjs +85 -0
- package/dist/react/index.mjs.map +1 -0
- package/package.json +45 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Copyright (c) 2024-2026 Emplorium. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software and associated documentation files (the "Software") are the
|
|
4
|
+
proprietary property of Emplorium. The Software is licensed, not sold.
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted to any person or organization that has purchased
|
|
7
|
+
or otherwise been granted a valid license by Emplorium to use the Software
|
|
8
|
+
solely for the purpose of integrating with the Emplorium platform, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
1. The Software may not be copied, modified, merged, published, distributed,
|
|
12
|
+
sublicensed, or sold, in whole or in part, except as expressly permitted
|
|
13
|
+
by Emplorium in writing.
|
|
14
|
+
|
|
15
|
+
2. The Software may not be reverse-engineered, decompiled, or disassembled,
|
|
16
|
+
except to the extent that such activity is expressly permitted by
|
|
17
|
+
applicable law.
|
|
18
|
+
|
|
19
|
+
3. This license does not grant any rights to use Emplorium's name, logo, or
|
|
20
|
+
trademarks.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
25
|
+
EMPLORIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
26
|
+
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
27
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Emplorium SDK (single package)
|
|
2
|
+
|
|
3
|
+
This package ships the first cut of the browser-only SDK that wraps the existing iframe-based widget. It loads the production widget script, exposes a small programmatic API, and provides a thin React wrapper.
|
|
4
|
+
|
|
5
|
+
## Scope covered
|
|
6
|
+
|
|
7
|
+
- Reuse existing iframe widget (no new UI surface).
|
|
8
|
+
- Browser-only for v1.
|
|
9
|
+
- Visitor auth flow only (identification is proxied to the widget).
|
|
10
|
+
- PostMessage bridge with origin validation and event gating (wsInitiated, widgetSettingsLoaded, missedMessages, preview, launcher properties).
|
|
11
|
+
- Programmatic controls: `open`, `close`, `toggle`, `setUser` (proxied to iframe via `emplorium:identify`), event subscriptions, and readiness signals.
|
|
12
|
+
- React wrapper: `EmploriumProvider`, `useEmplorium`, `EmploriumWidget` (no DOM output, just lifecycle helpers).
|
|
13
|
+
|
|
14
|
+
## Usage (vanilla)
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { EmploriumClient } from "@emplorium/sdk";
|
|
18
|
+
|
|
19
|
+
const client = new EmploriumClient({ accountId: "ABC12" });
|
|
20
|
+
await client.init();
|
|
21
|
+
|
|
22
|
+
client.on("ready", () => console.log("widget ready"));
|
|
23
|
+
client.on("missedMessages", (count) => console.log("missed", count));
|
|
24
|
+
|
|
25
|
+
client.open();
|
|
26
|
+
client.setUser({ name: "Jane Doe", email: "jane@example.com" });
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage (React)
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { EmploriumProvider, EmploriumWidget, useEmplorium } from "@emplorium/sdk/react";
|
|
33
|
+
|
|
34
|
+
function App() {
|
|
35
|
+
return (
|
|
36
|
+
<EmploriumProvider config={{ accountId: "ABC12" }} autoOpen>
|
|
37
|
+
<EmploriumWidget />
|
|
38
|
+
{/* your app */}
|
|
39
|
+
</EmploriumProvider>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Configuration
|
|
45
|
+
|
|
46
|
+
- `accountId` (required): site/account identifier (same as snippet).
|
|
47
|
+
- `scriptUrl` (optional): override loader URL. Default: `https://widget-service.emplorium.io/acc-${accountId}/init.js`.
|
|
48
|
+
- Env overrides (evaluated at build time): `EMPLORIUM_WIDGET_SCRIPT_URL`, `NEXT_PUBLIC_EMPLORIUM_WIDGET_SCRIPT_URL`, `VITE_EMPLORIUM_WIDGET_SCRIPT_URL`.
|
|
49
|
+
- If only `IFRAME_WIDGET_URL` is provided (e.g., `https://widget-service-dev.emplorium.io`), SDK derives `IFRAME_WIDGET_URL/acc-${accountId}/init.js`.
|
|
50
|
+
- `widgetOrigin` (optional): overrides postMessage target origin. Derived from scriptUrl otherwise.
|
|
51
|
+
- `autoLoad` (default true): inject loader script during `init`.
|
|
52
|
+
- `autoOpen` (default false): open once ready.
|
|
53
|
+
- `allowedOrigins` (optional): additional allowed origins for postMessage (host + widget origin are always allowed).
|
|
54
|
+
|
|
55
|
+
## Notes / limitations
|
|
56
|
+
|
|
57
|
+
- The SDK reuses the current iframe widget. Message, typing, and other chat events are limited to what the existing widget emits today (e.g., `wsInitiated`, `widgetSettingsLoaded`, `missedMessages`, preview/launcher updates). Deeper chat events will require iframe changes.
|
|
58
|
+
- `setUser` forwards visitor identity via `emplorium:identify` to the chat iframe; it will queue until the iframe is ready.
|
|
59
|
+
- No SSR support for v1; calls must run in the browser.
|
|
60
|
+
|
|
61
|
+
## Build & test locally
|
|
62
|
+
|
|
63
|
+
- Build: `pnpm --filter @emplorium/sdk build`
|
|
64
|
+
- Dev/watch: `pnpm --filter @emplorium/sdk dev`
|
|
65
|
+
- Consume locally in this repo: `pnpm add @emplorium/sdk@file:./sdk`
|
|
66
|
+
- To test against dev widget service:
|
|
67
|
+
- Set `VITE_EMPLORIUM_WIDGET_SCRIPT_URL=https://widget-service-dev.emplorium.io/widget-script/ACC123` (or `VITE_IFRAME_WIDGET_URL=https://widget-service-dev.emplorium.io` to derive the path).
|
|
68
|
+
- Rebuild the SDK so env is inlined.
|
|
69
|
+
- Example React usage:
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import { EmploriumProvider, EmploriumWidget } from "@emplorium/sdk/react";
|
|
73
|
+
|
|
74
|
+
export function App() {
|
|
75
|
+
return (
|
|
76
|
+
<EmploriumProvider config={{ accountId: "ACC123" }}>
|
|
77
|
+
<EmploriumWidget autoOpen />
|
|
78
|
+
{/* rest of your app */}
|
|
79
|
+
</EmploriumProvider>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
// src/eventBus.ts
|
|
2
|
+
var EventBus = class {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
5
|
+
}
|
|
6
|
+
on(event, listener) {
|
|
7
|
+
var _a;
|
|
8
|
+
const existing = (_a = this.listeners.get(event)) != null ? _a : /* @__PURE__ */ new Set();
|
|
9
|
+
existing.add(listener);
|
|
10
|
+
this.listeners.set(event, existing);
|
|
11
|
+
return () => this.off(event, listener);
|
|
12
|
+
}
|
|
13
|
+
off(event, listener) {
|
|
14
|
+
const existing = this.listeners.get(event);
|
|
15
|
+
if (!existing)
|
|
16
|
+
return;
|
|
17
|
+
existing.delete(listener);
|
|
18
|
+
if (existing.size === 0) {
|
|
19
|
+
this.listeners.delete(event);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
emit(event, payload) {
|
|
23
|
+
const existing = this.listeners.get(event);
|
|
24
|
+
if (!existing)
|
|
25
|
+
return;
|
|
26
|
+
existing.forEach((listener) => {
|
|
27
|
+
try {
|
|
28
|
+
listener(payload);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error("[Emplorium SDK] Event listener failed:", error);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
clear() {
|
|
35
|
+
this.listeners.clear();
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// src/logger.ts
|
|
40
|
+
var createLogger = (logger) => {
|
|
41
|
+
const fallback = {
|
|
42
|
+
debug: () => void 0,
|
|
43
|
+
info: () => void 0,
|
|
44
|
+
warn: () => void 0,
|
|
45
|
+
error: () => void 0
|
|
46
|
+
};
|
|
47
|
+
if (!logger) {
|
|
48
|
+
return fallback;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
debug: logger.debug || fallback.debug,
|
|
52
|
+
info: logger.info || fallback.info,
|
|
53
|
+
warn: logger.warn || fallback.warn,
|
|
54
|
+
error: logger.error || fallback.error
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/iframeLoader.ts
|
|
59
|
+
var LOADER_SCRIPT_ID = "emplorium-sdk-loader-script";
|
|
60
|
+
var loadPromise = null;
|
|
61
|
+
var loadedScriptUrl = null;
|
|
62
|
+
var getEnvWidgetScriptUrl = (accountId) => {
|
|
63
|
+
const env = typeof process !== "undefined" && process.env;
|
|
64
|
+
if (!env) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const direct = env.EMPLORIUM_WIDGET_SCRIPT_URL || env.NEXT_PUBLIC_EMPLORIUM_WIDGET_SCRIPT_URL || env.VITE_EMPLORIUM_WIDGET_SCRIPT_URL;
|
|
68
|
+
if (direct)
|
|
69
|
+
return direct;
|
|
70
|
+
const iframeBase = env.IFRAME_WIDGET_URL || env.NEXT_PUBLIC_IFRAME_WIDGET_URL || env.VITE_IFRAME_WIDGET_URL;
|
|
71
|
+
if (iframeBase) {
|
|
72
|
+
const base = iframeBase.replace(/\/+$/, "");
|
|
73
|
+
return `${base}/acc-${accountId}/init.js`;
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
};
|
|
77
|
+
var buildScriptUrl = (accountId, override) => {
|
|
78
|
+
if (override)
|
|
79
|
+
return override;
|
|
80
|
+
const fromEnv = getEnvWidgetScriptUrl(accountId);
|
|
81
|
+
if (fromEnv)
|
|
82
|
+
return fromEnv;
|
|
83
|
+
const defaultBase = "https://widget-service.emplorium.io";
|
|
84
|
+
return `${defaultBase.replace(/\/+$/, "")}/acc-${accountId}/init.js`;
|
|
85
|
+
};
|
|
86
|
+
var ensureLoaderScript = (options) => {
|
|
87
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
88
|
+
return Promise.reject(new Error("Emplorium SDK is browser-only for v1"));
|
|
89
|
+
}
|
|
90
|
+
const logger = createLogger(options.logger);
|
|
91
|
+
const targetUrl = buildScriptUrl(options.accountId, options.scriptUrl);
|
|
92
|
+
if (loadPromise && loadedScriptUrl === targetUrl) {
|
|
93
|
+
return loadPromise;
|
|
94
|
+
}
|
|
95
|
+
const existing = document.querySelector(`script#${LOADER_SCRIPT_ID}`) || document.querySelector('script[data-emplorium-loader="true"]');
|
|
96
|
+
if (existing) {
|
|
97
|
+
loadedScriptUrl = existing.src || targetUrl;
|
|
98
|
+
const alreadyLoaded = existing.dataset.loaded === "true" || existing.getAttribute("data-loaded") === "true" || existing.readyState === "complete";
|
|
99
|
+
loadPromise = alreadyLoaded ? Promise.resolve() : new Promise((resolve, reject) => {
|
|
100
|
+
existing.addEventListener("load", () => resolve(), { once: true });
|
|
101
|
+
existing.addEventListener(
|
|
102
|
+
"error",
|
|
103
|
+
() => reject(new Error("Emplorium loader script failed to load")),
|
|
104
|
+
{ once: true }
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
existing.dataset.loaded = alreadyLoaded ? "true" : existing.dataset.loaded || "false";
|
|
108
|
+
return loadPromise;
|
|
109
|
+
}
|
|
110
|
+
loadPromise = new Promise((resolve, reject) => {
|
|
111
|
+
const script = document.createElement("script");
|
|
112
|
+
script.id = LOADER_SCRIPT_ID;
|
|
113
|
+
script.src = targetUrl;
|
|
114
|
+
script.async = true;
|
|
115
|
+
script.dataset.emploriumLoader = "true";
|
|
116
|
+
script.dataset.loaded = "false";
|
|
117
|
+
if (options.scriptAttributes) {
|
|
118
|
+
Object.entries(options.scriptAttributes).forEach(([key, value]) => {
|
|
119
|
+
script.setAttribute(key, value);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
script.onload = () => {
|
|
123
|
+
script.dataset.loaded = "true";
|
|
124
|
+
loadedScriptUrl = targetUrl;
|
|
125
|
+
logger.info("[Emplorium SDK] Loader script ready");
|
|
126
|
+
resolve();
|
|
127
|
+
};
|
|
128
|
+
script.onerror = () => {
|
|
129
|
+
logger.error("[Emplorium SDK] Failed to load loader script", targetUrl);
|
|
130
|
+
reject(new Error("Failed to load Emplorium loader script"));
|
|
131
|
+
};
|
|
132
|
+
document.head.appendChild(script);
|
|
133
|
+
});
|
|
134
|
+
return loadPromise;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// src/postMessageBridge.ts
|
|
138
|
+
var CHAT_IFRAME_ID = "emplorium-iframe-chat";
|
|
139
|
+
var PostMessageBridge = class {
|
|
140
|
+
constructor(options) {
|
|
141
|
+
this.options = options;
|
|
142
|
+
this.started = false;
|
|
143
|
+
this.pendingIdentify = [];
|
|
144
|
+
this.handleMessage = (event) => {
|
|
145
|
+
if (!event || !this.validateOrigin(event.origin)) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const data = event.data;
|
|
149
|
+
if (!data || typeof data !== "object" || typeof data.type !== "string") {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
switch (data.type) {
|
|
153
|
+
case "widgetSettingsLoaded":
|
|
154
|
+
this.emitter.emit("widgetSettingsLoaded", Boolean(data.value));
|
|
155
|
+
this.flushPendingIdentify();
|
|
156
|
+
break;
|
|
157
|
+
case "wsInitiated":
|
|
158
|
+
this.emitter.emit("wsInitiated", Boolean(data.value));
|
|
159
|
+
this.flushPendingIdentify();
|
|
160
|
+
break;
|
|
161
|
+
case "missedMessages":
|
|
162
|
+
if (typeof data.value === "number") {
|
|
163
|
+
this.emitter.emit("missedMessages", data.value);
|
|
164
|
+
}
|
|
165
|
+
break;
|
|
166
|
+
case "launcherProperties":
|
|
167
|
+
this.emitter.emit("launcherProperties", data.value || {});
|
|
168
|
+
break;
|
|
169
|
+
case "openPreviewIframe":
|
|
170
|
+
this.emitter.emit("previewOpen", {
|
|
171
|
+
url: data.url,
|
|
172
|
+
fileType: data.fileType
|
|
173
|
+
});
|
|
174
|
+
break;
|
|
175
|
+
default:
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
this.logger = createLogger(options.config.logger);
|
|
180
|
+
const hostOrigin = typeof window !== "undefined" && window.location.origin ? window.location.origin : "*";
|
|
181
|
+
const derivedWidgetOrigin = this.deriveWidgetOrigin(options.config);
|
|
182
|
+
this.widgetOrigin = derivedWidgetOrigin || hostOrigin;
|
|
183
|
+
this.emitter = options.emitter;
|
|
184
|
+
this.allowedOrigins = /* @__PURE__ */ new Set([
|
|
185
|
+
hostOrigin,
|
|
186
|
+
this.widgetOrigin,
|
|
187
|
+
...options.config.allowedOrigins || []
|
|
188
|
+
]);
|
|
189
|
+
}
|
|
190
|
+
start() {
|
|
191
|
+
if (this.started || typeof window === "undefined")
|
|
192
|
+
return;
|
|
193
|
+
window.addEventListener("message", this.handleMessage);
|
|
194
|
+
this.started = true;
|
|
195
|
+
}
|
|
196
|
+
stop() {
|
|
197
|
+
if (!this.started || typeof window === "undefined")
|
|
198
|
+
return;
|
|
199
|
+
window.removeEventListener("message", this.handleMessage);
|
|
200
|
+
this.started = false;
|
|
201
|
+
}
|
|
202
|
+
sendToggle(open) {
|
|
203
|
+
if (typeof window === "undefined")
|
|
204
|
+
return;
|
|
205
|
+
const targetOrigin = window.location.origin || "*";
|
|
206
|
+
window.postMessage({ type: "toggle", show: open }, targetOrigin);
|
|
207
|
+
this.emitter.emit("toggle", { open });
|
|
208
|
+
this.emitter.emit(open ? "open" : "close", void 0);
|
|
209
|
+
}
|
|
210
|
+
sendIdentify(user) {
|
|
211
|
+
if (!user || typeof user !== "object")
|
|
212
|
+
return;
|
|
213
|
+
const chatWindow = this.getChatWindow();
|
|
214
|
+
if (!chatWindow) {
|
|
215
|
+
this.pendingIdentify.push(user);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
chatWindow.postMessage({ type: "emplorium:identify", payload: user }, this.widgetOrigin);
|
|
219
|
+
}
|
|
220
|
+
sendVisibility(enabled) {
|
|
221
|
+
const chatWindow = this.getChatWindow();
|
|
222
|
+
if (!chatWindow)
|
|
223
|
+
return;
|
|
224
|
+
chatWindow.postMessage(
|
|
225
|
+
{ type: "emplorium:visibility", payload: { enabled } },
|
|
226
|
+
this.widgetOrigin
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
flushPendingIdentify() {
|
|
230
|
+
if (this.pendingIdentify.length === 0)
|
|
231
|
+
return;
|
|
232
|
+
const chatWindow = this.getChatWindow();
|
|
233
|
+
if (!chatWindow)
|
|
234
|
+
return;
|
|
235
|
+
while (this.pendingIdentify.length > 0) {
|
|
236
|
+
const user = this.pendingIdentify.shift();
|
|
237
|
+
if (user) {
|
|
238
|
+
chatWindow.postMessage({ type: "emplorium:identify", payload: user }, this.widgetOrigin);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
deriveWidgetOrigin(config) {
|
|
243
|
+
if (config.widgetOrigin)
|
|
244
|
+
return config.widgetOrigin;
|
|
245
|
+
if (config.scriptUrl) {
|
|
246
|
+
try {
|
|
247
|
+
return new URL(config.scriptUrl).origin;
|
|
248
|
+
} catch {
|
|
249
|
+
this.logger.warn("[Emplorium SDK] Unable to parse widget origin from scriptUrl");
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return "https://widget.emplorium.io";
|
|
253
|
+
}
|
|
254
|
+
validateOrigin(origin) {
|
|
255
|
+
return !!origin && origin !== "null" && this.allowedOrigins.has(origin);
|
|
256
|
+
}
|
|
257
|
+
getChatWindow() {
|
|
258
|
+
if (typeof document === "undefined")
|
|
259
|
+
return null;
|
|
260
|
+
const iframe = document.getElementById(CHAT_IFRAME_ID);
|
|
261
|
+
if (iframe && iframe.contentWindow) {
|
|
262
|
+
return iframe.contentWindow;
|
|
263
|
+
}
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// src/client.ts
|
|
269
|
+
var DEFAULT_STATE = {
|
|
270
|
+
initialized: false,
|
|
271
|
+
loaderLoaded: false,
|
|
272
|
+
widgetReady: false,
|
|
273
|
+
visibility: "unknown"
|
|
274
|
+
};
|
|
275
|
+
var EmploriumClient = class {
|
|
276
|
+
constructor(config) {
|
|
277
|
+
this.config = config;
|
|
278
|
+
this.emitter = new EventBus();
|
|
279
|
+
this.state = { ...DEFAULT_STATE };
|
|
280
|
+
this.initPromise = null;
|
|
281
|
+
this.readyPromise = null;
|
|
282
|
+
this.resolveReady = null;
|
|
283
|
+
this.init = () => {
|
|
284
|
+
if (this.initPromise) {
|
|
285
|
+
return this.initPromise;
|
|
286
|
+
}
|
|
287
|
+
if (!this.isEnabled) {
|
|
288
|
+
this.logger.debug("[Emplorium SDK] Widget disabled via config");
|
|
289
|
+
this.initPromise = Promise.resolve();
|
|
290
|
+
return this.initPromise;
|
|
291
|
+
}
|
|
292
|
+
this.state.initialized = true;
|
|
293
|
+
this.bridge.start();
|
|
294
|
+
this.readyPromise = new Promise((resolve) => {
|
|
295
|
+
this.resolveReady = resolve;
|
|
296
|
+
});
|
|
297
|
+
this.bindBridgeEvents();
|
|
298
|
+
this.initPromise = (async () => {
|
|
299
|
+
if (this.config.autoLoad !== false) {
|
|
300
|
+
await ensureLoaderScript({
|
|
301
|
+
accountId: this.config.accountId,
|
|
302
|
+
scriptUrl: this.config.scriptUrl,
|
|
303
|
+
scriptAttributes: this.config.scriptAttributes,
|
|
304
|
+
logger: this.config.logger,
|
|
305
|
+
user: this.config.user
|
|
306
|
+
// Pass user identity to loader
|
|
307
|
+
});
|
|
308
|
+
this.state.loaderLoaded = true;
|
|
309
|
+
this.logger.debug("[Emplorium SDK] Loader script injected");
|
|
310
|
+
if (this.config.user) {
|
|
311
|
+
const { firstName, lastName, email } = this.config.user;
|
|
312
|
+
if (firstName || lastName || email) {
|
|
313
|
+
this.setUser({ firstName, lastName, email });
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (this.config.autoOpen) {
|
|
318
|
+
this.open();
|
|
319
|
+
}
|
|
320
|
+
})().catch((error) => {
|
|
321
|
+
this.emitter.emit("error", error);
|
|
322
|
+
throw error;
|
|
323
|
+
});
|
|
324
|
+
return this.initPromise;
|
|
325
|
+
};
|
|
326
|
+
this.on = (event, listener) => {
|
|
327
|
+
return this.emitter.on(event, listener);
|
|
328
|
+
};
|
|
329
|
+
this.off = (event, listener) => {
|
|
330
|
+
return this.emitter.off(event, listener);
|
|
331
|
+
};
|
|
332
|
+
this.ready = async () => {
|
|
333
|
+
await this.init();
|
|
334
|
+
return this.readyPromise || Promise.resolve();
|
|
335
|
+
};
|
|
336
|
+
this.open = () => {
|
|
337
|
+
this.bridge.sendToggle(true);
|
|
338
|
+
this.state.visibility = "open";
|
|
339
|
+
};
|
|
340
|
+
this.close = () => {
|
|
341
|
+
this.bridge.sendToggle(false);
|
|
342
|
+
this.state.visibility = "closed";
|
|
343
|
+
};
|
|
344
|
+
this.toggle = () => {
|
|
345
|
+
const nextOpen = this.state.visibility !== "open";
|
|
346
|
+
this.bridge.sendToggle(nextOpen);
|
|
347
|
+
this.state.visibility = nextOpen ? "open" : "closed";
|
|
348
|
+
};
|
|
349
|
+
this.setUser = (user) => {
|
|
350
|
+
if (!this.isEnabled)
|
|
351
|
+
return;
|
|
352
|
+
this.bridge.sendIdentify(user);
|
|
353
|
+
};
|
|
354
|
+
/**
|
|
355
|
+
* Enable the widget (show it). Only has effect if widget was previously disabled.
|
|
356
|
+
*/
|
|
357
|
+
this.enable = () => {
|
|
358
|
+
if (this.isEnabled)
|
|
359
|
+
return;
|
|
360
|
+
this.isEnabled = true;
|
|
361
|
+
this.bridge.sendVisibility(true);
|
|
362
|
+
};
|
|
363
|
+
/**
|
|
364
|
+
* Disable the widget (hide it completely).
|
|
365
|
+
*/
|
|
366
|
+
this.disable = () => {
|
|
367
|
+
if (!this.isEnabled)
|
|
368
|
+
return;
|
|
369
|
+
this.isEnabled = false;
|
|
370
|
+
this.bridge.sendVisibility(false);
|
|
371
|
+
this.state.visibility = "closed";
|
|
372
|
+
};
|
|
373
|
+
/**
|
|
374
|
+
* Check if the widget is currently enabled.
|
|
375
|
+
*/
|
|
376
|
+
this.isWidgetEnabled = () => {
|
|
377
|
+
return this.isEnabled;
|
|
378
|
+
};
|
|
379
|
+
this.getState = () => {
|
|
380
|
+
return { ...this.state };
|
|
381
|
+
};
|
|
382
|
+
this.destroy = () => {
|
|
383
|
+
this.bridge.stop();
|
|
384
|
+
this.emitter.clear();
|
|
385
|
+
this.state = { ...DEFAULT_STATE };
|
|
386
|
+
this.initPromise = null;
|
|
387
|
+
this.readyPromise = null;
|
|
388
|
+
this.resolveReady = null;
|
|
389
|
+
};
|
|
390
|
+
this.logger = createLogger(config.logger);
|
|
391
|
+
this.bridge = new PostMessageBridge({ config, emitter: this.emitter });
|
|
392
|
+
this.isEnabled = config.enabled !== false;
|
|
393
|
+
this.bindApiMethods();
|
|
394
|
+
}
|
|
395
|
+
bindApiMethods() {
|
|
396
|
+
this.init = this.init.bind(this);
|
|
397
|
+
this.on = this.on.bind(this);
|
|
398
|
+
this.off = this.off.bind(this);
|
|
399
|
+
this.ready = this.ready.bind(this);
|
|
400
|
+
this.open = this.open.bind(this);
|
|
401
|
+
this.close = this.close.bind(this);
|
|
402
|
+
this.toggle = this.toggle.bind(this);
|
|
403
|
+
this.setUser = this.setUser.bind(this);
|
|
404
|
+
this.enable = this.enable.bind(this);
|
|
405
|
+
this.disable = this.disable.bind(this);
|
|
406
|
+
this.isWidgetEnabled = this.isWidgetEnabled.bind(this);
|
|
407
|
+
this.getState = this.getState.bind(this);
|
|
408
|
+
this.destroy = this.destroy.bind(this);
|
|
409
|
+
}
|
|
410
|
+
setVisibility(state) {
|
|
411
|
+
this.state.visibility = state;
|
|
412
|
+
}
|
|
413
|
+
bindBridgeEvents() {
|
|
414
|
+
this.emitter.on("toggle", ({ open }) => this.setVisibility(open ? "open" : "closed"));
|
|
415
|
+
this.emitter.on("open", () => this.setVisibility("open"));
|
|
416
|
+
this.emitter.on("close", () => this.setVisibility("closed"));
|
|
417
|
+
const markReady = () => {
|
|
418
|
+
var _a;
|
|
419
|
+
if (this.state.widgetReady)
|
|
420
|
+
return;
|
|
421
|
+
this.state.widgetReady = true;
|
|
422
|
+
(_a = this.resolveReady) == null ? void 0 : _a.call(this);
|
|
423
|
+
this.resolveReady = null;
|
|
424
|
+
this.emitter.emit("ready", void 0);
|
|
425
|
+
};
|
|
426
|
+
this.emitter.on("wsInitiated", markReady);
|
|
427
|
+
this.emitter.on("widgetSettingsLoaded", markReady);
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
export {
|
|
432
|
+
EmploriumClient
|
|
433
|
+
};
|
|
434
|
+
//# sourceMappingURL=chunk-DYG422DG.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/eventBus.ts","../src/logger.ts","../src/iframeLoader.ts","../src/postMessageBridge.ts","../src/client.ts"],"sourcesContent":["type Listener<T> = (payload: T) => void;\n\nexport class EventBus<Events extends Record<string, unknown>> {\n private listeners: Map<keyof Events, Set<Listener<Events[keyof Events]>>> = new Map();\n\n on<K extends keyof Events>(event: K, listener: Listener<Events[K]>): () => void {\n const existing = this.listeners.get(event) ?? new Set();\n existing.add(listener as Listener<Events[keyof Events]>);\n this.listeners.set(event, existing);\n\n return () => this.off(event, listener);\n }\n\n off<K extends keyof Events>(event: K, listener: Listener<Events[K]>): void {\n const existing = this.listeners.get(event);\n if (!existing) return;\n existing.delete(listener as Listener<Events[keyof Events]>);\n if (existing.size === 0) {\n this.listeners.delete(event);\n }\n }\n\n emit<K extends keyof Events>(event: K, payload: Events[K]): void {\n const existing = this.listeners.get(event);\n if (!existing) return;\n existing.forEach((listener) => {\n try {\n (listener as Listener<Events[keyof Events]>)(payload);\n } catch (error) {\n // Avoid breaking other listeners\n console.error(\"[Emplorium SDK] Event listener failed:\", error);\n }\n });\n }\n\n clear(): void {\n this.listeners.clear();\n }\n}\n","import { Logger } from \"./types\";\n\nexport const createLogger = (logger?: Logger): Required<Logger> => {\n const fallback: Required<Logger> = {\n debug: () => undefined,\n info: () => undefined,\n warn: () => undefined,\n error: () => undefined,\n };\n\n if (!logger) {\n return fallback;\n }\n\n return {\n debug: logger.debug || fallback.debug,\n info: logger.info || fallback.info,\n warn: logger.warn || fallback.warn,\n error: logger.error || fallback.error,\n };\n};\n","import { createLogger } from \"./logger\";\nimport { EmploriumConfig, EmploriumVisitorIdentity } from \"./types\";\n\ntype LoaderOptions = Pick<\n EmploriumConfig,\n \"accountId\" | \"scriptUrl\" | \"scriptAttributes\" | \"logger\"\n> & {\n user?: EmploriumVisitorIdentity;\n};\n\nconst LOADER_SCRIPT_ID = \"emplorium-sdk-loader-script\";\nlet loadPromise: Promise<void> | null = null;\nlet loadedScriptUrl: string | null = null;\n\nconst getEnvWidgetScriptUrl = (accountId: string): string | null => {\n const env = typeof process !== \"undefined\" && (process.env as Record<string, string | undefined>);\n if (!env) {\n return null;\n }\n\n const direct =\n env.EMPLORIUM_WIDGET_SCRIPT_URL ||\n env.NEXT_PUBLIC_EMPLORIUM_WIDGET_SCRIPT_URL ||\n env.VITE_EMPLORIUM_WIDGET_SCRIPT_URL;\n if (direct) return direct;\n\n const iframeBase =\n env.IFRAME_WIDGET_URL || env.NEXT_PUBLIC_IFRAME_WIDGET_URL || env.VITE_IFRAME_WIDGET_URL;\n if (iframeBase) {\n const base = iframeBase.replace(/\\/+$/, \"\");\n return `${base}/acc-${accountId}/init.js`;\n }\n\n return null;\n};\n\nexport const buildScriptUrl = (accountId: string, override?: string): string => {\n if (override) return override;\n\n const fromEnv = getEnvWidgetScriptUrl(accountId);\n if (fromEnv) return fromEnv;\n\n const defaultBase = \"https://widget-service.emplorium.io\";\n return `${defaultBase.replace(/\\/+$/, \"\")}/acc-${accountId}/init.js`;\n};\n\nexport const ensureLoaderScript = (options: LoaderOptions): Promise<void> => {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return Promise.reject(new Error(\"Emplorium SDK is browser-only for v1\"));\n }\n\n const logger = createLogger(options.logger);\n const targetUrl = buildScriptUrl(options.accountId, options.scriptUrl);\n\n // If a loader already exists with the same URL, reuse it\n if (loadPromise && loadedScriptUrl === targetUrl) {\n return loadPromise;\n }\n\n // If the host page already injected the loader (e.g., via snippet), reuse it\n const existing =\n document.querySelector<HTMLScriptElement>(`script#${LOADER_SCRIPT_ID}`) ||\n document.querySelector<HTMLScriptElement>('script[data-emplorium-loader=\"true\"]');\n\n if (existing) {\n loadedScriptUrl = existing.src || targetUrl;\n const alreadyLoaded =\n existing.dataset.loaded === \"true\" ||\n existing.getAttribute(\"data-loaded\") === \"true\" ||\n (existing as unknown as { readyState?: string }).readyState === \"complete\";\n\n loadPromise = alreadyLoaded\n ? Promise.resolve()\n : new Promise<void>((resolve, reject) => {\n existing.addEventListener(\"load\", () => resolve(), { once: true });\n existing.addEventListener(\n \"error\",\n () => reject(new Error(\"Emplorium loader script failed to load\")),\n { once: true }\n );\n });\n\n existing.dataset.loaded = alreadyLoaded ? \"true\" : existing.dataset.loaded || \"false\";\n return loadPromise;\n }\n\n loadPromise = new Promise<void>((resolve, reject) => {\n const script = document.createElement(\"script\");\n script.id = LOADER_SCRIPT_ID;\n script.src = targetUrl;\n script.async = true;\n script.dataset.emploriumLoader = \"true\";\n script.dataset.loaded = \"false\";\n\n if (options.scriptAttributes) {\n Object.entries(options.scriptAttributes).forEach(([key, value]) => {\n script.setAttribute(key, value);\n });\n }\n\n script.onload = () => {\n script.dataset.loaded = \"true\";\n loadedScriptUrl = targetUrl;\n logger.info(\"[Emplorium SDK] Loader script ready\");\n resolve();\n };\n script.onerror = () => {\n logger.error(\"[Emplorium SDK] Failed to load loader script\", targetUrl);\n reject(new Error(\"Failed to load Emplorium loader script\"));\n };\n\n document.head.appendChild(script);\n });\n\n return loadPromise;\n};\n","import { EventBus } from \"./eventBus\";\nimport { createLogger } from \"./logger\";\nimport { EmploriumConfig, EmploriumEventMap, EmploriumUser } from \"./types\";\n\ntype BridgeOptions = {\n config: EmploriumConfig;\n emitter: EventBus<EmploriumEventMap>;\n};\n\nconst CHAT_IFRAME_ID = \"emplorium-iframe-chat\";\n\nexport class PostMessageBridge {\n private readonly allowedOrigins: Set<string>;\n private readonly widgetOrigin: string;\n private readonly emitter: EventBus<EmploriumEventMap>;\n private readonly logger;\n private started = false;\n private pendingIdentify: EmploriumUser[] = [];\n\n constructor(private readonly options: BridgeOptions) {\n this.logger = createLogger(options.config.logger);\n const hostOrigin =\n typeof window !== \"undefined\" && window.location.origin ? window.location.origin : \"*\";\n const derivedWidgetOrigin = this.deriveWidgetOrigin(options.config);\n this.widgetOrigin = derivedWidgetOrigin || hostOrigin;\n this.emitter = options.emitter;\n this.allowedOrigins = new Set([\n hostOrigin,\n this.widgetOrigin,\n ...(options.config.allowedOrigins || []),\n ]);\n }\n\n start(): void {\n if (this.started || typeof window === \"undefined\") return;\n window.addEventListener(\"message\", this.handleMessage);\n this.started = true;\n }\n\n stop(): void {\n if (!this.started || typeof window === \"undefined\") return;\n window.removeEventListener(\"message\", this.handleMessage);\n this.started = false;\n }\n\n sendToggle(open: boolean): void {\n if (typeof window === \"undefined\") return;\n const targetOrigin = window.location.origin || \"*\";\n window.postMessage({ type: \"toggle\", show: open }, targetOrigin);\n this.emitter.emit(\"toggle\", { open });\n this.emitter.emit(open ? \"open\" : \"close\", undefined as never);\n }\n\n sendIdentify(user: EmploriumUser): void {\n if (!user || typeof user !== \"object\") return;\n const chatWindow = this.getChatWindow();\n if (!chatWindow) {\n this.pendingIdentify.push(user);\n return;\n }\n chatWindow.postMessage({ type: \"emplorium:identify\", payload: user }, this.widgetOrigin);\n }\n\n sendVisibility(enabled: boolean): void {\n const chatWindow = this.getChatWindow();\n if (!chatWindow) return;\n chatWindow.postMessage(\n { type: \"emplorium:visibility\", payload: { enabled } },\n this.widgetOrigin\n );\n }\n\n flushPendingIdentify(): void {\n if (this.pendingIdentify.length === 0) return;\n const chatWindow = this.getChatWindow();\n if (!chatWindow) return;\n while (this.pendingIdentify.length > 0) {\n const user = this.pendingIdentify.shift();\n if (user) {\n chatWindow.postMessage({ type: \"emplorium:identify\", payload: user }, this.widgetOrigin);\n }\n }\n }\n\n private deriveWidgetOrigin(config: EmploriumConfig): string {\n if (config.widgetOrigin) return config.widgetOrigin;\n if (config.scriptUrl) {\n try {\n return new URL(config.scriptUrl).origin;\n } catch {\n this.logger.warn(\"[Emplorium SDK] Unable to parse widget origin from scriptUrl\");\n }\n }\n return \"https://widget.emplorium.io\";\n }\n\n private validateOrigin(origin: string): boolean {\n return !!origin && origin !== \"null\" && this.allowedOrigins.has(origin);\n }\n\n private handleMessage = (event: MessageEvent) => {\n if (!event || !this.validateOrigin(event.origin)) {\n return;\n }\n\n const data = event.data;\n if (!data || typeof data !== \"object\" || typeof data.type !== \"string\") {\n return;\n }\n\n switch (data.type) {\n case \"widgetSettingsLoaded\":\n this.emitter.emit(\"widgetSettingsLoaded\", Boolean(data.value));\n this.flushPendingIdentify();\n break;\n case \"wsInitiated\":\n this.emitter.emit(\"wsInitiated\", Boolean(data.value));\n this.flushPendingIdentify();\n break;\n case \"missedMessages\":\n if (typeof data.value === \"number\") {\n this.emitter.emit(\"missedMessages\", data.value);\n }\n break;\n case \"launcherProperties\":\n this.emitter.emit(\"launcherProperties\", data.value || {});\n break;\n case \"openPreviewIframe\":\n this.emitter.emit(\"previewOpen\", {\n url: data.url,\n fileType: data.fileType,\n });\n break;\n default:\n // Intentionally ignore unknown messages; they may be internal or from extensions\n break;\n }\n };\n\n private getChatWindow(): Window | null {\n if (typeof document === \"undefined\") return null;\n const iframe = document.getElementById(CHAT_IFRAME_ID) as HTMLIFrameElement | null;\n if (iframe && iframe.contentWindow) {\n return iframe.contentWindow;\n }\n return null;\n }\n}\n","import { EventBus } from \"./eventBus\";\nimport { ensureLoaderScript } from \"./iframeLoader\";\nimport { createLogger } from \"./logger\";\nimport { PostMessageBridge } from \"./postMessageBridge\";\nimport {\n EmploriumConfig,\n EmploriumEventMap,\n EmploriumState,\n EmploriumUser,\n WidgetVisibilityState,\n} from \"./types\";\n\nconst DEFAULT_STATE: EmploriumState = {\n initialized: false,\n loaderLoaded: false,\n widgetReady: false,\n visibility: \"unknown\",\n};\n\nexport class EmploriumClient {\n private readonly emitter = new EventBus<EmploriumEventMap>();\n private readonly logger;\n private readonly bridge: PostMessageBridge;\n private state: EmploriumState = { ...DEFAULT_STATE };\n private initPromise: Promise<void> | null = null;\n private readyPromise: Promise<void> | null = null;\n private resolveReady: (() => void) | null = null;\n private isEnabled: boolean;\n\n constructor(private readonly config: EmploriumConfig) {\n this.logger = createLogger(config.logger);\n this.bridge = new PostMessageBridge({ config, emitter: this.emitter });\n this.isEnabled = config.enabled !== false; // Default to true if not specified\n this.bindApiMethods();\n }\n\n init = (): Promise<void> => {\n if (this.initPromise) {\n return this.initPromise;\n }\n\n // If widget is disabled, resolve immediately without loading\n if (!this.isEnabled) {\n this.logger.debug(\"[Emplorium SDK] Widget disabled via config\");\n this.initPromise = Promise.resolve();\n return this.initPromise;\n }\n\n this.state.initialized = true;\n this.bridge.start();\n\n this.readyPromise = new Promise<void>((resolve) => {\n this.resolveReady = resolve;\n });\n\n this.bindBridgeEvents();\n\n this.initPromise = (async () => {\n if (this.config.autoLoad !== false) {\n await ensureLoaderScript({\n accountId: this.config.accountId,\n scriptUrl: this.config.scriptUrl,\n scriptAttributes: this.config.scriptAttributes,\n logger: this.config.logger,\n user: this.config.user, // Pass user identity to loader\n });\n this.state.loaderLoaded = true;\n this.logger.debug(\"[Emplorium SDK] Loader script injected\");\n\n // If user identity was provided in config, send it immediately\n if (this.config.user) {\n const { firstName, lastName, email } = this.config.user;\n if (firstName || lastName || email) {\n this.setUser({ firstName, lastName, email });\n }\n }\n }\n\n if (this.config.autoOpen) {\n this.open();\n }\n })().catch((error) => {\n this.emitter.emit(\"error\", error);\n throw error;\n });\n\n return this.initPromise;\n };\n\n on = <K extends keyof EmploriumEventMap>(\n event: K,\n listener: (payload: EmploriumEventMap[K]) => void\n ) => {\n return this.emitter.on(event, listener);\n };\n\n off = <K extends keyof EmploriumEventMap>(\n event: K,\n listener: (payload: EmploriumEventMap[K]) => void\n ) => {\n return this.emitter.off(event, listener);\n };\n\n ready = async (): Promise<void> => {\n await this.init();\n return this.readyPromise || Promise.resolve();\n };\n\n open = (): void => {\n this.bridge.sendToggle(true);\n this.state.visibility = \"open\";\n };\n\n close = (): void => {\n this.bridge.sendToggle(false);\n this.state.visibility = \"closed\";\n };\n\n toggle = (): void => {\n const nextOpen = this.state.visibility !== \"open\";\n this.bridge.sendToggle(nextOpen);\n this.state.visibility = nextOpen ? \"open\" : \"closed\";\n };\n\n setUser = (user: EmploriumUser): void => {\n if (!this.isEnabled) return;\n this.bridge.sendIdentify(user);\n };\n\n /**\n * Enable the widget (show it). Only has effect if widget was previously disabled.\n */\n enable = (): void => {\n if (this.isEnabled) return;\n this.isEnabled = true;\n this.bridge.sendVisibility(true);\n };\n\n /**\n * Disable the widget (hide it completely).\n */\n disable = (): void => {\n if (!this.isEnabled) return;\n this.isEnabled = false;\n this.bridge.sendVisibility(false);\n this.state.visibility = \"closed\";\n };\n\n /**\n * Check if the widget is currently enabled.\n */\n isWidgetEnabled = (): boolean => {\n return this.isEnabled;\n };\n\n getState = (): EmploriumState => {\n return { ...this.state };\n };\n\n destroy = (): void => {\n this.bridge.stop();\n this.emitter.clear();\n this.state = { ...DEFAULT_STATE };\n this.initPromise = null;\n this.readyPromise = null;\n this.resolveReady = null;\n };\n\n private bindApiMethods(): void {\n this.init = this.init.bind(this);\n this.on = this.on.bind(this);\n this.off = this.off.bind(this);\n this.ready = this.ready.bind(this);\n this.open = this.open.bind(this);\n this.close = this.close.bind(this);\n this.toggle = this.toggle.bind(this);\n this.setUser = this.setUser.bind(this);\n this.enable = this.enable.bind(this);\n this.disable = this.disable.bind(this);\n this.isWidgetEnabled = this.isWidgetEnabled.bind(this);\n this.getState = this.getState.bind(this);\n this.destroy = this.destroy.bind(this);\n }\n\n private setVisibility(state: WidgetVisibilityState): void {\n this.state.visibility = state;\n }\n\n private bindBridgeEvents(): void {\n this.emitter.on(\"toggle\", ({ open }) => this.setVisibility(open ? \"open\" : \"closed\"));\n this.emitter.on(\"open\", () => this.setVisibility(\"open\"));\n this.emitter.on(\"close\", () => this.setVisibility(\"closed\"));\n\n const markReady = () => {\n if (this.state.widgetReady) return;\n this.state.widgetReady = true;\n this.resolveReady?.();\n this.resolveReady = null;\n this.emitter.emit(\"ready\", undefined as never);\n };\n\n this.emitter.on(\"wsInitiated\", markReady);\n this.emitter.on(\"widgetSettingsLoaded\", markReady);\n }\n}\n"],"mappings":"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","names":[]}
|