@humanfirst-chat/js 0.1.6 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +75 -82
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +75 -82
- package/dist/index.mjs.map +1 -1
- package/package.json +25 -25
package/dist/index.d.mts
CHANGED
|
@@ -58,6 +58,10 @@ type HFChatGlobal = HFChatAPI & {
|
|
|
58
58
|
*/
|
|
59
59
|
init(opts?: HFChatLoaderConfig): Promise<HFChatAPI>;
|
|
60
60
|
};
|
|
61
|
+
type QueuedCall = {
|
|
62
|
+
method: keyof HFChatAPI;
|
|
63
|
+
args: unknown[];
|
|
64
|
+
};
|
|
61
65
|
declare global {
|
|
62
66
|
interface Window {
|
|
63
67
|
HFChat?: HFChatAPI;
|
|
@@ -65,8 +69,13 @@ declare global {
|
|
|
65
69
|
init: (opts: unknown) => HFChatAPI;
|
|
66
70
|
};
|
|
67
71
|
__HFCHAT_DISABLE_AUTO_INIT?: boolean;
|
|
72
|
+
__HFCHAT_QUEUE__?: QueuedCall[];
|
|
73
|
+
__HFCHAT_REAL__?: HFChatAPI;
|
|
68
74
|
}
|
|
69
75
|
}
|
|
70
|
-
declare const HFChat: HFChatGlobal
|
|
76
|
+
declare const HFChat: HFChatGlobal & {
|
|
77
|
+
__HFCHAT_STUB__?: true;
|
|
78
|
+
__real?: HFChatAPI;
|
|
79
|
+
};
|
|
71
80
|
|
|
72
81
|
export { HFChat, type HFChatAPI, type HFChatConfig, type HFChatGlobal, type HFChatIdentifyMeta, type HFChatLoaderConfig, type HFChatLogLevel, type HFChatOpenOptions, type HFChatWidgetSettings, HFChat as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -58,6 +58,10 @@ type HFChatGlobal = HFChatAPI & {
|
|
|
58
58
|
*/
|
|
59
59
|
init(opts?: HFChatLoaderConfig): Promise<HFChatAPI>;
|
|
60
60
|
};
|
|
61
|
+
type QueuedCall = {
|
|
62
|
+
method: keyof HFChatAPI;
|
|
63
|
+
args: unknown[];
|
|
64
|
+
};
|
|
61
65
|
declare global {
|
|
62
66
|
interface Window {
|
|
63
67
|
HFChat?: HFChatAPI;
|
|
@@ -65,8 +69,13 @@ declare global {
|
|
|
65
69
|
init: (opts: unknown) => HFChatAPI;
|
|
66
70
|
};
|
|
67
71
|
__HFCHAT_DISABLE_AUTO_INIT?: boolean;
|
|
72
|
+
__HFCHAT_QUEUE__?: QueuedCall[];
|
|
73
|
+
__HFCHAT_REAL__?: HFChatAPI;
|
|
68
74
|
}
|
|
69
75
|
}
|
|
70
|
-
declare const HFChat: HFChatGlobal
|
|
76
|
+
declare const HFChat: HFChatGlobal & {
|
|
77
|
+
__HFCHAT_STUB__?: true;
|
|
78
|
+
__real?: HFChatAPI;
|
|
79
|
+
};
|
|
71
80
|
|
|
72
81
|
export { HFChat, type HFChatAPI, type HFChatConfig, type HFChatGlobal, type HFChatIdentifyMeta, type HFChatLoaderConfig, type HFChatLogLevel, type HFChatOpenOptions, type HFChatWidgetSettings, HFChat as default };
|
package/dist/index.js
CHANGED
|
@@ -41,14 +41,44 @@ function logError(message, ...args) {
|
|
|
41
41
|
}
|
|
42
42
|
var loaderPromise = null;
|
|
43
43
|
var lastInitOpts;
|
|
44
|
-
function
|
|
44
|
+
function getQueue() {
|
|
45
|
+
if (typeof window === "undefined") return [];
|
|
46
|
+
if (!window.__HFCHAT_QUEUE__) {
|
|
47
|
+
window.__HFCHAT_QUEUE__ = [];
|
|
48
|
+
}
|
|
49
|
+
return window.__HFCHAT_QUEUE__;
|
|
50
|
+
}
|
|
51
|
+
function enqueue(method, args) {
|
|
52
|
+
if (typeof window === "undefined") return;
|
|
53
|
+
getQueue().push({ method, args });
|
|
54
|
+
}
|
|
55
|
+
function getRealApi() {
|
|
45
56
|
if (typeof window === "undefined") return null;
|
|
57
|
+
const globalReal = window.__HFCHAT_REAL__;
|
|
58
|
+
if (globalReal && globalReal.__HFCHAT_INSTANCE__ === true) {
|
|
59
|
+
return globalReal;
|
|
60
|
+
}
|
|
46
61
|
const candidate = window.HFChat;
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
|
|
62
|
+
if (candidate && candidate.__HFCHAT_INSTANCE__ === true) {
|
|
63
|
+
return candidate;
|
|
64
|
+
}
|
|
65
|
+
if (candidate && candidate.__real && candidate.__real.__HFCHAT_INSTANCE__ === true) {
|
|
66
|
+
return candidate.__real;
|
|
67
|
+
}
|
|
50
68
|
return null;
|
|
51
69
|
}
|
|
70
|
+
function callOrQueue(method, args) {
|
|
71
|
+
if (typeof window === "undefined") return;
|
|
72
|
+
const api = getRealApi();
|
|
73
|
+
const fn = api ? api[method] : null;
|
|
74
|
+
if (api && typeof fn === "function") {
|
|
75
|
+
logFull(`Calling '${String(method)}' on real API`);
|
|
76
|
+
fn.apply(api, args);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
logFull(`Queueing '${String(method)}' until real API is ready`);
|
|
80
|
+
enqueue(method, args);
|
|
81
|
+
}
|
|
52
82
|
function injectScript(src) {
|
|
53
83
|
return new Promise((resolve, reject) => {
|
|
54
84
|
if (typeof document === "undefined") return resolve();
|
|
@@ -111,8 +141,9 @@ async function loadWidget(opts = {}) {
|
|
|
111
141
|
baseURL: opts.baseURL,
|
|
112
142
|
host: opts.host
|
|
113
143
|
});
|
|
114
|
-
|
|
115
|
-
|
|
144
|
+
const realApi = getRealApi();
|
|
145
|
+
logFull("HumanFirstChat.init() returned:", { hasInstance: realApi?.__HFCHAT_INSTANCE__ });
|
|
146
|
+
return realApi ?? api;
|
|
116
147
|
}
|
|
117
148
|
async function init(opts = {}) {
|
|
118
149
|
if (opts.logs) {
|
|
@@ -120,7 +151,7 @@ async function init(opts = {}) {
|
|
|
120
151
|
}
|
|
121
152
|
lastInitOpts = { ...lastInitOpts, ...opts };
|
|
122
153
|
log("init() called with options:", { siteId: opts.siteId, logs: opts.logs });
|
|
123
|
-
const existingApi = getRealApi(
|
|
154
|
+
const existingApi = getRealApi();
|
|
124
155
|
if (existingApi) {
|
|
125
156
|
log("Returning existing real API");
|
|
126
157
|
return existingApi;
|
|
@@ -133,84 +164,46 @@ async function init(opts = {}) {
|
|
|
133
164
|
loaderPromise = loadWidget(lastInitOpts);
|
|
134
165
|
return loaderPromise;
|
|
135
166
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
windowHFChat: typeof window.HFChat,
|
|
158
|
-
isProxy: window.HFChat === HFChat
|
|
159
|
-
});
|
|
167
|
+
var HFChat = {
|
|
168
|
+
init,
|
|
169
|
+
show: () => callOrQueue("show", []),
|
|
170
|
+
hide: () => callOrQueue("hide", []),
|
|
171
|
+
open: (options) => callOrQueue("open", [options]),
|
|
172
|
+
close: () => callOrQueue("close", []),
|
|
173
|
+
toggle: () => callOrQueue("toggle", []),
|
|
174
|
+
isOpen: () => {
|
|
175
|
+
const api = getRealApi();
|
|
176
|
+
return api?.isOpen?.() ?? false;
|
|
177
|
+
},
|
|
178
|
+
identify: (meta) => callOrQueue("identify", [meta]),
|
|
179
|
+
configure: (settings) => callOrQueue("configure", [settings]),
|
|
180
|
+
onReady: (callback) => {
|
|
181
|
+
if (typeof callback !== "function") return;
|
|
182
|
+
const api = getRealApi();
|
|
183
|
+
if (api?.ready) {
|
|
184
|
+
try {
|
|
185
|
+
callback();
|
|
186
|
+
} catch (error) {
|
|
187
|
+
console.error("[HFChat SDK] Error in onReady callback:", error);
|
|
160
188
|
}
|
|
161
|
-
|
|
162
|
-
log(`Method '${methodName}' found after ${attempts} attempts`);
|
|
163
|
-
resolve(api);
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
if (attempts < maxAttempts) {
|
|
167
|
-
attempts += 1;
|
|
168
|
-
setTimeout(checkMethod, 100);
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
logError(`Timeout: '${methodName}' not available after 5 seconds`);
|
|
172
|
-
reject(new Error(`HFChat method '${methodName}' not available after 5 seconds`));
|
|
173
|
-
};
|
|
174
|
-
setTimeout(checkMethod, 100);
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
var HFChat = new Proxy(
|
|
178
|
-
{},
|
|
179
|
-
{
|
|
180
|
-
get(_target, prop) {
|
|
181
|
-
if (prop === "init") return init;
|
|
182
|
-
if (typeof window === "undefined") return () => {
|
|
183
|
-
};
|
|
184
|
-
if (prop === "__HFCHAT_INSTANCE__") return void 0;
|
|
185
|
-
if (prop === "then") return void 0;
|
|
186
|
-
if (prop === "ready") {
|
|
187
|
-
const api = getRealApi(HFChat);
|
|
188
|
-
return !!api?.ready;
|
|
189
|
-
}
|
|
190
|
-
if (prop === "isOpen") {
|
|
191
|
-
return () => {
|
|
192
|
-
const api = getRealApi(HFChat);
|
|
193
|
-
return api?.isOpen?.() ?? false;
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
return (...args) => {
|
|
197
|
-
const methodName = String(prop);
|
|
198
|
-
logFull(`Proxy: '${methodName}' called, forwarding to waitForMethod`);
|
|
199
|
-
waitForMethod(methodName).then((api) => {
|
|
200
|
-
const fn = api[methodName];
|
|
201
|
-
if (typeof fn === "function") {
|
|
202
|
-
logFull(`Proxy: executing '${methodName}' on real API`);
|
|
203
|
-
fn.apply(api, args);
|
|
204
|
-
} else {
|
|
205
|
-
logError(`Method '${methodName}' not found on real API`);
|
|
206
|
-
}
|
|
207
|
-
}).catch((error) => {
|
|
208
|
-
logError(error instanceof Error ? error.message : String(error));
|
|
209
|
-
});
|
|
210
|
-
};
|
|
189
|
+
return;
|
|
211
190
|
}
|
|
191
|
+
callOrQueue("onReady", [callback]);
|
|
192
|
+
},
|
|
193
|
+
onOpen: (callback) => {
|
|
194
|
+
if (typeof callback !== "function") return;
|
|
195
|
+
callOrQueue("onOpen", [callback]);
|
|
196
|
+
},
|
|
197
|
+
onClose: (callback) => {
|
|
198
|
+
if (typeof callback !== "function") return;
|
|
199
|
+
callOrQueue("onClose", [callback]);
|
|
200
|
+
},
|
|
201
|
+
get ready() {
|
|
202
|
+
const api = getRealApi();
|
|
203
|
+
return api?.ready ?? false;
|
|
212
204
|
}
|
|
213
|
-
|
|
205
|
+
};
|
|
206
|
+
HFChat.__HFCHAT_STUB__ = true;
|
|
214
207
|
if (typeof window !== "undefined") {
|
|
215
208
|
if (!window.HFChat) {
|
|
216
209
|
window.HFChat = HFChat;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Re-export public types for consumers\nexport type {\n HFChatLogLevel,\n HFChatConfig,\n HFChatWidgetSettings,\n HFChatIdentifyMeta,\n HFChatOpenOptions,\n HFChatAPI,\n} from './types'\n\nimport type { HFChatConfig, HFChatAPI, HFChatLogLevel } from './types'\n\n// Extended config for the JS SDK loader (adds scriptSrc option)\nexport type HFChatLoaderConfig = HFChatConfig & {\n /** Override widget script source (for self-hosting / testing) */\n scriptSrc?: string\n}\n\nexport type HFChatGlobal = HFChatAPI & {\n /**\n * Load the widget script and initialize the widget.\n */\n init(opts?: HFChatLoaderConfig): Promise<HFChatAPI>\n}\n\ndeclare global {\n interface Window {\n HFChat?: HFChatAPI\n HumanFirstChat?: {\n init: (opts: unknown) => HFChatAPI\n }\n __HFCHAT_DISABLE_AUTO_INIT?: boolean\n }\n}\n\nconst DEFAULT_SCRIPT_SRC = 'https://humanfirst.chat/widget.js'\nconst SCRIPT_DATA_ATTR = 'data-hfchat-widget'\n\n// Logging configuration\nlet logLevel: HFChatLogLevel = 'none'\n\nfunction log(message: string, ...args: unknown[]) {\n if (logLevel === 'none') return\n console.log(`[HFChat SDK] ${message}`, ...args)\n}\n\nfunction logFull(message: string, ...args: unknown[]) {\n if (logLevel !== 'full') return\n console.log(`[HFChat SDK] ${message}`, ...args)\n}\n\nfunction logError(message: string, ...args: unknown[]) {\n if (logLevel === 'none') return\n console.error(`[HFChat SDK] ${message}`, ...args)\n}\n\nlet loaderPromise: Promise<HFChatAPI> | null = null\nlet lastInitOpts: HFChatLoaderConfig | undefined\n\nfunction getRealApi(selfProxy: HFChatGlobal): HFChatAPI | null {\n if (typeof window === 'undefined') return null\n const candidate = window.HFChat\n if (!candidate) return null\n // Check if candidate is the proxy (same reference) - if so, real API not yet available\n if (candidate === selfProxy) return null\n // Check if candidate has the real instance marker\n if ((candidate as any).__HFCHAT_INSTANCE__ === true) return candidate\n return null\n}\n\nfunction injectScript(src: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (typeof document === 'undefined') return resolve()\n if (window.HumanFirstChat) {\n logFull('HumanFirstChat already exists, skipping script injection')\n return resolve()\n }\n\n const existing = document.querySelector(\n `script[${SCRIPT_DATA_ATTR}=\"1\"]`\n ) as HTMLScriptElement | null\n if (existing) {\n logFull('Widget script already in DOM, waiting for load')\n existing.addEventListener('load', () => resolve(), { once: true })\n existing.addEventListener(\n 'error',\n () => reject(new Error('Failed to load widget script')),\n { once: true }\n )\n return\n }\n\n log('Injecting widget script:', src)\n window.__HFCHAT_DISABLE_AUTO_INIT = true\n const script = document.createElement('script')\n script.async = true\n script.src = src\n script.setAttribute(SCRIPT_DATA_ATTR, '1')\n script.setAttribute('data-auto-init', 'false')\n script.onerror = () => {\n logError('Failed to load widget script:', src)\n reject(new Error(`Failed to load widget script: ${src}`))\n }\n script.onload = () => {\n setTimeout(() => {\n if (window.HumanFirstChat) {\n log('Widget script loaded successfully')\n resolve()\n } else {\n logError('Widget script loaded but HumanFirstChat not found')\n reject(new Error('Widget did not attach to window.HumanFirstChat'))\n }\n }, 0)\n }\n document.head.appendChild(script)\n })\n}\n\nasync function loadWidget(opts: HFChatLoaderConfig = {}): Promise<HFChatAPI> {\n if (typeof window === 'undefined') return {} as HFChatAPI\n\n const scriptSrc = opts.scriptSrc ?? DEFAULT_SCRIPT_SRC\n logFull('loadWidget starting with options:', { siteId: opts.siteId, scriptSrc })\n\n await injectScript(scriptSrc)\n\n if (!window.HumanFirstChat?.init) {\n throw new Error('HumanFirstChat.init is not available after script load')\n }\n\n log('Calling HumanFirstChat.init()')\n const api = window.HumanFirstChat.init({\n siteId: opts.siteId,\n hidden: opts.hidden,\n hideOnClose: opts.hideOnClose,\n logs: opts.logs,\n baseURL: opts.baseURL,\n host: opts.host,\n })\n\n logFull('HumanFirstChat.init() returned:', { hasInstance: (api as any)?.__HFCHAT_INSTANCE__ })\n return api\n}\n\nasync function init(opts: HFChatLoaderConfig = {}): Promise<HFChatAPI> {\n // Update log level from options\n if (opts.logs) {\n logLevel = opts.logs\n }\n\n lastInitOpts = { ...lastInitOpts, ...opts }\n log('init() called with options:', { siteId: opts.siteId, logs: opts.logs })\n\n const existingApi = getRealApi(HFChat)\n if (existingApi) {\n log('Returning existing real API')\n return existingApi\n }\n\n if (loaderPromise) {\n logFull('Returning existing loader promise')\n return loaderPromise\n }\n\n log('Starting widget load...')\n loaderPromise = loadWidget(lastInitOpts)\n return loaderPromise\n}\n\nasync function waitForMethod(methodName: string): Promise<HFChatAPI> {\n logFull(`waitForMethod('${methodName}') starting...`)\n\n // Ensure init is called (may already be in progress)\n await init()\n logFull(`init() completed, checking for '${methodName}'`)\n\n // Check if real API is already available\n const existing = getRealApi(HFChat)\n logFull('getRealApi returned:', existing ? 'real API found' : 'null')\n\n if (existing && typeof (existing as any)[methodName] === 'function') {\n log(`Method '${methodName}' available immediately`)\n return existing\n }\n\n // Poll for the real API to become available\n logFull(`Polling for '${methodName}'...`)\n return new Promise((resolve, reject) => {\n let attempts = 0\n const maxAttempts = 50 // 5 seconds total\n\n const checkMethod = () => {\n const api = getRealApi(HFChat)\n const fn = api ? (api as any)[methodName] : null\n\n // Log every 10 attempts (1 second)\n if (attempts % 10 === 0 && attempts > 0) {\n logFull(`Polling attempt ${attempts}/50 for '${methodName}':`, {\n hasApi: !!api,\n hasMethod: !!fn,\n windowHFChat: typeof window.HFChat,\n isProxy: window.HFChat === HFChat\n })\n }\n\n if (api && typeof fn === 'function') {\n log(`Method '${methodName}' found after ${attempts} attempts`)\n resolve(api)\n return\n }\n\n if (attempts < maxAttempts) {\n attempts += 1\n setTimeout(checkMethod, 100)\n return\n }\n\n logError(`Timeout: '${methodName}' not available after 5 seconds`)\n reject(new Error(`HFChat method '${methodName}' not available after 5 seconds`))\n }\n\n setTimeout(checkMethod, 100)\n })\n}\n\nexport const HFChat: HFChatGlobal = new Proxy(\n {},\n {\n get(_target, prop) {\n // Handle init specially - it's the entry point\n if (prop === 'init') return init\n\n // Server-side rendering guard\n if (typeof window === 'undefined') return () => {}\n\n // Handle __HFCHAT_INSTANCE__ check - return undefined so proxy isn't mistaken for real instance\n if (prop === '__HFCHAT_INSTANCE__') return undefined\n\n // Handle 'then' - return undefined so proxy isn't treated as a thenable/Promise\n // This is critical because await/Promise.resolve() check for .then()\n if (prop === 'then') return undefined\n\n // Handle ready property\n if (prop === 'ready') {\n const api = getRealApi(HFChat)\n return !!api?.ready\n }\n\n // Handle isOpen method\n if (prop === 'isOpen') {\n return () => {\n const api = getRealApi(HFChat)\n return api?.isOpen?.() ?? false\n }\n }\n\n // For all other methods, queue them until the real API is ready\n return (...args: unknown[]) => {\n const methodName = String(prop)\n logFull(`Proxy: '${methodName}' called, forwarding to waitForMethod`)\n\n waitForMethod(methodName)\n .then((api) => {\n const fn = (api as any)[methodName]\n if (typeof fn === 'function') {\n logFull(`Proxy: executing '${methodName}' on real API`)\n fn.apply(api, args)\n } else {\n logError(`Method '${methodName}' not found on real API`)\n }\n })\n .catch((error) => {\n logError(error instanceof Error ? error.message : String(error))\n })\n }\n },\n }\n) as HFChatGlobal\n\nif (typeof window !== 'undefined') {\n // Expose a stable global singleton, without breaking when the real widget assigns window.HFChat\n if (!window.HFChat) {\n window.HFChat = HFChat\n }\n}\n\nexport default HFChat\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Re-export public types for consumers\nexport type {\n HFChatLogLevel,\n HFChatConfig,\n HFChatWidgetSettings,\n HFChatIdentifyMeta,\n HFChatOpenOptions,\n HFChatAPI,\n} from './types'\n\nimport type { HFChatConfig, HFChatAPI, HFChatLogLevel } from './types'\n\n// Extended config for the JS SDK loader (adds scriptSrc option)\nexport type HFChatLoaderConfig = HFChatConfig & {\n /** Override widget script source (for self-hosting / testing) */\n scriptSrc?: string\n}\n\nexport type HFChatGlobal = HFChatAPI & {\n /**\n * Load the widget script and initialize the widget.\n */\n init(opts?: HFChatLoaderConfig): Promise<HFChatAPI>\n}\n\ntype QueuedCall = {\n method: keyof HFChatAPI\n args: unknown[]\n}\n\ndeclare global {\n interface Window {\n HFChat?: HFChatAPI\n HumanFirstChat?: {\n init: (opts: unknown) => HFChatAPI\n }\n __HFCHAT_DISABLE_AUTO_INIT?: boolean\n __HFCHAT_QUEUE__?: QueuedCall[]\n __HFCHAT_REAL__?: HFChatAPI\n }\n}\n\nconst DEFAULT_SCRIPT_SRC = 'https://humanfirst.chat/widget.js'\nconst SCRIPT_DATA_ATTR = 'data-hfchat-widget'\n\n// Logging configuration\nlet logLevel: HFChatLogLevel = 'none'\n\nfunction log(message: string, ...args: unknown[]) {\n if (logLevel === 'none') return\n console.log(`[HFChat SDK] ${message}`, ...args)\n}\n\nfunction logFull(message: string, ...args: unknown[]) {\n if (logLevel !== 'full') return\n console.log(`[HFChat SDK] ${message}`, ...args)\n}\n\nfunction logError(message: string, ...args: unknown[]) {\n if (logLevel === 'none') return\n console.error(`[HFChat SDK] ${message}`, ...args)\n}\n\nlet loaderPromise: Promise<HFChatAPI> | null = null\nlet lastInitOpts: HFChatLoaderConfig | undefined\n\nfunction getQueue(): QueuedCall[] {\n if (typeof window === 'undefined') return []\n if (!window.__HFCHAT_QUEUE__) {\n window.__HFCHAT_QUEUE__ = []\n }\n return window.__HFCHAT_QUEUE__\n}\n\nfunction enqueue(method: keyof HFChatAPI, args: unknown[]) {\n if (typeof window === 'undefined') return\n getQueue().push({ method, args })\n}\n\nfunction getRealApi(): HFChatAPI | null {\n if (typeof window === 'undefined') return null\n\n const globalReal = window.__HFCHAT_REAL__\n if (globalReal && (globalReal as any).__HFCHAT_INSTANCE__ === true) {\n return globalReal\n }\n\n const candidate = window.HFChat as any\n if (candidate && candidate.__HFCHAT_INSTANCE__ === true) {\n return candidate as HFChatAPI\n }\n\n if (candidate && candidate.__real && candidate.__real.__HFCHAT_INSTANCE__ === true) {\n return candidate.__real as HFChatAPI\n }\n\n return null\n}\n\nfunction callOrQueue(method: keyof HFChatAPI, args: unknown[]) {\n if (typeof window === 'undefined') return\n const api = getRealApi()\n const fn = api ? (api as any)[method] : null\n\n if (api && typeof fn === 'function') {\n logFull(`Calling '${String(method)}' on real API`)\n fn.apply(api, args)\n return\n }\n\n logFull(`Queueing '${String(method)}' until real API is ready`)\n enqueue(method, args)\n}\n\nfunction injectScript(src: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (typeof document === 'undefined') return resolve()\n if (window.HumanFirstChat) {\n logFull('HumanFirstChat already exists, skipping script injection')\n return resolve()\n }\n\n const existing = document.querySelector(\n `script[${SCRIPT_DATA_ATTR}=\"1\"]`\n ) as HTMLScriptElement | null\n if (existing) {\n logFull('Widget script already in DOM, waiting for load')\n existing.addEventListener('load', () => resolve(), { once: true })\n existing.addEventListener(\n 'error',\n () => reject(new Error('Failed to load widget script')),\n { once: true }\n )\n return\n }\n\n log('Injecting widget script:', src)\n window.__HFCHAT_DISABLE_AUTO_INIT = true\n const script = document.createElement('script')\n script.async = true\n script.src = src\n script.setAttribute(SCRIPT_DATA_ATTR, '1')\n script.setAttribute('data-auto-init', 'false')\n script.onerror = () => {\n logError('Failed to load widget script:', src)\n reject(new Error(`Failed to load widget script: ${src}`))\n }\n script.onload = () => {\n setTimeout(() => {\n if (window.HumanFirstChat) {\n log('Widget script loaded successfully')\n resolve()\n } else {\n logError('Widget script loaded but HumanFirstChat not found')\n reject(new Error('Widget did not attach to window.HumanFirstChat'))\n }\n }, 0)\n }\n document.head.appendChild(script)\n })\n}\n\nasync function loadWidget(opts: HFChatLoaderConfig = {}): Promise<HFChatAPI> {\n if (typeof window === 'undefined') return {} as HFChatAPI\n\n const scriptSrc = opts.scriptSrc ?? DEFAULT_SCRIPT_SRC\n logFull('loadWidget starting with options:', { siteId: opts.siteId, scriptSrc })\n\n await injectScript(scriptSrc)\n\n if (!window.HumanFirstChat?.init) {\n throw new Error('HumanFirstChat.init is not available after script load')\n }\n\n log('Calling HumanFirstChat.init()')\n const api = window.HumanFirstChat.init({\n siteId: opts.siteId,\n hidden: opts.hidden,\n hideOnClose: opts.hideOnClose,\n logs: opts.logs,\n baseURL: opts.baseURL,\n host: opts.host,\n })\n\n const realApi = getRealApi()\n logFull('HumanFirstChat.init() returned:', { hasInstance: (realApi as any)?.__HFCHAT_INSTANCE__ })\n return realApi ?? api\n}\n\nasync function init(opts: HFChatLoaderConfig = {}): Promise<HFChatAPI> {\n if (opts.logs) {\n logLevel = opts.logs\n }\n\n lastInitOpts = { ...lastInitOpts, ...opts }\n log('init() called with options:', { siteId: opts.siteId, logs: opts.logs })\n\n const existingApi = getRealApi()\n if (existingApi) {\n log('Returning existing real API')\n return existingApi\n }\n\n if (loaderPromise) {\n logFull('Returning existing loader promise')\n return loaderPromise\n }\n\n log('Starting widget load...')\n loaderPromise = loadWidget(lastInitOpts)\n return loaderPromise\n}\n\nconst HFChat: HFChatGlobal & { __HFCHAT_STUB__?: true; __real?: HFChatAPI } = {\n init,\n\n show: () => callOrQueue('show', []),\n hide: () => callOrQueue('hide', []),\n open: (options) => callOrQueue('open', [options]),\n close: () => callOrQueue('close', []),\n toggle: () => callOrQueue('toggle', []),\n isOpen: () => {\n const api = getRealApi()\n return api?.isOpen?.() ?? false\n },\n identify: (meta) => callOrQueue('identify', [meta]),\n configure: (settings) => callOrQueue('configure', [settings]),\n onReady: (callback) => {\n if (typeof callback !== 'function') return\n const api = getRealApi()\n if (api?.ready) {\n try {\n callback()\n } catch (error) {\n console.error('[HFChat SDK] Error in onReady callback:', error)\n }\n return\n }\n callOrQueue('onReady', [callback])\n },\n onOpen: (callback) => {\n if (typeof callback !== 'function') return\n callOrQueue('onOpen', [callback])\n },\n onClose: (callback) => {\n if (typeof callback !== 'function') return\n callOrQueue('onClose', [callback])\n },\n get ready() {\n const api = getRealApi()\n return api?.ready ?? false\n },\n}\n\nHFChat.__HFCHAT_STUB__ = true\n\nif (typeof window !== 'undefined') {\n // Expose a stable global singleton, without breaking when the real widget assigns window.HFChat\n if (!window.HFChat) {\n window.HFChat = HFChat\n }\n}\n\nexport { HFChat }\nexport default HFChat\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -16,14 +16,44 @@ function logError(message, ...args) {
|
|
|
16
16
|
}
|
|
17
17
|
var loaderPromise = null;
|
|
18
18
|
var lastInitOpts;
|
|
19
|
-
function
|
|
19
|
+
function getQueue() {
|
|
20
|
+
if (typeof window === "undefined") return [];
|
|
21
|
+
if (!window.__HFCHAT_QUEUE__) {
|
|
22
|
+
window.__HFCHAT_QUEUE__ = [];
|
|
23
|
+
}
|
|
24
|
+
return window.__HFCHAT_QUEUE__;
|
|
25
|
+
}
|
|
26
|
+
function enqueue(method, args) {
|
|
27
|
+
if (typeof window === "undefined") return;
|
|
28
|
+
getQueue().push({ method, args });
|
|
29
|
+
}
|
|
30
|
+
function getRealApi() {
|
|
20
31
|
if (typeof window === "undefined") return null;
|
|
32
|
+
const globalReal = window.__HFCHAT_REAL__;
|
|
33
|
+
if (globalReal && globalReal.__HFCHAT_INSTANCE__ === true) {
|
|
34
|
+
return globalReal;
|
|
35
|
+
}
|
|
21
36
|
const candidate = window.HFChat;
|
|
22
|
-
if (
|
|
23
|
-
|
|
24
|
-
|
|
37
|
+
if (candidate && candidate.__HFCHAT_INSTANCE__ === true) {
|
|
38
|
+
return candidate;
|
|
39
|
+
}
|
|
40
|
+
if (candidate && candidate.__real && candidate.__real.__HFCHAT_INSTANCE__ === true) {
|
|
41
|
+
return candidate.__real;
|
|
42
|
+
}
|
|
25
43
|
return null;
|
|
26
44
|
}
|
|
45
|
+
function callOrQueue(method, args) {
|
|
46
|
+
if (typeof window === "undefined") return;
|
|
47
|
+
const api = getRealApi();
|
|
48
|
+
const fn = api ? api[method] : null;
|
|
49
|
+
if (api && typeof fn === "function") {
|
|
50
|
+
logFull(`Calling '${String(method)}' on real API`);
|
|
51
|
+
fn.apply(api, args);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
logFull(`Queueing '${String(method)}' until real API is ready`);
|
|
55
|
+
enqueue(method, args);
|
|
56
|
+
}
|
|
27
57
|
function injectScript(src) {
|
|
28
58
|
return new Promise((resolve, reject) => {
|
|
29
59
|
if (typeof document === "undefined") return resolve();
|
|
@@ -86,8 +116,9 @@ async function loadWidget(opts = {}) {
|
|
|
86
116
|
baseURL: opts.baseURL,
|
|
87
117
|
host: opts.host
|
|
88
118
|
});
|
|
89
|
-
|
|
90
|
-
|
|
119
|
+
const realApi = getRealApi();
|
|
120
|
+
logFull("HumanFirstChat.init() returned:", { hasInstance: realApi?.__HFCHAT_INSTANCE__ });
|
|
121
|
+
return realApi ?? api;
|
|
91
122
|
}
|
|
92
123
|
async function init(opts = {}) {
|
|
93
124
|
if (opts.logs) {
|
|
@@ -95,7 +126,7 @@ async function init(opts = {}) {
|
|
|
95
126
|
}
|
|
96
127
|
lastInitOpts = { ...lastInitOpts, ...opts };
|
|
97
128
|
log("init() called with options:", { siteId: opts.siteId, logs: opts.logs });
|
|
98
|
-
const existingApi = getRealApi(
|
|
129
|
+
const existingApi = getRealApi();
|
|
99
130
|
if (existingApi) {
|
|
100
131
|
log("Returning existing real API");
|
|
101
132
|
return existingApi;
|
|
@@ -108,84 +139,46 @@ async function init(opts = {}) {
|
|
|
108
139
|
loaderPromise = loadWidget(lastInitOpts);
|
|
109
140
|
return loaderPromise;
|
|
110
141
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
windowHFChat: typeof window.HFChat,
|
|
133
|
-
isProxy: window.HFChat === HFChat
|
|
134
|
-
});
|
|
142
|
+
var HFChat = {
|
|
143
|
+
init,
|
|
144
|
+
show: () => callOrQueue("show", []),
|
|
145
|
+
hide: () => callOrQueue("hide", []),
|
|
146
|
+
open: (options) => callOrQueue("open", [options]),
|
|
147
|
+
close: () => callOrQueue("close", []),
|
|
148
|
+
toggle: () => callOrQueue("toggle", []),
|
|
149
|
+
isOpen: () => {
|
|
150
|
+
const api = getRealApi();
|
|
151
|
+
return api?.isOpen?.() ?? false;
|
|
152
|
+
},
|
|
153
|
+
identify: (meta) => callOrQueue("identify", [meta]),
|
|
154
|
+
configure: (settings) => callOrQueue("configure", [settings]),
|
|
155
|
+
onReady: (callback) => {
|
|
156
|
+
if (typeof callback !== "function") return;
|
|
157
|
+
const api = getRealApi();
|
|
158
|
+
if (api?.ready) {
|
|
159
|
+
try {
|
|
160
|
+
callback();
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error("[HFChat SDK] Error in onReady callback:", error);
|
|
135
163
|
}
|
|
136
|
-
|
|
137
|
-
log(`Method '${methodName}' found after ${attempts} attempts`);
|
|
138
|
-
resolve(api);
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
if (attempts < maxAttempts) {
|
|
142
|
-
attempts += 1;
|
|
143
|
-
setTimeout(checkMethod, 100);
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
logError(`Timeout: '${methodName}' not available after 5 seconds`);
|
|
147
|
-
reject(new Error(`HFChat method '${methodName}' not available after 5 seconds`));
|
|
148
|
-
};
|
|
149
|
-
setTimeout(checkMethod, 100);
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
var HFChat = new Proxy(
|
|
153
|
-
{},
|
|
154
|
-
{
|
|
155
|
-
get(_target, prop) {
|
|
156
|
-
if (prop === "init") return init;
|
|
157
|
-
if (typeof window === "undefined") return () => {
|
|
158
|
-
};
|
|
159
|
-
if (prop === "__HFCHAT_INSTANCE__") return void 0;
|
|
160
|
-
if (prop === "then") return void 0;
|
|
161
|
-
if (prop === "ready") {
|
|
162
|
-
const api = getRealApi(HFChat);
|
|
163
|
-
return !!api?.ready;
|
|
164
|
-
}
|
|
165
|
-
if (prop === "isOpen") {
|
|
166
|
-
return () => {
|
|
167
|
-
const api = getRealApi(HFChat);
|
|
168
|
-
return api?.isOpen?.() ?? false;
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
return (...args) => {
|
|
172
|
-
const methodName = String(prop);
|
|
173
|
-
logFull(`Proxy: '${methodName}' called, forwarding to waitForMethod`);
|
|
174
|
-
waitForMethod(methodName).then((api) => {
|
|
175
|
-
const fn = api[methodName];
|
|
176
|
-
if (typeof fn === "function") {
|
|
177
|
-
logFull(`Proxy: executing '${methodName}' on real API`);
|
|
178
|
-
fn.apply(api, args);
|
|
179
|
-
} else {
|
|
180
|
-
logError(`Method '${methodName}' not found on real API`);
|
|
181
|
-
}
|
|
182
|
-
}).catch((error) => {
|
|
183
|
-
logError(error instanceof Error ? error.message : String(error));
|
|
184
|
-
});
|
|
185
|
-
};
|
|
164
|
+
return;
|
|
186
165
|
}
|
|
166
|
+
callOrQueue("onReady", [callback]);
|
|
167
|
+
},
|
|
168
|
+
onOpen: (callback) => {
|
|
169
|
+
if (typeof callback !== "function") return;
|
|
170
|
+
callOrQueue("onOpen", [callback]);
|
|
171
|
+
},
|
|
172
|
+
onClose: (callback) => {
|
|
173
|
+
if (typeof callback !== "function") return;
|
|
174
|
+
callOrQueue("onClose", [callback]);
|
|
175
|
+
},
|
|
176
|
+
get ready() {
|
|
177
|
+
const api = getRealApi();
|
|
178
|
+
return api?.ready ?? false;
|
|
187
179
|
}
|
|
188
|
-
|
|
180
|
+
};
|
|
181
|
+
HFChat.__HFCHAT_STUB__ = true;
|
|
189
182
|
if (typeof window !== "undefined") {
|
|
190
183
|
if (!window.HFChat) {
|
|
191
184
|
window.HFChat = HFChat;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Re-export public types for consumers\nexport type {\n HFChatLogLevel,\n HFChatConfig,\n HFChatWidgetSettings,\n HFChatIdentifyMeta,\n HFChatOpenOptions,\n HFChatAPI,\n} from './types'\n\nimport type { HFChatConfig, HFChatAPI, HFChatLogLevel } from './types'\n\n// Extended config for the JS SDK loader (adds scriptSrc option)\nexport type HFChatLoaderConfig = HFChatConfig & {\n /** Override widget script source (for self-hosting / testing) */\n scriptSrc?: string\n}\n\nexport type HFChatGlobal = HFChatAPI & {\n /**\n * Load the widget script and initialize the widget.\n */\n init(opts?: HFChatLoaderConfig): Promise<HFChatAPI>\n}\n\ndeclare global {\n interface Window {\n HFChat?: HFChatAPI\n HumanFirstChat?: {\n init: (opts: unknown) => HFChatAPI\n }\n __HFCHAT_DISABLE_AUTO_INIT?: boolean\n }\n}\n\nconst DEFAULT_SCRIPT_SRC = 'https://humanfirst.chat/widget.js'\nconst SCRIPT_DATA_ATTR = 'data-hfchat-widget'\n\n// Logging configuration\nlet logLevel: HFChatLogLevel = 'none'\n\nfunction log(message: string, ...args: unknown[]) {\n if (logLevel === 'none') return\n console.log(`[HFChat SDK] ${message}`, ...args)\n}\n\nfunction logFull(message: string, ...args: unknown[]) {\n if (logLevel !== 'full') return\n console.log(`[HFChat SDK] ${message}`, ...args)\n}\n\nfunction logError(message: string, ...args: unknown[]) {\n if (logLevel === 'none') return\n console.error(`[HFChat SDK] ${message}`, ...args)\n}\n\nlet loaderPromise: Promise<HFChatAPI> | null = null\nlet lastInitOpts: HFChatLoaderConfig | undefined\n\nfunction getRealApi(selfProxy: HFChatGlobal): HFChatAPI | null {\n if (typeof window === 'undefined') return null\n const candidate = window.HFChat\n if (!candidate) return null\n // Check if candidate is the proxy (same reference) - if so, real API not yet available\n if (candidate === selfProxy) return null\n // Check if candidate has the real instance marker\n if ((candidate as any).__HFCHAT_INSTANCE__ === true) return candidate\n return null\n}\n\nfunction injectScript(src: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (typeof document === 'undefined') return resolve()\n if (window.HumanFirstChat) {\n logFull('HumanFirstChat already exists, skipping script injection')\n return resolve()\n }\n\n const existing = document.querySelector(\n `script[${SCRIPT_DATA_ATTR}=\"1\"]`\n ) as HTMLScriptElement | null\n if (existing) {\n logFull('Widget script already in DOM, waiting for load')\n existing.addEventListener('load', () => resolve(), { once: true })\n existing.addEventListener(\n 'error',\n () => reject(new Error('Failed to load widget script')),\n { once: true }\n )\n return\n }\n\n log('Injecting widget script:', src)\n window.__HFCHAT_DISABLE_AUTO_INIT = true\n const script = document.createElement('script')\n script.async = true\n script.src = src\n script.setAttribute(SCRIPT_DATA_ATTR, '1')\n script.setAttribute('data-auto-init', 'false')\n script.onerror = () => {\n logError('Failed to load widget script:', src)\n reject(new Error(`Failed to load widget script: ${src}`))\n }\n script.onload = () => {\n setTimeout(() => {\n if (window.HumanFirstChat) {\n log('Widget script loaded successfully')\n resolve()\n } else {\n logError('Widget script loaded but HumanFirstChat not found')\n reject(new Error('Widget did not attach to window.HumanFirstChat'))\n }\n }, 0)\n }\n document.head.appendChild(script)\n })\n}\n\nasync function loadWidget(opts: HFChatLoaderConfig = {}): Promise<HFChatAPI> {\n if (typeof window === 'undefined') return {} as HFChatAPI\n\n const scriptSrc = opts.scriptSrc ?? DEFAULT_SCRIPT_SRC\n logFull('loadWidget starting with options:', { siteId: opts.siteId, scriptSrc })\n\n await injectScript(scriptSrc)\n\n if (!window.HumanFirstChat?.init) {\n throw new Error('HumanFirstChat.init is not available after script load')\n }\n\n log('Calling HumanFirstChat.init()')\n const api = window.HumanFirstChat.init({\n siteId: opts.siteId,\n hidden: opts.hidden,\n hideOnClose: opts.hideOnClose,\n logs: opts.logs,\n baseURL: opts.baseURL,\n host: opts.host,\n })\n\n logFull('HumanFirstChat.init() returned:', { hasInstance: (api as any)?.__HFCHAT_INSTANCE__ })\n return api\n}\n\nasync function init(opts: HFChatLoaderConfig = {}): Promise<HFChatAPI> {\n // Update log level from options\n if (opts.logs) {\n logLevel = opts.logs\n }\n\n lastInitOpts = { ...lastInitOpts, ...opts }\n log('init() called with options:', { siteId: opts.siteId, logs: opts.logs })\n\n const existingApi = getRealApi(HFChat)\n if (existingApi) {\n log('Returning existing real API')\n return existingApi\n }\n\n if (loaderPromise) {\n logFull('Returning existing loader promise')\n return loaderPromise\n }\n\n log('Starting widget load...')\n loaderPromise = loadWidget(lastInitOpts)\n return loaderPromise\n}\n\nasync function waitForMethod(methodName: string): Promise<HFChatAPI> {\n logFull(`waitForMethod('${methodName}') starting...`)\n\n // Ensure init is called (may already be in progress)\n await init()\n logFull(`init() completed, checking for '${methodName}'`)\n\n // Check if real API is already available\n const existing = getRealApi(HFChat)\n logFull('getRealApi returned:', existing ? 'real API found' : 'null')\n\n if (existing && typeof (existing as any)[methodName] === 'function') {\n log(`Method '${methodName}' available immediately`)\n return existing\n }\n\n // Poll for the real API to become available\n logFull(`Polling for '${methodName}'...`)\n return new Promise((resolve, reject) => {\n let attempts = 0\n const maxAttempts = 50 // 5 seconds total\n\n const checkMethod = () => {\n const api = getRealApi(HFChat)\n const fn = api ? (api as any)[methodName] : null\n\n // Log every 10 attempts (1 second)\n if (attempts % 10 === 0 && attempts > 0) {\n logFull(`Polling attempt ${attempts}/50 for '${methodName}':`, {\n hasApi: !!api,\n hasMethod: !!fn,\n windowHFChat: typeof window.HFChat,\n isProxy: window.HFChat === HFChat\n })\n }\n\n if (api && typeof fn === 'function') {\n log(`Method '${methodName}' found after ${attempts} attempts`)\n resolve(api)\n return\n }\n\n if (attempts < maxAttempts) {\n attempts += 1\n setTimeout(checkMethod, 100)\n return\n }\n\n logError(`Timeout: '${methodName}' not available after 5 seconds`)\n reject(new Error(`HFChat method '${methodName}' not available after 5 seconds`))\n }\n\n setTimeout(checkMethod, 100)\n })\n}\n\nexport const HFChat: HFChatGlobal = new Proxy(\n {},\n {\n get(_target, prop) {\n // Handle init specially - it's the entry point\n if (prop === 'init') return init\n\n // Server-side rendering guard\n if (typeof window === 'undefined') return () => {}\n\n // Handle __HFCHAT_INSTANCE__ check - return undefined so proxy isn't mistaken for real instance\n if (prop === '__HFCHAT_INSTANCE__') return undefined\n\n // Handle 'then' - return undefined so proxy isn't treated as a thenable/Promise\n // This is critical because await/Promise.resolve() check for .then()\n if (prop === 'then') return undefined\n\n // Handle ready property\n if (prop === 'ready') {\n const api = getRealApi(HFChat)\n return !!api?.ready\n }\n\n // Handle isOpen method\n if (prop === 'isOpen') {\n return () => {\n const api = getRealApi(HFChat)\n return api?.isOpen?.() ?? false\n }\n }\n\n // For all other methods, queue them until the real API is ready\n return (...args: unknown[]) => {\n const methodName = String(prop)\n logFull(`Proxy: '${methodName}' called, forwarding to waitForMethod`)\n\n waitForMethod(methodName)\n .then((api) => {\n const fn = (api as any)[methodName]\n if (typeof fn === 'function') {\n logFull(`Proxy: executing '${methodName}' on real API`)\n fn.apply(api, args)\n } else {\n logError(`Method '${methodName}' not found on real API`)\n }\n })\n .catch((error) => {\n logError(error instanceof Error ? error.message : String(error))\n })\n }\n },\n }\n) as HFChatGlobal\n\nif (typeof window !== 'undefined') {\n // Expose a stable global singleton, without breaking when the real widget assigns window.HFChat\n if (!window.HFChat) {\n window.HFChat = HFChat\n }\n}\n\nexport default HFChat\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Re-export public types for consumers\nexport type {\n HFChatLogLevel,\n HFChatConfig,\n HFChatWidgetSettings,\n HFChatIdentifyMeta,\n HFChatOpenOptions,\n HFChatAPI,\n} from './types'\n\nimport type { HFChatConfig, HFChatAPI, HFChatLogLevel } from './types'\n\n// Extended config for the JS SDK loader (adds scriptSrc option)\nexport type HFChatLoaderConfig = HFChatConfig & {\n /** Override widget script source (for self-hosting / testing) */\n scriptSrc?: string\n}\n\nexport type HFChatGlobal = HFChatAPI & {\n /**\n * Load the widget script and initialize the widget.\n */\n init(opts?: HFChatLoaderConfig): Promise<HFChatAPI>\n}\n\ntype QueuedCall = {\n method: keyof HFChatAPI\n args: unknown[]\n}\n\ndeclare global {\n interface Window {\n HFChat?: HFChatAPI\n HumanFirstChat?: {\n init: (opts: unknown) => HFChatAPI\n }\n __HFCHAT_DISABLE_AUTO_INIT?: boolean\n __HFCHAT_QUEUE__?: QueuedCall[]\n __HFCHAT_REAL__?: HFChatAPI\n }\n}\n\nconst DEFAULT_SCRIPT_SRC = 'https://humanfirst.chat/widget.js'\nconst SCRIPT_DATA_ATTR = 'data-hfchat-widget'\n\n// Logging configuration\nlet logLevel: HFChatLogLevel = 'none'\n\nfunction log(message: string, ...args: unknown[]) {\n if (logLevel === 'none') return\n console.log(`[HFChat SDK] ${message}`, ...args)\n}\n\nfunction logFull(message: string, ...args: unknown[]) {\n if (logLevel !== 'full') return\n console.log(`[HFChat SDK] ${message}`, ...args)\n}\n\nfunction logError(message: string, ...args: unknown[]) {\n if (logLevel === 'none') return\n console.error(`[HFChat SDK] ${message}`, ...args)\n}\n\nlet loaderPromise: Promise<HFChatAPI> | null = null\nlet lastInitOpts: HFChatLoaderConfig | undefined\n\nfunction getQueue(): QueuedCall[] {\n if (typeof window === 'undefined') return []\n if (!window.__HFCHAT_QUEUE__) {\n window.__HFCHAT_QUEUE__ = []\n }\n return window.__HFCHAT_QUEUE__\n}\n\nfunction enqueue(method: keyof HFChatAPI, args: unknown[]) {\n if (typeof window === 'undefined') return\n getQueue().push({ method, args })\n}\n\nfunction getRealApi(): HFChatAPI | null {\n if (typeof window === 'undefined') return null\n\n const globalReal = window.__HFCHAT_REAL__\n if (globalReal && (globalReal as any).__HFCHAT_INSTANCE__ === true) {\n return globalReal\n }\n\n const candidate = window.HFChat as any\n if (candidate && candidate.__HFCHAT_INSTANCE__ === true) {\n return candidate as HFChatAPI\n }\n\n if (candidate && candidate.__real && candidate.__real.__HFCHAT_INSTANCE__ === true) {\n return candidate.__real as HFChatAPI\n }\n\n return null\n}\n\nfunction callOrQueue(method: keyof HFChatAPI, args: unknown[]) {\n if (typeof window === 'undefined') return\n const api = getRealApi()\n const fn = api ? (api as any)[method] : null\n\n if (api && typeof fn === 'function') {\n logFull(`Calling '${String(method)}' on real API`)\n fn.apply(api, args)\n return\n }\n\n logFull(`Queueing '${String(method)}' until real API is ready`)\n enqueue(method, args)\n}\n\nfunction injectScript(src: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (typeof document === 'undefined') return resolve()\n if (window.HumanFirstChat) {\n logFull('HumanFirstChat already exists, skipping script injection')\n return resolve()\n }\n\n const existing = document.querySelector(\n `script[${SCRIPT_DATA_ATTR}=\"1\"]`\n ) as HTMLScriptElement | null\n if (existing) {\n logFull('Widget script already in DOM, waiting for load')\n existing.addEventListener('load', () => resolve(), { once: true })\n existing.addEventListener(\n 'error',\n () => reject(new Error('Failed to load widget script')),\n { once: true }\n )\n return\n }\n\n log('Injecting widget script:', src)\n window.__HFCHAT_DISABLE_AUTO_INIT = true\n const script = document.createElement('script')\n script.async = true\n script.src = src\n script.setAttribute(SCRIPT_DATA_ATTR, '1')\n script.setAttribute('data-auto-init', 'false')\n script.onerror = () => {\n logError('Failed to load widget script:', src)\n reject(new Error(`Failed to load widget script: ${src}`))\n }\n script.onload = () => {\n setTimeout(() => {\n if (window.HumanFirstChat) {\n log('Widget script loaded successfully')\n resolve()\n } else {\n logError('Widget script loaded but HumanFirstChat not found')\n reject(new Error('Widget did not attach to window.HumanFirstChat'))\n }\n }, 0)\n }\n document.head.appendChild(script)\n })\n}\n\nasync function loadWidget(opts: HFChatLoaderConfig = {}): Promise<HFChatAPI> {\n if (typeof window === 'undefined') return {} as HFChatAPI\n\n const scriptSrc = opts.scriptSrc ?? DEFAULT_SCRIPT_SRC\n logFull('loadWidget starting with options:', { siteId: opts.siteId, scriptSrc })\n\n await injectScript(scriptSrc)\n\n if (!window.HumanFirstChat?.init) {\n throw new Error('HumanFirstChat.init is not available after script load')\n }\n\n log('Calling HumanFirstChat.init()')\n const api = window.HumanFirstChat.init({\n siteId: opts.siteId,\n hidden: opts.hidden,\n hideOnClose: opts.hideOnClose,\n logs: opts.logs,\n baseURL: opts.baseURL,\n host: opts.host,\n })\n\n const realApi = getRealApi()\n logFull('HumanFirstChat.init() returned:', { hasInstance: (realApi as any)?.__HFCHAT_INSTANCE__ })\n return realApi ?? api\n}\n\nasync function init(opts: HFChatLoaderConfig = {}): Promise<HFChatAPI> {\n if (opts.logs) {\n logLevel = opts.logs\n }\n\n lastInitOpts = { ...lastInitOpts, ...opts }\n log('init() called with options:', { siteId: opts.siteId, logs: opts.logs })\n\n const existingApi = getRealApi()\n if (existingApi) {\n log('Returning existing real API')\n return existingApi\n }\n\n if (loaderPromise) {\n logFull('Returning existing loader promise')\n return loaderPromise\n }\n\n log('Starting widget load...')\n loaderPromise = loadWidget(lastInitOpts)\n return loaderPromise\n}\n\nconst HFChat: HFChatGlobal & { __HFCHAT_STUB__?: true; __real?: HFChatAPI } = {\n init,\n\n show: () => callOrQueue('show', []),\n hide: () => callOrQueue('hide', []),\n open: (options) => callOrQueue('open', [options]),\n close: () => callOrQueue('close', []),\n toggle: () => callOrQueue('toggle', []),\n isOpen: () => {\n const api = getRealApi()\n return api?.isOpen?.() ?? false\n },\n identify: (meta) => callOrQueue('identify', [meta]),\n configure: (settings) => callOrQueue('configure', [settings]),\n onReady: (callback) => {\n if (typeof callback !== 'function') return\n const api = getRealApi()\n if (api?.ready) {\n try {\n callback()\n } catch (error) {\n console.error('[HFChat SDK] Error in onReady callback:', error)\n }\n return\n }\n callOrQueue('onReady', [callback])\n },\n onOpen: (callback) => {\n if (typeof callback !== 'function') return\n callOrQueue('onOpen', [callback])\n },\n onClose: (callback) => {\n if (typeof callback !== 'function') return\n callOrQueue('onClose', [callback])\n },\n get ready() {\n const api = getRealApi()\n return api?.ready ?? false\n },\n}\n\nHFChat.__HFCHAT_STUB__ = true\n\nif (typeof window !== 'undefined') {\n // Expose a stable global singleton, without breaking when the real widget assigns window.HFChat\n if (!window.HFChat) {\n window.HFChat = HFChat\n }\n}\n\nexport { HFChat }\nexport default HFChat\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
"version": "0.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
2
|
+
"name": "@humanfirst-chat/js",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "HumanFirst.chat JavaScript SDK",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"type": "commonjs",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsup",
|
|
16
|
+
"prepublishOnly": "pnpm build",
|
|
17
|
+
"type-check": "tsc --noEmit"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^25.0.8",
|
|
24
|
+
"tsup": "^8.5.1",
|
|
25
|
+
"typescript": "^5.9.3"
|
|
26
|
+
}
|
|
27
27
|
}
|