@uptrademedia/site-kit 1.0.20 → 1.0.24

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.
Files changed (81) hide show
  1. package/dist/analytics/index.js +6 -6
  2. package/dist/analytics/index.mjs +2 -2
  3. package/dist/{chunk-BZBJVG5Y.js → chunk-4KKQQRZV.js} +4 -4
  4. package/dist/{chunk-BZBJVG5Y.js.map → chunk-4KKQQRZV.js.map} +1 -1
  5. package/dist/{chunk-D5VBZVOE.js → chunk-6J26EHDM.js} +79 -30
  6. package/dist/chunk-6J26EHDM.js.map +1 -0
  7. package/dist/{chunk-VDMZZL2O.mjs → chunk-ASVFZY6X.mjs} +4 -4
  8. package/dist/{chunk-VDMZZL2O.mjs.map → chunk-ASVFZY6X.mjs.map} +1 -1
  9. package/dist/{chunk-KBS3KW2U.js → chunk-GKABCBZE.js} +2 -2
  10. package/dist/{chunk-KBS3KW2U.js.map → chunk-GKABCBZE.js.map} +1 -1
  11. package/dist/{chunk-SQHDILBN.js → chunk-HGTTGJVZ.js} +4 -2
  12. package/dist/chunk-HGTTGJVZ.js.map +1 -0
  13. package/dist/{chunk-DOHML47I.mjs → chunk-HHAJAANV.mjs} +46 -4
  14. package/dist/chunk-HHAJAANV.mjs.map +1 -0
  15. package/dist/{chunk-IJVPYQAB.mjs → chunk-JTLOJLWQ.mjs} +3 -50
  16. package/dist/chunk-JTLOJLWQ.mjs.map +1 -0
  17. package/dist/{chunk-BV4YYSAZ.js → chunk-KUGMH4ZF.js} +2 -50
  18. package/dist/chunk-KUGMH4ZF.js.map +1 -0
  19. package/dist/chunk-M5VNAX5I.mjs +54 -0
  20. package/dist/chunk-M5VNAX5I.mjs.map +1 -0
  21. package/dist/{chunk-UWUYO5DJ.mjs → chunk-MDOHOEME.mjs} +80 -31
  22. package/dist/chunk-MDOHOEME.mjs.map +1 -0
  23. package/dist/chunk-MXBDMOVK.js +56 -0
  24. package/dist/chunk-MXBDMOVK.js.map +1 -0
  25. package/dist/{chunk-YHQHSM76.mjs → chunk-OW2C3ATV.mjs} +4 -2
  26. package/dist/chunk-OW2C3ATV.mjs.map +1 -0
  27. package/dist/{chunk-K2HWVOEO.js → chunk-RM4XFDE6.js} +46 -3
  28. package/dist/chunk-RM4XFDE6.js.map +1 -0
  29. package/dist/{chunk-IT6R5VAZ.mjs → chunk-VZHEJXDY.mjs} +2 -2
  30. package/dist/{chunk-IT6R5VAZ.mjs.map → chunk-VZHEJXDY.mjs.map} +1 -1
  31. package/dist/cli/index.js +1 -1
  32. package/dist/cli/index.mjs +1 -1
  33. package/dist/commerce/index.d.mts +1 -1
  34. package/dist/commerce/index.d.ts +1 -1
  35. package/dist/commerce/index.js +42 -38
  36. package/dist/commerce/index.mjs +1 -1
  37. package/dist/engage/index.d.mts +3 -2
  38. package/dist/engage/index.d.ts +3 -2
  39. package/dist/engage/index.js +4 -4
  40. package/dist/engage/index.mjs +1 -1
  41. package/dist/forms/index.js +5 -7
  42. package/dist/forms/index.js.map +1 -1
  43. package/dist/forms/index.mjs +5 -7
  44. package/dist/forms/index.mjs.map +1 -1
  45. package/dist/images/index.d.mts +2 -54
  46. package/dist/images/index.d.ts +2 -54
  47. package/dist/images/index.js +13 -12
  48. package/dist/images/index.mjs +2 -1
  49. package/dist/images/server.d.mts +54 -0
  50. package/dist/images/server.d.ts +54 -0
  51. package/dist/images/server.js +13 -0
  52. package/dist/images/server.js.map +1 -0
  53. package/dist/images/server.mjs +4 -0
  54. package/dist/images/server.mjs.map +1 -0
  55. package/dist/index.d.mts +1 -1
  56. package/dist/index.d.ts +1 -1
  57. package/dist/index.js +43 -42
  58. package/dist/index.js.map +1 -1
  59. package/dist/index.mjs +6 -5
  60. package/dist/index.mjs.map +1 -1
  61. package/dist/redirects/index.js +5 -5
  62. package/dist/redirects/index.mjs +1 -1
  63. package/dist/setup/index.js +2 -2
  64. package/dist/setup/index.mjs +1 -1
  65. package/dist/setup/server.js +2 -2
  66. package/dist/setup/server.mjs +1 -1
  67. package/dist/socket-loader-3FWQWPDQ.js +16 -0
  68. package/dist/socket-loader-3FWQWPDQ.js.map +1 -0
  69. package/dist/socket-loader-N5ETWMXW.mjs +14 -0
  70. package/dist/socket-loader-N5ETWMXW.mjs.map +1 -0
  71. package/dist/{useEventModal-CaePVcfW.d.ts → useEventModal-DHO4-xhg.d.ts} +6 -1
  72. package/dist/{useEventModal-Dt6y1L0o.d.mts → useEventModal-Dbg2fYYk.d.mts} +6 -1
  73. package/package.json +6 -1
  74. package/dist/chunk-BV4YYSAZ.js.map +0 -1
  75. package/dist/chunk-D5VBZVOE.js.map +0 -1
  76. package/dist/chunk-DOHML47I.mjs.map +0 -1
  77. package/dist/chunk-IJVPYQAB.mjs.map +0 -1
  78. package/dist/chunk-K2HWVOEO.js.map +0 -1
  79. package/dist/chunk-SQHDILBN.js.map +0 -1
  80. package/dist/chunk-UWUYO5DJ.mjs.map +0 -1
  81. package/dist/chunk-YHQHSM76.mjs.map +0 -1
