@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 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
+ }