@olotalk/widget-loader 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +150 -0
- package/dist/loader.iife.js +1 -0
- package/dist/loader.js +155 -0
- package/package.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# @olotalk/widget-loader
|
|
2
|
+
|
|
3
|
+
Embed the [Olotalk](https://olotalk.com) AI chat widget on any website with a single `<script>` tag — no framework required.
|
|
4
|
+
|
|
5
|
+
The loader handles config fetching, browser compatibility detection, and dynamic loading of the widget bundle from the CDN. Your visitors get a grounded, RAG-powered chat assistant that answers questions based on your own content.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<script
|
|
13
|
+
src="https://cdn.jsdelivr.net/npm/@olotalk/widget-loader/dist/loader.iife.js"
|
|
14
|
+
data-olotalk-widget-id="YOUR_WIDGET_ID"
|
|
15
|
+
data-olotalk-origin="https://api.olotalk.com"
|
|
16
|
+
></script>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Paste this before `</body>` on any page. The widget appears immediately as a floating launcher in the bottom-right corner.
|
|
20
|
+
|
|
21
|
+
> Get your widget ID from the [Olotalk dashboard](https://olotalk.com).
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Configuration
|
|
26
|
+
|
|
27
|
+
### Via HTML attributes
|
|
28
|
+
|
|
29
|
+
All attributes are read from the `<script>` tag itself.
|
|
30
|
+
|
|
31
|
+
| Attribute | Type | Description |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| `data-olotalk-widget-id` | `string` | **Required.** Your widget ID from the dashboard. |
|
|
34
|
+
| `data-olotalk-origin` | `string` | Base URL of your Olotalk API (e.g. `https://api.olotalk.com`). Defaults to current page origin. |
|
|
35
|
+
| `data-olotalk-locale` | `string` | Force a display language: `"en"`, `"fr"`, `"en-CA"`, `"fr-CA"`. Defaults to browser language. |
|
|
36
|
+
| `data-olotalk-cdn-base` | `string` | Override the widget asset base URL (for self-hosting). |
|
|
37
|
+
|
|
38
|
+
### Via `window.OlotalkConfig`
|
|
39
|
+
|
|
40
|
+
Declare a global config object **before** the loader script for programmatic setup:
|
|
41
|
+
|
|
42
|
+
```html
|
|
43
|
+
<script>
|
|
44
|
+
window.OlotalkConfig = {
|
|
45
|
+
widgetId: "YOUR_WIDGET_ID",
|
|
46
|
+
origin: "https://api.olotalk.com",
|
|
47
|
+
locale: "fr",
|
|
48
|
+
theme: "dark",
|
|
49
|
+
placement: "embedded",
|
|
50
|
+
mount: "#chat-container",
|
|
51
|
+
};
|
|
52
|
+
</script>
|
|
53
|
+
<script src="https://cdn.jsdelivr.net/npm/@olotalk/widget-loader/dist/loader.iife.js"></script>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Full config reference
|
|
57
|
+
|
|
58
|
+
| Option | Type | Default | Description |
|
|
59
|
+
|---|---|---|---|
|
|
60
|
+
| `widgetId` | `string` | — | **Required.** Your widget ID. |
|
|
61
|
+
| `origin` | `string` | `window.location.origin` | Base URL of your Olotalk API. |
|
|
62
|
+
| `locale` | `string` | Browser language | Force language: `"en"` \| `"fr"` \| `"en-CA"` \| `"fr-CA"`. |
|
|
63
|
+
| `theme` | `"light"` \| `"dark"` \| `object` | `"light"` | Color scheme or custom theme overrides. |
|
|
64
|
+
| `placement` | `"floating"` \| `"embedded"` | `"floating"` | Floating launcher button or inline panel. |
|
|
65
|
+
| `mount` | `string` | `document.body` | CSS selector for the widget mount point (use with `"embedded"`). |
|
|
66
|
+
| `version` | `string` | `"latest"` | Pin a specific `@olotalk/widget` npm version (e.g. `"0.1.0"`). |
|
|
67
|
+
| `cdnBase` | `string` | jsDelivr CDN | Override widget asset base URL for self-hosting. |
|
|
68
|
+
| `cssUrl` | `string` | Auto-resolved | Override the widget CSS URL. In a future release this will be provided automatically by the widget config from the dashboard. |
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## JavaScript API
|
|
73
|
+
|
|
74
|
+
The loader exposes a global `Olotalk()` command queue. You can call it before or after the script loads.
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
// Open or close the panel programmatically
|
|
78
|
+
Olotalk('open')
|
|
79
|
+
Olotalk('close')
|
|
80
|
+
|
|
81
|
+
// Re-initialize with a different config
|
|
82
|
+
Olotalk('init', { locale: 'fr' })
|
|
83
|
+
|
|
84
|
+
// Remove the widget from the page entirely
|
|
85
|
+
Olotalk('destroy')
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Commands queued before the widget loads are replayed automatically once it is ready.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Version pinning
|
|
93
|
+
|
|
94
|
+
By default, the loader fetches the `latest` published version of `@olotalk/widget` from jsDelivr. To lock a specific version:
|
|
95
|
+
|
|
96
|
+
```html
|
|
97
|
+
<!-- Pin widget bundle to a specific version -->
|
|
98
|
+
<script
|
|
99
|
+
src="https://cdn.jsdelivr.net/npm/@olotalk/widget-loader/dist/loader.iife.js"
|
|
100
|
+
data-olotalk-widget-id="YOUR_WIDGET_ID"
|
|
101
|
+
data-olotalk-version="0.1.0"
|
|
102
|
+
></script>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Or pin the loader itself by version:
|
|
106
|
+
|
|
107
|
+
```html
|
|
108
|
+
<script src="https://cdn.jsdelivr.net/npm/@olotalk/widget-loader@0.0.1/dist/loader.iife.js" ...></script>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Self-hosting
|
|
114
|
+
|
|
115
|
+
To serve widget assets from your own server instead of jsDelivr:
|
|
116
|
+
|
|
117
|
+
```html
|
|
118
|
+
<script
|
|
119
|
+
src="/path/to/loader.iife.js"
|
|
120
|
+
data-olotalk-widget-id="YOUR_WIDGET_ID"
|
|
121
|
+
data-olotalk-cdn-base="/assets/widget"
|
|
122
|
+
></script>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The loader will fetch `olotalk-widget.js`, `olotalk-widget.iife.js`, and `olotalk-widget.css` from the provided base URL.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## npm install
|
|
130
|
+
|
|
131
|
+
If you are using a bundler or framework, you can import the loader directly:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
npm install @olotalk/widget-loader
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import { ensureWidget } from '@olotalk/widget-loader'
|
|
139
|
+
|
|
140
|
+
ensureWidget({
|
|
141
|
+
widgetId: 'YOUR_WIDGET_ID',
|
|
142
|
+
origin: 'https://api.olotalk.com',
|
|
143
|
+
})
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
MIT © [Olotalk](https://olotalk.com)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var OlotalkWidgetLoader=(function(w){"use strict";const a=window,g=((t,e)=>{(g.q||(g.q=[])).push([t,e])});a.Olotalk||(a.Olotalk=g);function y(){var u;const t=document.currentScript;let e={};try{const s=(u=t==null?void 0:t.dataset)==null?void 0:u.olotalk;s&&(e=JSON.parse(s))}catch{}const i=(t==null?void 0:t.dataset)||{},o={...a.OlotalkConfig||{},...e||{}},l=i.olotalkWidgetId||o.widgetId||o.siteId,c=i.olotalkOrigin||o.origin,m=i.olotalkCdnBase||o.cdnBase,h=i.olotalkLocale||o.locale;return{...o,widgetId:l,origin:c,cdnBase:m,locale:h}}function W(t){if(!t)return window.location.origin;try{const e=new URL(t);return e.pathname.endsWith("/api")&&(e.pathname=e.pathname.replace(/\/api$/,"")),e.origin}catch{return window.location.origin}}function C(t,e){if(!e||e.length===0)return!0;const i=t.toLowerCase();return e.some(o=>{if(!o)return!1;const l=o.toLowerCase();if(l===i)return!0;if(l.startsWith("*.")){const c=l.slice(2);return i===c||i.endsWith(`.${c}`)}return!1})}async function b(t,e){const i=new URL(`/public/v1/widgets/${e}/config`,t),o=await fetch(i.toString());if(!o.ok)throw new Error(`Config fetch failed (${o.status})`);return o.json()}function E(){return"noModule"in document.createElement("script")}async function S(t){return import(t)}function L(t){return new Promise((e,i)=>{const o=document.createElement("script");o.src=t,o.async=!0,o.onload=()=>e(),o.onerror=()=>i(new Error("Failed to load "+t)),document.head.appendChild(o)})}let n=null,d=null;const k=function(t,e){var i,o,l;try{switch(t){case"init":return f(e);case"destroy":return(i=n==null?void 0:n.destroy)==null?void 0:i.call(n).finally(()=>{n=null});case"open":return(o=n==null?void 0:n.open)==null?void 0:o.call(n);case"close":return(l=n==null?void 0:n.close)==null?void 0:l.call(n);default:console.warn("[Olotalk] Unknown command:",t)}}catch(c){console.error("[Olotalk] Command error:",c)}};async function $(){var p,O;const t=y(),e=t.widgetId||t.siteId;if(!e){console.error("[Olotalk] Missing required 'widgetId' in config.");return}const i=W(t.origin);let o=null;try{o=await b(i,e)}catch(r){console.error("[Olotalk] Failed to fetch widget config:",r);return}if(!C(window.location.hostname,o.allowedDomains)){console.warn("[Olotalk] Widget disabled for this domain.");return}const l=t.cdnBase||`https://cdn.jsdelivr.net/npm/@olotalk/widget@${t.version||"latest"}/dist`,c=`${l}/olotalk-widget.js`,m=`${l}/olotalk-widget.iife.js`,h=t.cssUrl||`${l}/olotalk-widget.css`,u=(p=o.launcher)==null?void 0:p.logoUrl;if(u){const r=new Image;r.src=u}let s=a.OlotalkWidget||null;try{if(!s)if(E()){const r=await S(c);s=(r==null?void 0:r.default)||r}else await L(m),s=a.OlotalkWidget}catch(r){console.error("[Olotalk] Failed to load widget bundle:",r);return}if(!s||typeof s.createWidget!="function"){console.error("[Olotalk] Widget API missing 'createWidget'.");return}const M=(t.mount?document.querySelector(t.mount):null)||document.body;n!=null&&n.destroy&&(await n.destroy(),n=null),n=s.createWidget(M,{widgetId:e,origin:i,config:o,theme:t.theme||"light",placement:t.placement,cssUrl:h,locale:t.locale});const U=((O=a.Olotalk)==null?void 0:O.q)||[];a.Olotalk=k,a.Olotalk.q=[],U.forEach(([r,j])=>k(r,j))}function f(t){return t&&(a.OlotalkConfig={...a.OlotalkConfig||{},...t}),d||(d=$().finally(()=>{d=null}),d)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>f(),{once:!0}):f(),w.ensureWidget=f,Object.defineProperty(w,Symbol.toStringTag,{value:"Module"}),w})({});
|
package/dist/loader.js
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
const a = window, g = ((t, e) => {
|
|
2
|
+
(g.q || (g.q = [])).push([t, e]);
|
|
3
|
+
});
|
|
4
|
+
a.Olotalk || (a.Olotalk = g);
|
|
5
|
+
function C() {
|
|
6
|
+
var d;
|
|
7
|
+
const t = document.currentScript;
|
|
8
|
+
let e = {};
|
|
9
|
+
try {
|
|
10
|
+
const s = (d = t == null ? void 0 : t.dataset) == null ? void 0 : d.olotalk;
|
|
11
|
+
s && (e = JSON.parse(s));
|
|
12
|
+
} catch {
|
|
13
|
+
}
|
|
14
|
+
const l = (t == null ? void 0 : t.dataset) || {}, o = {
|
|
15
|
+
...a.OlotalkConfig || {},
|
|
16
|
+
...e || {}
|
|
17
|
+
}, i = l.olotalkWidgetId || o.widgetId || o.siteId, c = l.olotalkOrigin || o.origin, f = l.olotalkCdnBase || o.cdnBase, w = l.olotalkLocale || o.locale;
|
|
18
|
+
return {
|
|
19
|
+
...o,
|
|
20
|
+
widgetId: i,
|
|
21
|
+
origin: c,
|
|
22
|
+
cdnBase: f,
|
|
23
|
+
locale: w
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function E(t) {
|
|
27
|
+
if (!t) return window.location.origin;
|
|
28
|
+
try {
|
|
29
|
+
const e = new URL(t);
|
|
30
|
+
return e.pathname.endsWith("/api") && (e.pathname = e.pathname.replace(/\/api$/, "")), e.origin;
|
|
31
|
+
} catch {
|
|
32
|
+
return window.location.origin;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function b(t, e) {
|
|
36
|
+
if (!e || e.length === 0) return !0;
|
|
37
|
+
const l = t.toLowerCase();
|
|
38
|
+
return e.some((o) => {
|
|
39
|
+
if (!o) return !1;
|
|
40
|
+
const i = o.toLowerCase();
|
|
41
|
+
if (i === l) return !0;
|
|
42
|
+
if (i.startsWith("*.")) {
|
|
43
|
+
const c = i.slice(2);
|
|
44
|
+
return l === c || l.endsWith(`.${c}`);
|
|
45
|
+
}
|
|
46
|
+
return !1;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async function $(t, e) {
|
|
50
|
+
const l = new URL(`/public/v1/widgets/${e}/config`, t), o = await fetch(l.toString());
|
|
51
|
+
if (!o.ok)
|
|
52
|
+
throw new Error(`Config fetch failed (${o.status})`);
|
|
53
|
+
return o.json();
|
|
54
|
+
}
|
|
55
|
+
function L() {
|
|
56
|
+
return "noModule" in document.createElement("script");
|
|
57
|
+
}
|
|
58
|
+
async function S(t) {
|
|
59
|
+
return import(
|
|
60
|
+
/* @vite-ignore */
|
|
61
|
+
/* webpackIgnore: true */
|
|
62
|
+
t
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
function U(t) {
|
|
66
|
+
return new Promise((e, l) => {
|
|
67
|
+
const o = document.createElement("script");
|
|
68
|
+
o.src = t, o.async = !0, o.onload = () => e(), o.onerror = () => l(new Error("Failed to load " + t)), document.head.appendChild(o);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
let n = null, u = null;
|
|
72
|
+
const k = function(t, e) {
|
|
73
|
+
var l, o, i;
|
|
74
|
+
try {
|
|
75
|
+
switch (t) {
|
|
76
|
+
case "init":
|
|
77
|
+
return m(e);
|
|
78
|
+
case "destroy":
|
|
79
|
+
return (l = n == null ? void 0 : n.destroy) == null ? void 0 : l.call(n).finally(() => {
|
|
80
|
+
n = null;
|
|
81
|
+
});
|
|
82
|
+
case "open":
|
|
83
|
+
return (o = n == null ? void 0 : n.open) == null ? void 0 : o.call(n);
|
|
84
|
+
case "close":
|
|
85
|
+
return (i = n == null ? void 0 : n.close) == null ? void 0 : i.call(n);
|
|
86
|
+
default:
|
|
87
|
+
console.warn("[Olotalk] Unknown command:", t);
|
|
88
|
+
}
|
|
89
|
+
} catch (c) {
|
|
90
|
+
console.error("[Olotalk] Command error:", c);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
async function M() {
|
|
94
|
+
var h, p;
|
|
95
|
+
const t = C(), e = t.widgetId || t.siteId;
|
|
96
|
+
if (!e) {
|
|
97
|
+
console.error("[Olotalk] Missing required 'widgetId' in config.");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const l = E(t.origin);
|
|
101
|
+
let o = null;
|
|
102
|
+
try {
|
|
103
|
+
o = await $(l, e);
|
|
104
|
+
} catch (r) {
|
|
105
|
+
console.error("[Olotalk] Failed to fetch widget config:", r);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (!b(window.location.hostname, o.allowedDomains)) {
|
|
109
|
+
console.warn("[Olotalk] Widget disabled for this domain.");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const i = t.cdnBase || `https://cdn.jsdelivr.net/npm/@olotalk/widget@${t.version || "latest"}/dist`, c = `${i}/olotalk-widget.js`, f = `${i}/olotalk-widget.iife.js`, w = t.cssUrl || `${i}/olotalk-widget.css`, d = (h = o.launcher) == null ? void 0 : h.logoUrl;
|
|
113
|
+
if (d) {
|
|
114
|
+
const r = new Image();
|
|
115
|
+
r.src = d;
|
|
116
|
+
}
|
|
117
|
+
let s = a.OlotalkWidget || null;
|
|
118
|
+
try {
|
|
119
|
+
if (!s)
|
|
120
|
+
if (L()) {
|
|
121
|
+
const r = await S(c);
|
|
122
|
+
s = (r == null ? void 0 : r.default) || r;
|
|
123
|
+
} else
|
|
124
|
+
await U(f), s = a.OlotalkWidget;
|
|
125
|
+
} catch (r) {
|
|
126
|
+
console.error("[Olotalk] Failed to load widget bundle:", r);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (!s || typeof s.createWidget != "function") {
|
|
130
|
+
console.error("[Olotalk] Widget API missing 'createWidget'.");
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const O = (t.mount ? document.querySelector(t.mount) : null) || document.body;
|
|
134
|
+
n != null && n.destroy && (await n.destroy(), n = null), n = s.createWidget(O, {
|
|
135
|
+
widgetId: e,
|
|
136
|
+
origin: l,
|
|
137
|
+
config: o,
|
|
138
|
+
theme: t.theme || "light",
|
|
139
|
+
placement: t.placement,
|
|
140
|
+
cssUrl: w,
|
|
141
|
+
// Pass explicit locale override if provided; widget resolves browser language itself.
|
|
142
|
+
locale: t.locale
|
|
143
|
+
});
|
|
144
|
+
const y = ((p = a.Olotalk) == null ? void 0 : p.q) || [];
|
|
145
|
+
a.Olotalk = k, a.Olotalk.q = [], y.forEach(([r, W]) => k(r, W));
|
|
146
|
+
}
|
|
147
|
+
function m(t) {
|
|
148
|
+
return t && (a.OlotalkConfig = { ...a.OlotalkConfig || {}, ...t }), u || (u = M().finally(() => {
|
|
149
|
+
u = null;
|
|
150
|
+
}), u);
|
|
151
|
+
}
|
|
152
|
+
document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", () => m(), { once: !0 }) : m();
|
|
153
|
+
export {
|
|
154
|
+
m as ensureWidget
|
|
155
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@olotalk/widget-loader",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/loader.js",
|
|
7
|
+
"module": "./dist/loader.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/loader.js",
|
|
11
|
+
"require": "./dist/loader.js"
|
|
12
|
+
},
|
|
13
|
+
"./iife": "./dist/loader.iife.js"
|
|
14
|
+
},
|
|
15
|
+
"files": ["dist"],
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "vite build"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"typescript": "^5.6.3",
|
|
24
|
+
"vite": "^6.4.1"
|
|
25
|
+
}
|
|
26
|
+
}
|