@@ -1,13 +1,13 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkSQHDILBN_js = require('../chunk-SQHDILBN.js');
4
+ var chunkHGTTGJVZ_js = require('../chunk-HGTTGJVZ.js');
5
5
  require('../chunk-ZSMWDLMK.js');
6
6
  var react = require('react');
7
7
 
8
8
  function useContactTracking(options = {}) {
9
9
  const { autoTrack = true, debug = false } = options;
10
- const { trackConversion } = chunkSQHDILBN_js.useAnalytics();
10
+ const { trackConversion } = chunkHGTTGJVZ_js.useAnalytics();
11
11
  const trackPhoneClick = react.useCallback((phoneNumber, metadata) => {
12
12
  if (debug) console.log("[Analytics] Phone click:", phoneNumber);
13
13
  trackConversion({
@@ -69,19 +69,19 @@ function ContactTracking({ debug = false }) {
69
69
 
70
70
  Object.defineProperty(exports, "AnalyticsProvider", {
71
71
  enumerable: true,
72
- get: function () { return chunkSQHDILBN_js.AnalyticsProvider; }
72
+ get: function () { return chunkHGTTGJVZ_js.AnalyticsProvider; }
73
73
  });
74
74
  Object.defineProperty(exports, "WebVitals", {
75
75
  enumerable: true,
76
- get: function () { return chunkSQHDILBN_js.WebVitals; }
76
+ get: function () { return chunkHGTTGJVZ_js.WebVitals; }
77
77
  });
78
78
  Object.defineProperty(exports, "useAnalytics", {
79
79
  enumerable: true,
80
- get: function () { return chunkSQHDILBN_js.useAnalytics; }
80
+ get: function () { return chunkHGTTGJVZ_js.useAnalytics; }
81
81
  });
82
82
  Object.defineProperty(exports, "useTrackEvent", {
83
83
  enumerable: true,
84
- get: function () { return chunkSQHDILBN_js.useTrackEvent; }
84
+ get: function () { return chunkHGTTGJVZ_js.useTrackEvent; }
85
85
  });
86
86
  exports.ContactTracking = ContactTracking;
87
87
  exports.useContactTracking = useContactTracking;
@@ -1,6 +1,6 @@
1
1
  'use client';
2
- import { useAnalytics } from '../chunk-YHQHSM76.mjs';
3
- export { AnalyticsProvider, WebVitals, useAnalytics, useTrackEvent } from '../chunk-YHQHSM76.mjs';
2
+ import { useAnalytics } from '../chunk-OW2C3ATV.mjs';
3
+ export { AnalyticsProvider, WebVitals, useAnalytics, useTrackEvent } from '../chunk-OW2C3ATV.mjs';
4
4
  import '../chunk-4XPGGLVP.mjs';
5
5
  import { useCallback, useEffect } from 'react';
6
6
 
@@ -14,7 +14,7 @@ async function fetchRedirectRules(config) {
14
14
  try {
15
15
  const baseUrl = config.portalApiUrl || "https://api.uptrademedia.com";
16
16
  const domain = config.domain || "";
17
- const url = `${baseUrl}/public/seo/redirects?domain=${encodeURIComponent(domain)}`;
17
+ const url = `${baseUrl}/api/public/seo/redirects?domain=${encodeURIComponent(domain)}`;
18
18
  const res = await fetch(url, {
19
19
  headers: { "Content-Type": "application/json" },
20
20
  next: { revalidate: cacheSeconds }
@@ -59,7 +59,7 @@ async function handleManagedRedirects(request, config) {
59
59
  async function trackRedirectHit(config, fromPath) {
60
60
  try {
61
61
  const baseUrl = config.portalApiUrl || "https://api.uptrademedia.com";
62
- await fetch(`${baseUrl}/public/seo/redirects/hit`, {
62
+ await fetch(`${baseUrl}/api/public/seo/redirects/hit`, {
63
63
  method: "POST",
64
64
  headers: { "Content-Type": "application/json" },
65
65
  body: JSON.stringify({ domain: config.domain, from_path: fromPath })
@@ -84,5 +84,5 @@ exports.clearRedirectCache = clearRedirectCache;
84
84
  exports.fetchRedirectRules = fetchRedirectRules;
85
85
  exports.generateNextRedirects = generateNextRedirects;
86
86
  exports.handleManagedRedirects = handleManagedRedirects;
87
- //# sourceMappingURL=chunk-BZBJVG5Y.js.map
88
- //# sourceMappingURL=chunk-BZBJVG5Y.js.map
87
+ //# sourceMappingURL=chunk-4KKQQRZV.js.map
88
+ //# sourceMappingURL=chunk-4KKQQRZV.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/redirects/index.ts"],"names":["NextResponse"],"mappings":"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","file":"chunk-BZBJVG5Y.js","sourcesContent":["/**\n * Managed Redirects - Next.js Middleware Helper\n * \n * Fetches redirect rules from Uptrade Portal and applies them.\n * Can be used in middleware.ts for server-side redirects.\n * \n * Usage in middleware.ts:\n * \n * import { handleManagedRedirects } from '@uptrade/site-kit/redirects'\n * \n * export async function middleware(request: NextRequest) {\n * const redirect = await handleManagedRedirects(request, {\n * domain: 'example.com', // Your site's domain (without https://)\n * portalApiUrl: process.env.PORTAL_API_URL || 'https://api.uptrademedia.com',\n * })\n * \n * if (redirect) return redirect\n * \n * return NextResponse.next()\n * }\n */\n\nimport { NextRequest, NextResponse } from 'next/server'\n\nexport interface RedirectRule {\n from_path: string\n to_path: string\n redirect_type: '301' | '302' | '307' | '308'\n is_enabled: boolean\n}\n\nexport interface RedirectConfig {\n domain: string // Required: the domain to fetch redirects for\n portalApiUrl?: string\n cacheSeconds?: number\n}\n\n// Cache for redirect rules\nlet cachedRules: RedirectRule[] = []\nlet cacheExpiry = 0\n\n/**\n * Fetch redirect rules from Portal API\n */\nexport async function fetchRedirectRules(config: RedirectConfig): Promise<RedirectRule[]> {\n const now = Date.now()\n const cacheSeconds = config.cacheSeconds ?? 300 // 5 min default\n\n // Return cached if still valid\n if (cachedRules.length > 0 && now < cacheExpiry) {\n return cachedRules\n }\n\n try {\n const baseUrl = config.portalApiUrl || 'https://api.uptrademedia.com'\n // Use domain-based lookup from public endpoint (no auth required)\n const domain = config.domain || ''\n const url = `${baseUrl}/public/seo/redirects?domain=${encodeURIComponent(domain)}`\n\n const res = await fetch(url, {\n headers: { 'Content-Type': 'application/json' },\n next: { revalidate: cacheSeconds },\n })\n\n if (!res.ok) {\n console.error(`[site-kit] Failed to fetch redirects: ${res.status}`)\n return cachedRules\n }\n\n const data = await res.json()\n cachedRules = (data.redirects || []).filter((r: RedirectRule) => r.is_enabled)\n cacheExpiry = now + (cacheSeconds * 1000)\n \n return cachedRules\n } catch (error) {\n console.error('[site-kit] Error fetching redirects:', error)\n return cachedRules\n }\n}\n\n/**\n * Handle managed redirects in middleware\n * Returns a NextResponse.redirect if a match is found, otherwise undefined\n */\nexport async function handleManagedRedirects(\n request: NextRequest,\n config: RedirectConfig,\n): Promise<NextResponse | undefined> {\n const pathname = request.nextUrl.pathname\n \n // Skip for static assets and API routes\n if (\n pathname.startsWith('/_next') ||\n pathname.startsWith('/api') ||\n pathname.includes('.') // Has file extension\n ) {\n return undefined\n }\n\n const rules = await fetchRedirectRules(config)\n \n // Find matching redirect\n const match = rules.find(r => {\n // Exact match\n if (r.from_path === pathname) return true\n \n // Match with trailing slash variance\n const normalizedFrom = r.from_path.endsWith('/') \n ? r.from_path.slice(0, -1) \n : r.from_path\n const normalizedPath = pathname.endsWith('/') \n ? pathname.slice(0, -1) \n : pathname\n \n return normalizedFrom === normalizedPath\n })\n\n if (!match) {\n return undefined\n }\n\n // Build redirect URL\n const redirectUrl = new URL(match.to_path, request.url)\n \n // Preserve query params\n request.nextUrl.searchParams.forEach((value, key) => {\n redirectUrl.searchParams.set(key, value)\n })\n\n // Track hit (fire and forget)\n trackRedirectHit(config, match.from_path).catch(() => {})\n\n // Return redirect response\n const statusCode = parseInt(match.redirect_type) as 301 | 302 | 307 | 308\n return NextResponse.redirect(redirectUrl, statusCode)\n}\n\n/**\n * Track redirect hit for analytics\n */\nasync function trackRedirectHit(config: RedirectConfig, fromPath: string): Promise<void> {\n try {\n const baseUrl = config.portalApiUrl || 'https://api.uptrademedia.com'\n await fetch(`${baseUrl}/public/seo/redirects/hit`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ domain: config.domain, from_path: fromPath }),\n })\n } catch {\n // Ignore tracking errors\n }\n}\n\n/**\n * Generate Next.js redirects config from Portal\n * Use this in next.config.js for build-time redirects\n * \n * Usage in next.config.js:\n * \n * const { generateNextRedirects } = require('@uptrade/site-kit/redirects')\n * \n * module.exports = {\n * async redirects() {\n * return generateNextRedirects({\n * domain: 'example.com',\n * portalApiUrl: process.env.PORTAL_API_URL,\n * })\n * }\n * }\n */\nexport async function generateNextRedirects(config: RedirectConfig): Promise<Array<{\n source: string\n destination: string\n permanent: boolean\n}>> {\n const rules = await fetchRedirectRules({ ...config, cacheSeconds: 0 })\n \n return rules.map(r => ({\n source: r.from_path,\n destination: r.to_path,\n permanent: r.redirect_type === '301' || r.redirect_type === '308',\n }))\n}\n\n/**\n * Clear redirect cache (useful for development)\n */\nexport function clearRedirectCache(): void {\n cachedRules = []\n cacheExpiry = 0\n}\n"]}
1
+ {"version":3,"sources":["../src/redirects/index.ts"],"names":["NextResponse"],"mappings":"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","file":"chunk-4KKQQRZV.js","sourcesContent":["/**\n * Managed Redirects - Next.js Middleware Helper\n * \n * Fetches redirect rules from Uptrade Portal and applies them.\n * Can be used in middleware.ts for server-side redirects.\n * \n * Usage in middleware.ts:\n * \n * import { handleManagedRedirects } from '@uptrade/site-kit/redirects'\n * \n * export async function middleware(request: NextRequest) {\n * const redirect = await handleManagedRedirects(request, {\n * domain: 'example.com', // Your site's domain (without https://)\n * portalApiUrl: process.env.PORTAL_API_URL || 'https://api.uptrademedia.com',\n * })\n * \n * if (redirect) return redirect\n * \n * return NextResponse.next()\n * }\n */\n\nimport { NextRequest, NextResponse } from 'next/server'\n\nexport interface RedirectRule {\n from_path: string\n to_path: string\n redirect_type: '301' | '302' | '307' | '308'\n is_enabled: boolean\n}\n\nexport interface RedirectConfig {\n domain: string // Required: the domain to fetch redirects for\n portalApiUrl?: string\n cacheSeconds?: number\n}\n\n// Cache for redirect rules\nlet cachedRules: RedirectRule[] = []\nlet cacheExpiry = 0\n\n/**\n * Fetch redirect rules from Portal API\n */\nexport async function fetchRedirectRules(config: RedirectConfig): Promise<RedirectRule[]> {\n const now = Date.now()\n const cacheSeconds = config.cacheSeconds ?? 300 // 5 min default\n\n // Return cached if still valid\n if (cachedRules.length > 0 && now < cacheExpiry) {\n return cachedRules\n }\n\n try {\n const baseUrl = config.portalApiUrl || 'https://api.uptrademedia.com'\n // Use domain-based lookup from public endpoint (no auth required)\n const domain = config.domain || ''\n const url = `${baseUrl}/api/public/seo/redirects?domain=${encodeURIComponent(domain)}`\n\n const res = await fetch(url, {\n headers: { 'Content-Type': 'application/json' },\n next: { revalidate: cacheSeconds },\n })\n\n if (!res.ok) {\n console.error(`[site-kit] Failed to fetch redirects: ${res.status}`)\n return cachedRules\n }\n\n const data = await res.json()\n cachedRules = (data.redirects || []).filter((r: RedirectRule) => r.is_enabled)\n cacheExpiry = now + (cacheSeconds * 1000)\n \n return cachedRules\n } catch (error) {\n console.error('[site-kit] Error fetching redirects:', error)\n return cachedRules\n }\n}\n\n/**\n * Handle managed redirects in middleware\n * Returns a NextResponse.redirect if a match is found, otherwise undefined\n */\nexport async function handleManagedRedirects(\n request: NextRequest,\n config: RedirectConfig,\n): Promise<NextResponse | undefined> {\n const pathname = request.nextUrl.pathname\n \n // Skip for static assets and API routes\n if (\n pathname.startsWith('/_next') ||\n pathname.startsWith('/api') ||\n pathname.includes('.') // Has file extension\n ) {\n return undefined\n }\n\n const rules = await fetchRedirectRules(config)\n \n // Find matching redirect\n const match = rules.find(r => {\n // Exact match\n if (r.from_path === pathname) return true\n \n // Match with trailing slash variance\n const normalizedFrom = r.from_path.endsWith('/') \n ? r.from_path.slice(0, -1) \n : r.from_path\n const normalizedPath = pathname.endsWith('/') \n ? pathname.slice(0, -1) \n : pathname\n \n return normalizedFrom === normalizedPath\n })\n\n if (!match) {\n return undefined\n }\n\n // Build redirect URL\n const redirectUrl = new URL(match.to_path, request.url)\n \n // Preserve query params\n request.nextUrl.searchParams.forEach((value, key) => {\n redirectUrl.searchParams.set(key, value)\n })\n\n // Track hit (fire and forget)\n trackRedirectHit(config, match.from_path).catch(() => {})\n\n // Return redirect response\n const statusCode = parseInt(match.redirect_type) as 301 | 302 | 307 | 308\n return NextResponse.redirect(redirectUrl, statusCode)\n}\n\n/**\n * Track redirect hit for analytics\n */\nasync function trackRedirectHit(config: RedirectConfig, fromPath: string): Promise<void> {\n try {\n const baseUrl = config.portalApiUrl || 'https://api.uptrademedia.com'\n await fetch(`${baseUrl}/api/public/seo/redirects/hit`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ domain: config.domain, from_path: fromPath }),\n })\n } catch {\n // Ignore tracking errors\n }\n}\n\n/**\n * Generate Next.js redirects config from Portal\n * Use this in next.config.js for build-time redirects\n * \n * Usage in next.config.js:\n * \n * const { generateNextRedirects } = require('@uptrade/site-kit/redirects')\n * \n * module.exports = {\n * async redirects() {\n * return generateNextRedirects({\n * domain: 'example.com',\n * portalApiUrl: process.env.PORTAL_API_URL,\n * })\n * }\n * }\n */\nexport async function generateNextRedirects(config: RedirectConfig): Promise<Array<{\n source: string\n destination: string\n permanent: boolean\n}>> {\n const rules = await fetchRedirectRules({ ...config, cacheSeconds: 0 })\n \n return rules.map(r => ({\n source: r.from_path,\n destination: r.to_path,\n permanent: r.redirect_type === '301' || r.redirect_type === '308',\n }))\n}\n\n/**\n * Clear redirect cache (useful for development)\n */\nexport function clearRedirectCache(): void {\n cachedRules = []\n cacheExpiry = 0\n}\n"]}
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  var React2 = require('react');
4
- var socket_ioClient = require('socket.io-client');
5
4
  var jsxRuntime = require('react/jsx-runtime');
6
5
  var navigation = require('next/navigation');
7
6
 
@@ -36,7 +35,9 @@ function isLightColor(hex) {
36
35
  const b = num & 255;
37
36
  return (r * 299 + g * 587 + b * 114) / 1e3 > 160;
38
37
  }
39
- function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
38
+ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl }) {
39
+ const [resolvedProjectId, setResolvedProjectId] = React2.useState(propProjectId || null);
40
+ const projectId = propProjectId || resolvedProjectId || "";
40
41
  const [isOpen, setIsOpen] = React2.useState(false);
41
42
  const [messages, setMessages] = React2.useState([]);
42
43
  const [inputValue, setInputValue] = React2.useState("");
@@ -56,6 +57,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
56
57
  const [showWelcome, setShowWelcome] = React2.useState(true);
57
58
  const [checkingAvailability, setCheckingAvailability] = React2.useState(false);
58
59
  React2.useRef(null);
60
+ const pendingInitialMessageRef = React2.useRef(null);
59
61
  const messagesEndRef = React2.useRef(null);
60
62
  const inputRef = React2.useRef(null);
61
63
  const socketRef = React2.useRef(null);
@@ -72,7 +74,24 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
72
74
  const offlineHeading = widgetConfig?.offline_heading ?? "No agents available right now";
73
75
  const offlineSubheading = handoffOfflinePrompt ?? widgetConfig?.offline_subheading ?? widgetConfig?.form_description ?? widgetConfig?.offline_message ?? config?.offlineMessage ?? "Leave us a message and we'll get back to you!";
74
76
  const baseUrl = propApiUrl || getApiConfig().apiUrl;
77
+ React2.useEffect(() => {
78
+ if (propProjectId || resolvedProjectId) return;
79
+ const { apiKey } = getApiConfig();
80
+ if (!apiKey) return;
81
+ let cancelled = false;
82
+ fetch(`${baseUrl}/api/public/seo/project-info`, {
83
+ headers: { "x-api-key": apiKey }
84
+ }).then((res) => res.ok ? res.json() : null).then((data) => {
85
+ if (cancelled || !data?.valid || !data?.project_id) return;
86
+ setResolvedProjectId(data.project_id);
87
+ }).catch(() => {
88
+ });
89
+ return () => {
90
+ cancelled = true;
91
+ };
92
+ }, [propProjectId, resolvedProjectId, baseUrl]);
75
93
  const fetchWidgetConfig = React2.useCallback(async () => {
94
+ if (!projectId) return;
76
95
  try {
77
96
  const { apiKey } = getApiConfig();
78
97
  const response = await fetch(`${baseUrl}/engage/widget/config?projectId=${projectId}`, {
@@ -83,10 +102,13 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
83
102
  setWidgetConfig(data ?? null);
84
103
  }
85
104
  } catch (error) {
86
- console.error("[ChatWidget] Config fetch failed:", error);
105
+ if (process.env.NODE_ENV === "development") {
106
+ console.warn("[ChatWidget] Config fetch failed:", error instanceof Error ? error.message : error);
107
+ }
87
108
  }
88
109
  }, [projectId, baseUrl]);
89
110
  const checkAvailability = React2.useCallback(async () => {
111
+ if (!projectId) return null;
90
112
  try {
91
113
  const { apiKey } = getApiConfig();
92
114
  const response = await fetch(`${baseUrl}/engage/widget/availability?projectId=${projectId}`, {
@@ -98,7 +120,9 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
98
120
  return data;
99
121
  }
100
122
  } catch (error) {
101
- console.error("[ChatWidget] Availability check failed:", error);
123
+ if (process.env.NODE_ENV === "development") {
124
+ console.warn("[ChatWidget] Availability check failed:", error instanceof Error ? error.message : error);
125
+ }
102
126
  }
103
127
  return null;
104
128
  }, [projectId, baseUrl]);
@@ -186,14 +210,15 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
186
210
  }
187
211
  }, []);
188
212
  const connectSocket = React2.useCallback(
189
- (currentSessionId) => {
213
+ async (currentSessionId) => {
190
214
  if (socketRef.current?.connected) return;
191
215
  if (socketRef.current) {
192
216
  socketRef.current.disconnect();
193
217
  socketRef.current = null;
194
218
  }
219
+ const { createSocket } = await import('./socket-loader-3FWQWPDQ.js');
195
220
  const namespaceUrl = `${baseUrl.replace(/\/$/, "")}/engage/chat`;
196
- const socket = socket_ioClient.io(namespaceUrl, {
221
+ const socket = await createSocket(namespaceUrl, {
197
222
  query: { projectId, visitorId, sessionId: currentSessionId },
198
223
  transports: ["websocket", "polling"],
199
224
  // Auto-reconnect config
@@ -320,18 +345,35 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
320
345
  };
321
346
  }, [fetchWidgetConfig, checkAvailability]);
322
347
  React2.useEffect(() => {
323
- if (isOpen && !showWelcome && !checkingAvailability && !showOfflineForm && !sessionId && availability?.mode !== "offline") {
324
- initSession().then((id) => {
325
- if (id && (availability?.mode === "live" || availability?.mode === "ai")) {
326
- setConnectionStatus("connecting");
327
- connectSocket(id);
348
+ if (isOpen && !showWelcome && !checkingAvailability && !showOfflineForm && !sessionId) {
349
+ initSession().then(async (id) => {
350
+ if (!id) return;
351
+ setConnectionStatus("connecting");
352
+ await connectSocket(id);
353
+ const pending = pendingInitialMessageRef.current;
354
+ if (pending) {
355
+ pendingInitialMessageRef.current = null;
356
+ const waitForSocket = () => new Promise((resolve) => {
357
+ const check = (attempts = 0) => {
358
+ if (socketRef.current?.connected || attempts > 20) {
359
+ resolve();
360
+ return;
361
+ }
362
+ setTimeout(() => check(attempts + 1), 150);
363
+ };
364
+ check();
365
+ });
366
+ await waitForSocket();
367
+ if (socketRef.current?.connected) {
368
+ socketRef.current.emit("visitor:message", { content: pending });
369
+ }
328
370
  }
329
371
  });
330
372
  }
331
373
  return () => {
332
374
  if (pollingIntervalRef.current) clearInterval(pollingIntervalRef.current);
333
375
  };
334
- }, [isOpen, showWelcome, checkingAvailability, showOfflineForm, sessionId, availability?.mode, initSession, connectSocket]);
376
+ }, [isOpen, showWelcome, checkingAvailability, showOfflineForm, sessionId, initSession, connectSocket]);
335
377
  const handleToggle = React2.useCallback(() => {
336
378
  setIsOpen((prev) => !prev);
337
379
  }, []);
@@ -341,17 +383,13 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
341
383
  const beginChatSession = () => {
342
384
  setMessages([{ id: "welcome", role: "assistant", content: welcomeMessage, timestamp: /* @__PURE__ */ new Date() }]);
343
385
  if (initialMessage) {
344
- setInputValue(initialMessage);
345
- setTimeout(() => {
346
- setInputValue("");
347
- const userMsg = { id: `user-${Date.now()}`, role: "user", content: initialMessage, timestamp: /* @__PURE__ */ new Date() };
348
- setMessages((prev) => [...prev, userMsg]);
349
- setIsLoading(true);
350
- setLastFailedSend({ content: initialMessage, attachments: [] });
351
- }, 100);
386
+ pendingInitialMessageRef.current = initialMessage;
387
+ const userMsg = { id: `user-${Date.now()}`, role: "user", content: initialMessage, timestamp: /* @__PURE__ */ new Date() };
388
+ setMessages((prev) => [...prev, userMsg]);
389
+ setIsLoading(true);
352
390
  }
353
391
  };
354
- if (availability?.mode === "ai") {
392
+ if (widgetConfig?.signal_enabled) {
355
393
  beginChatSession();
356
394
  return;
357
395
  }
@@ -371,7 +409,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
371
409
  setShowOfflineForm(true);
372
410
  }
373
411
  },
374
- [availability, welcomeMessage, checkAvailability]
412
+ [widgetConfig?.signal_enabled, welcomeMessage, checkAvailability]
375
413
  );
376
414
  const uploadWidgetFile = React2.useCallback(
377
415
  async (file) => {
@@ -485,11 +523,13 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
485
523
  console.error("[ChatWidget] Handoff request failed:", error);
486
524
  }
487
525
  }, [sessionId, baseUrl, projectId, widgetConfig, offlineHeading]);
526
+ const [offlineError, setOfflineError] = React2.useState(null);
488
527
  const handleOfflineSubmit = React2.useCallback(
489
528
  async (e) => {
490
529
  e.preventDefault();
491
530
  if (!offlineForm.name || !offlineForm.email || !offlineForm.message) return;
492
531
  setIsLoading(true);
532
+ setOfflineError(null);
493
533
  try {
494
534
  const { apiKey } = getApiConfig();
495
535
  const response = await fetch(`${baseUrl}/engage/widget/offline-form`, {
@@ -503,9 +543,16 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
503
543
  ...widgetConfig?.offlineFormSlug && { formSlug: widgetConfig.offlineFormSlug }
504
544
  })
505
545
  });
506
- if (response.ok) setOfflineSubmitted(true);
546
+ if (response.ok) {
547
+ setOfflineSubmitted(true);
548
+ } else {
549
+ const errorBody = await response.text().catch(() => "");
550
+ console.error(`[ChatWidget] Offline form returned ${response.status}:`, errorBody);
551
+ setOfflineError("Something went wrong. Please try again.");
552
+ }
507
553
  } catch (error) {
508
554
  console.error("[ChatWidget] Offline form submission failed:", error);
555
+ setOfflineError("Unable to send message. Please check your connection and try again.");
509
556
  } finally {
510
557
  setIsLoading(false);
511
558
  }
@@ -529,9 +576,9 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
529
576
  }, []);
530
577
  const statusLabel = (() => {
531
578
  if (showOfflineForm) return null;
532
- if (checkingAvailability) return { dot: "#f59e0b", text: "Checking availability..." };
533
- if (availability?.mode === "live" && availability.agentsOnline > 0) return { dot: "#22c55e", text: "Online" };
534
- if (availability?.mode === "ai") return { dot: "#a78bfa", text: "AI Assistant" };
579
+ if (checkingAvailability) return { dot: "#f59e0b", text: "Checking for a team member..." };
580
+ if (widgetConfig?.signal_enabled) return { dot: "#a78bfa", text: "AI Assistant" };
581
+ if (availability && availability.agentsOnline > 0) return { dot: "#22c55e", text: "Online" };
535
582
  return { dot: "#9ca3af", text: "We'll respond soon" };
536
583
  })();
537
584
  const ChatButton = /* @__PURE__ */ jsxRuntime.jsx(
@@ -705,6 +752,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
705
752
  onBlur: (e) => e.currentTarget.style.borderColor = "#e5e7eb"
706
753
  }
707
754
  ) }),
755
+ offlineError && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "8px 12px", borderRadius: 8, backgroundColor: "#fef2f2", border: "1px solid #fecaca", color: "#dc2626", fontSize: 13, marginBottom: 12 }, children: offlineError }),
708
756
  /* @__PURE__ */ jsxRuntime.jsx(
709
757
  "button",
710
758
  {
@@ -774,7 +822,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
774
822
  )
775
823
  ] }),
776
824
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
777
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 16, fontWeight: 600, color: "#111827", marginBottom: 6 }, children: "Checking if any agents are available" }),
825
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 16, fontWeight: 600, color: "#111827", marginBottom: 6 }, children: "Checking for a team member" }),
778
826
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: 14, color: "#6b7280", lineHeight: 1.5 }, children: [
779
827
  "One moment please",
780
828
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: { display: "inline-flex", width: 20 }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { animation: "checkDots 1.5s infinite steps(4, end)" }, children: "..." }) })
@@ -856,7 +904,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
856
904
  children: "Retry send"
857
905
  }
858
906
  ) }),
859
- message.role === "assistant" && widgetConfig?.handoff_enabled !== false && messages.filter((m) => m.role === "user").length >= 2 && message.id === messages.filter((m) => m.role === "assistant").slice(-1)[0]?.id && /* @__PURE__ */ jsxRuntime.jsx(
907
+ widgetConfig?.signal_enabled && message.role === "assistant" && !message.suggestions?.length && widgetConfig?.handoff_enabled !== false && messages.filter((m) => m.role === "user").length >= 2 && message.id === messages.filter((m) => m.role === "assistant").slice(-1)[0]?.id && /* @__PURE__ */ jsxRuntime.jsx(
860
908
  "button",
861
909
  {
862
910
  onClick: requestHandoff,
@@ -1010,6 +1058,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
1010
1058
  ]
1011
1059
  }
1012
1060
  );
1061
+ if (!projectId) return null;
1013
1062
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1014
1063
  ChatPopup,
1015
1064
  ChatButton
@@ -1632,5 +1681,5 @@ function getDeviceType() {
1632
1681
  exports.ChatWidget = ChatWidget;
1633
1682
  exports.DesignRenderer = DesignRenderer;
1634
1683
  exports.EngageWidget = EngageWidget;
1635
- //# sourceMappingURL=chunk-D5VBZVOE.js.map
1636
- //# sourceMappingURL=chunk-D5VBZVOE.js.map
1684
+ //# sourceMappingURL=chunk-6J26EHDM.js.map
1685
+ //# sourceMappingURL=chunk-6J26EHDM.js.map