@weldsuite/helpdesk-widget-sdk 1.0.16 → 1.0.17

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.esm.js CHANGED
@@ -31,32 +31,6 @@ const DEFAULT_CONFIG = {
31
31
  closeOnClick: true,
32
32
  },
33
33
  },
34
- customization: {
35
- primaryColor: '#000000',
36
- accentColor: '#3b82f6',
37
- backgroundColor: '#ffffff',
38
- textColor: '#111827',
39
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
40
- fontSize: '14px',
41
- borderRadius: '12px',
42
- },
43
- features: {
44
- attachments: true,
45
- reactions: true,
46
- typing: true,
47
- readReceipts: true,
48
- offlineMode: false,
49
- fileUpload: true,
50
- imageUpload: true,
51
- voiceMessages: false,
52
- videoMessages: false,
53
- },
54
- mobile: {
55
- fullScreen: true,
56
- scrollLock: true,
57
- keyboardHandling: 'auto',
58
- safeAreaInsets: true,
59
- },
60
34
  auth: {
61
35
  enabled: true,
62
36
  mode: 'anonymous',
@@ -100,6 +74,7 @@ function resolveConfig(config) {
100
74
  validateConfig(config);
101
75
  return {
102
76
  widgetId: config.widgetId,
77
+ testMode: config.testMode,
103
78
  api: {
104
79
  ...DEFAULT_CONFIG.api,
105
80
  widgetId: config.widgetId,
@@ -129,18 +104,6 @@ function resolveConfig(config) {
129
104
  ...config.iframes?.backdrop,
130
105
  },
131
106
  },
132
- customization: {
133
- ...DEFAULT_CONFIG.customization,
134
- ...config.customization,
135
- },
136
- features: {
137
- ...DEFAULT_CONFIG.features,
138
- ...config.features,
139
- },
140
- mobile: {
141
- ...DEFAULT_CONFIG.mobile,
142
- ...config.mobile,
143
- },
144
107
  auth: {
145
108
  ...DEFAULT_CONFIG.auth,
146
109
  ...config.auth,
@@ -383,6 +346,8 @@ class IframeManager {
383
346
  this.modalContainer = null;
384
347
  this.styleElement = null;
385
348
  this.messageBroker = null;
349
+ // Guard flag to prevent double-binding event listeners
350
+ this.eventListenersBound = false;
386
351
  this.config = config;
387
352
  this.logger = new Logger(config.logging);
388
353
  this.deviceInfo = detectDevice();
@@ -422,18 +387,27 @@ class IframeManager {
422
387
  }
423
388
  /**
424
389
  * Create root container structure
390
+ * Reuses existing container if it has the same widgetId (singleton behavior)
425
391
  */
426
392
  createRootContainer() {
427
- // Check if already exists
428
- let existingContainer = document.getElementById('weld-container');
393
+ const existingContainer = document.getElementById('weld-container');
429
394
  if (existingContainer) {
430
- this.logger.warn('Weld container already exists, removing old instance');
395
+ // Reuse if same widgetId
396
+ if (existingContainer.getAttribute('data-widget-id') === this.config.widgetId) {
397
+ this.logger.debug('Reusing existing root container');
398
+ this.rootContainer = existingContainer;
399
+ this.appContainer = existingContainer.querySelector('.weld-app');
400
+ this.modalContainer = document.getElementById('weld-modal-container');
401
+ return;
402
+ }
403
+ this.logger.warn('Weld container already exists with different widgetId, removing old instance');
431
404
  existingContainer.remove();
432
405
  }
433
406
  // Create root container
434
407
  this.rootContainer = document.createElement('div');
435
408
  this.rootContainer.id = 'weld-container';
436
409
  this.rootContainer.className = 'weld-namespace';
410
+ this.rootContainer.setAttribute('data-widget-id', this.config.widgetId);
437
411
  // Create app container
438
412
  this.appContainer = document.createElement('div');
439
413
  this.appContainer.className = 'weld-app';
@@ -468,17 +442,7 @@ class IframeManager {
468
442
  * Generate CSS for containers
469
443
  */
470
444
  generateCSS() {
471
- const { customization } = this.config;
472
445
  return `
473
- /* Weld Container */
474
- #weld-container {
475
- --weld-color-primary: ${customization.primaryColor};
476
- --weld-color-accent: ${customization.accentColor};
477
- --weld-font-family: ${customization.fontFamily};
478
- --weld-font-size-base: ${customization.fontSize};
479
- --weld-radius-xl: ${customization.borderRadius};
480
- }
481
-
482
446
  /* Import main stylesheet */
483
447
  @import url('/styles/index.css');
484
448
 
@@ -502,6 +466,11 @@ class IframeManager {
502
466
  * Create launcher iframe
503
467
  */
504
468
  async createLauncherIframe() {
469
+ // Guard: skip if launcher iframe already exists
470
+ if (this.iframes.has(IframeType.LAUNCHER)) {
471
+ this.logger.debug('Launcher iframe already exists, skipping creation');
472
+ return;
473
+ }
505
474
  const { iframes } = this.config;
506
475
  const { launcher } = iframes;
507
476
  // Create container
@@ -529,9 +498,12 @@ class IframeManager {
529
498
  width: 100%;
530
499
  height: 100%;
531
500
  border: none;
532
- background: transparent;
501
+ background: none;
502
+ color-scheme: none;
533
503
  display: block;
534
504
  pointer-events: auto;
505
+ border-radius: 50%;
506
+ filter: drop-shadow(rgba(9, 14, 21, 0.54) 0px 1px 6px) drop-shadow(rgba(9, 14, 21, 0.9) 0px 2px 32px);
535
507
  `;
536
508
  iframe.setAttribute('allow', 'clipboard-write');
537
509
  iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups');
@@ -547,20 +519,36 @@ class IframeManager {
547
519
  createdAt: Date.now(),
548
520
  });
549
521
  // When DOM loads, notify MessageBroker to send weld:init
522
+ let launcherRetried = false;
550
523
  iframe.onload = () => {
551
524
  const metadata = this.iframes.get(IframeType.LAUNCHER);
552
525
  if (metadata) {
553
526
  this.logger.debug('Launcher iframe DOM loaded');
554
- // Notify MessageBroker that DOM is loaded (triggers weld:init)
555
527
  this.messageBroker?.setIframeDomLoaded(IframeType.LAUNCHER);
556
528
  }
557
529
  };
530
+ iframe.onerror = () => {
531
+ this.logger.error('Launcher iframe failed to load');
532
+ if (!launcherRetried) {
533
+ launcherRetried = true;
534
+ this.logger.info('Retrying launcher iframe load...');
535
+ setTimeout(() => { iframe.src = this.buildIframeUrl(launcher.url); }, 3000);
536
+ }
537
+ else {
538
+ this.config.onError?.(new Error('Failed to load widget launcher'));
539
+ }
540
+ };
558
541
  this.logger.debug('Launcher iframe created');
559
542
  }
560
543
  /**
561
544
  * Create widget iframe
562
545
  */
563
546
  async createWidgetIframe() {
547
+ // Guard: skip if widget iframe already exists
548
+ if (this.iframes.has(IframeType.WIDGET)) {
549
+ this.logger.debug('Widget iframe already exists, skipping creation');
550
+ return;
551
+ }
564
552
  const { iframes } = this.config;
565
553
  const { widget } = iframes;
566
554
  // Create container
@@ -641,14 +629,25 @@ class IframeManager {
641
629
  createdAt: Date.now(),
642
630
  });
643
631
  // When DOM loads, notify MessageBroker to send weld:init
632
+ let widgetRetried = false;
644
633
  iframe.onload = () => {
645
634
  const metadata = this.iframes.get(IframeType.WIDGET);
646
635
  if (metadata) {
647
636
  this.logger.debug('Widget iframe DOM loaded');
648
- // Notify MessageBroker that DOM is loaded (triggers weld:init)
649
637
  this.messageBroker?.setIframeDomLoaded(IframeType.WIDGET);
650
638
  }
651
639
  };
640
+ iframe.onerror = () => {
641
+ this.logger.error('Widget iframe failed to load');
642
+ if (!widgetRetried) {
643
+ widgetRetried = true;
644
+ this.logger.info('Retrying widget iframe load...');
645
+ setTimeout(() => { iframe.src = this.buildIframeUrl(widget.url); }, 3000);
646
+ }
647
+ else {
648
+ this.config.onError?.(new Error('Failed to load widget'));
649
+ }
650
+ };
652
651
  this.logger.debug('Widget iframe created');
653
652
  }
654
653
  /**
@@ -669,12 +668,21 @@ class IframeManager {
669
668
  url.searchParams.set('device', this.deviceInfo.type);
670
669
  url.searchParams.set('mobile', String(this.deviceInfo.isMobile));
671
670
  url.searchParams.set('parentOrigin', window.location.origin);
671
+ if (this.config.testMode) {
672
+ url.searchParams.set('testMode', 'true');
673
+ }
672
674
  return url.toString();
673
675
  }
674
676
  /**
675
677
  * Setup event listeners
676
678
  */
677
679
  setupEventListeners() {
680
+ // Guard: prevent double-binding
681
+ if (this.eventListenersBound) {
682
+ this.logger.debug('Event listeners already bound, skipping');
683
+ return;
684
+ }
685
+ this.eventListenersBound = true;
678
686
  // Window resize - use bound handler for proper cleanup
679
687
  window.addEventListener('resize', this.boundHandleResize);
680
688
  // Orientation change - use bound handler for proper cleanup
@@ -777,7 +785,7 @@ class IframeManager {
777
785
  iframe.container.style.transform = 'scale(1) translateY(0)';
778
786
  }
779
787
  // Handle mobile scroll lock
780
- if (this.deviceInfo.isMobile && type === IframeType.WIDGET && this.config.mobile.scrollLock) {
788
+ if (this.deviceInfo.isMobile && type === IframeType.WIDGET) {
781
789
  document.body.classList.add('weld-mobile-open');
782
790
  }
783
791
  // Hide launcher on mobile when widget is open (full-screen mode)
@@ -876,6 +884,8 @@ class IframeManager {
876
884
  this.iframes.clear();
877
885
  // Clear messageBroker reference
878
886
  this.messageBroker = null;
887
+ // Reset guard flag
888
+ this.eventListenersBound = false;
879
889
  this.logger.info('IframeManager destroyed');
880
890
  }
881
891
  }
@@ -943,6 +953,8 @@ var MessageType;
943
953
  // Events
944
954
  MessageType["EVENT_TRACK"] = "weld:event:track";
945
955
  MessageType["ERROR_REPORT"] = "weld:error:report";
956
+ // Page tracking
957
+ MessageType["PAGE_CHANGE"] = "weld:page:change";
946
958
  // API responses
947
959
  MessageType["API_SUCCESS"] = "weld:api:success";
948
960
  MessageType["API_ERROR"] = "weld:api:error";
@@ -1521,8 +1533,6 @@ class MessageBroker {
1521
1533
  iframeType,
1522
1534
  config: {
1523
1535
  api: this.config.api,
1524
- customization: this.config.customization,
1525
- features: this.config.features,
1526
1536
  },
1527
1537
  };
1528
1538
  const message = createMessage('weld:init', MessageOrigin.PARENT, initPayload);
@@ -2365,7 +2375,7 @@ class StateCoordinator {
2365
2375
  }
2366
2376
  }
2367
2377
 
2368
- var version = "1.0.16";
2378
+ var version = "1.0.17";
2369
2379
  var packageJson = {
2370
2380
  version: version};
2371
2381
 
@@ -2373,6 +2383,16 @@ var packageJson = {
2373
2383
  * Weld SDK - Main Entry Point
2374
2384
  * Public API for the Weld helpdesk widget
2375
2385
  */
2386
+ /**
2387
+ * Module-level singleton registry keyed by widgetId
2388
+ */
2389
+ const sdkRegistry = new Map();
2390
+ /**
2391
+ * SessionStorage key helpers
2392
+ */
2393
+ function openStateKey(widgetId) {
2394
+ return `weld-widget-open-${widgetId}`;
2395
+ }
2376
2396
  /**
2377
2397
  * SDK initialization status
2378
2398
  */
@@ -2395,6 +2415,8 @@ class WeldSDK {
2395
2415
  this.readyResolve = null;
2396
2416
  // Subscription IDs for cleanup
2397
2417
  this.subscriptionIds = [];
2418
+ // Page tracking cleanup
2419
+ this.pageTrackingCleanup = null;
2398
2420
  /**
2399
2421
  * Update user attributes (Intercom-style, with rate limiting)
2400
2422
  * Limited to 20 calls per page load to prevent abuse
@@ -2433,6 +2455,13 @@ class WeldSDK {
2433
2455
  console.log('[Weld SDK] Received message:', event.data.type);
2434
2456
  }
2435
2457
  if (event.data?.type === 'launcher:clicked') {
2458
+ if (this.status !== SDKStatus.READY) {
2459
+ console.log('[Weld SDK] Launcher clicked but SDK not ready yet — waiting...');
2460
+ this.readyPromise?.then(() => {
2461
+ this.handleLauncherClickMessage(event);
2462
+ });
2463
+ return;
2464
+ }
2436
2465
  // Toggle behavior - if widget is open, close it; if closed, open it
2437
2466
  const state = this.stateCoordinator.getState();
2438
2467
  if (state.widget.isOpen) {
@@ -2445,9 +2474,24 @@ class WeldSDK {
2445
2474
  }
2446
2475
  }
2447
2476
  if (event.data?.type === 'weld:close') {
2477
+ if (this.status !== SDKStatus.READY)
2478
+ return;
2448
2479
  console.log('[Weld SDK] Widget close requested');
2449
2480
  this.close();
2450
2481
  }
2482
+ if (event.data?.type === 'weld:unread-count') {
2483
+ const count = event.data.count ?? 0;
2484
+ // Forward to launcher iframe
2485
+ const launcherIframe = this.iframeManager.getIframe(IframeType.LAUNCHER);
2486
+ if (launcherIframe?.element?.contentWindow) {
2487
+ launcherIframe.element.contentWindow.postMessage({
2488
+ type: 'weld:unread-count',
2489
+ count
2490
+ }, '*');
2491
+ }
2492
+ // Update state coordinator for external API consumers
2493
+ this.stateCoordinator.setBadgeCount(count);
2494
+ }
2451
2495
  if (event.data?.type === 'weld:image:open' && event.data?.url) {
2452
2496
  this.showImageLightbox(event.data.url);
2453
2497
  }
@@ -2709,6 +2753,13 @@ class WeldSDK {
2709
2753
  this.logger.info('WeldSDK ready');
2710
2754
  // Call onReady callback
2711
2755
  this.config.onReady?.();
2756
+ // Start tracking page URL changes
2757
+ this.startPageTracking();
2758
+ // Auto-open if widget was previously open (persisted in sessionStorage)
2759
+ if (this.wasOpen()) {
2760
+ this.logger.info('Restoring previously open widget from sessionStorage');
2761
+ this.open();
2762
+ }
2712
2763
  }
2713
2764
  catch (error) {
2714
2765
  this.status = SDKStatus.ERROR;
@@ -2787,6 +2838,58 @@ class WeldSDK {
2787
2838
  isReady() {
2788
2839
  return this.status === SDKStatus.READY;
2789
2840
  }
2841
+ /**
2842
+ * Update callbacks on an existing instance (used by singleton reuse)
2843
+ */
2844
+ updateCallbacks(config) {
2845
+ if (config.onReady !== undefined)
2846
+ this.config.onReady = config.onReady;
2847
+ if (config.onOpen !== undefined)
2848
+ this.config.onOpen = config.onOpen;
2849
+ if (config.onClose !== undefined)
2850
+ this.config.onClose = config.onClose;
2851
+ if (config.onError !== undefined)
2852
+ this.config.onError = config.onError;
2853
+ if (config.onDestroy !== undefined)
2854
+ this.config.onDestroy = config.onDestroy;
2855
+ if (config.onMinimize !== undefined)
2856
+ this.config.onMinimize = config.onMinimize;
2857
+ if (config.onMaximize !== undefined)
2858
+ this.config.onMaximize = config.onMaximize;
2859
+ }
2860
+ /**
2861
+ * Persist open/closed state to sessionStorage
2862
+ */
2863
+ persistOpenState(isOpen) {
2864
+ try {
2865
+ sessionStorage.setItem(openStateKey(this.config.widgetId), isOpen ? 'true' : 'false');
2866
+ }
2867
+ catch {
2868
+ // sessionStorage might not be available
2869
+ }
2870
+ }
2871
+ /**
2872
+ * Clear persisted state from sessionStorage
2873
+ */
2874
+ clearPersistedState() {
2875
+ try {
2876
+ sessionStorage.removeItem(openStateKey(this.config.widgetId));
2877
+ }
2878
+ catch {
2879
+ // sessionStorage might not be available
2880
+ }
2881
+ }
2882
+ /**
2883
+ * Check if widget was previously open (from sessionStorage)
2884
+ */
2885
+ wasOpen() {
2886
+ try {
2887
+ return sessionStorage.getItem(openStateKey(this.config.widgetId)) === 'true';
2888
+ }
2889
+ catch {
2890
+ return false;
2891
+ }
2892
+ }
2790
2893
  /**
2791
2894
  * Open the widget
2792
2895
  */
@@ -2805,6 +2908,7 @@ class WeldSDK {
2805
2908
  if (launcherIframe?.element?.contentWindow) {
2806
2909
  launcherIframe.element.contentWindow.postMessage({ type: 'weld:widget-opened' }, '*');
2807
2910
  }
2911
+ this.persistOpenState(true);
2808
2912
  this.config.onOpen?.();
2809
2913
  }
2810
2914
  /**
@@ -2825,6 +2929,7 @@ class WeldSDK {
2825
2929
  if (launcherIframe?.element?.contentWindow) {
2826
2930
  launcherIframe.element.contentWindow.postMessage({ type: 'weld:widget-closed' }, '*');
2827
2931
  }
2932
+ this.persistOpenState(false);
2828
2933
  this.config.onClose?.();
2829
2934
  }
2830
2935
  /**
@@ -3013,6 +3118,8 @@ class WeldSDK {
3013
3118
  });
3014
3119
  // Broadcast logout to iframes
3015
3120
  this.messageBroker.broadcast('weld:auth:logout', {});
3121
+ // Clear persisted widget state
3122
+ this.clearPersistedState();
3016
3123
  // Clear any stored session data
3017
3124
  try {
3018
3125
  const prefix = 'weld-';
@@ -3154,6 +3261,63 @@ class WeldSDK {
3154
3261
  this.logger.setLevel('warn');
3155
3262
  this.logger.info('Debug mode disabled');
3156
3263
  }
3264
+ /**
3265
+ * Send a page change message to the widget iframe
3266
+ */
3267
+ sendPageChange(url, title) {
3268
+ const widgetIframe = this.iframeManager.getIframe(IframeType.WIDGET);
3269
+ if (widgetIframe?.element?.contentWindow) {
3270
+ widgetIframe.element.contentWindow.postMessage({
3271
+ type: 'weld:page:change',
3272
+ url,
3273
+ title,
3274
+ timestamp: Date.now(),
3275
+ }, '*');
3276
+ }
3277
+ }
3278
+ /**
3279
+ * Start tracking page URL changes (SPA navigations + popstate)
3280
+ */
3281
+ startPageTracking() {
3282
+ let lastUrl = window.location.href;
3283
+ let debounceTimer = null;
3284
+ const notifyChange = () => {
3285
+ const currentUrl = window.location.href;
3286
+ if (currentUrl !== lastUrl) {
3287
+ lastUrl = currentUrl;
3288
+ this.sendPageChange(currentUrl, document.title);
3289
+ }
3290
+ };
3291
+ const debouncedNotify = () => {
3292
+ if (debounceTimer)
3293
+ clearTimeout(debounceTimer);
3294
+ debounceTimer = setTimeout(notifyChange, 300);
3295
+ };
3296
+ // Send initial page
3297
+ this.sendPageChange(window.location.href, document.title);
3298
+ // Monkey-patch history.pushState and history.replaceState
3299
+ const origPushState = history.pushState.bind(history);
3300
+ const origReplaceState = history.replaceState.bind(history);
3301
+ history.pushState = function (...args) {
3302
+ origPushState(...args);
3303
+ debouncedNotify();
3304
+ };
3305
+ history.replaceState = function (...args) {
3306
+ origReplaceState(...args);
3307
+ debouncedNotify();
3308
+ };
3309
+ // Listen for popstate (browser back/forward)
3310
+ const handlePopstate = () => debouncedNotify();
3311
+ window.addEventListener('popstate', handlePopstate);
3312
+ // Store cleanup
3313
+ this.pageTrackingCleanup = () => {
3314
+ if (debounceTimer)
3315
+ clearTimeout(debounceTimer);
3316
+ window.removeEventListener('popstate', handlePopstate);
3317
+ history.pushState = origPushState;
3318
+ history.replaceState = origReplaceState;
3319
+ };
3320
+ }
3157
3321
  /**
3158
3322
  * Ensure SDK is ready before operation
3159
3323
  */
@@ -3162,11 +3326,26 @@ class WeldSDK {
3162
3326
  throw new Error('SDK not ready. Call init() first.');
3163
3327
  }
3164
3328
  }
3329
+ /**
3330
+ * Detach from the current component lifecycle without destroying the widget.
3331
+ * Use this as a React useEffect cleanup — the widget stays alive across navigations.
3332
+ */
3333
+ detach() {
3334
+ // No-op: widget stays alive in the singleton registry
3335
+ this.logger.debug('WeldSDK detached (no-op, widget stays alive)');
3336
+ }
3165
3337
  /**
3166
3338
  * Destroy SDK and cleanup
3167
3339
  */
3168
3340
  destroy() {
3169
3341
  this.logger.info('Destroying WeldSDK');
3342
+ // Remove from singleton registry
3343
+ sdkRegistry.delete(this.config.widgetId);
3344
+ // Clear persisted state
3345
+ this.clearPersistedState();
3346
+ // Stop page tracking
3347
+ this.pageTrackingCleanup?.();
3348
+ this.pageTrackingCleanup = null;
3170
3349
  // Remove event listener using bound handler
3171
3350
  window.removeEventListener('message', this.boundHandleLauncherClick);
3172
3351
  // Unsubscribe from all message broker subscriptions
@@ -3186,13 +3365,33 @@ class WeldSDK {
3186
3365
  }
3187
3366
  }
3188
3367
  /**
3189
- * Create and initialize WeldSDK instance
3368
+ * Create and initialize WeldSDK instance.
3369
+ * Uses singleton pattern — if an instance for the same widgetId already exists
3370
+ * and is not destroyed, updates callbacks and returns the existing instance.
3190
3371
  */
3191
3372
  async function createWeldSDK(config) {
3373
+ const widgetId = config.widgetId;
3374
+ // Check for existing, non-destroyed instance
3375
+ const existing = sdkRegistry.get(widgetId);
3376
+ if (existing && existing.getStatus() !== 'destroyed') {
3377
+ existing.updateCallbacks(config);
3378
+ return existing;
3379
+ }
3192
3380
  const sdk = new WeldSDK(config);
3381
+ sdkRegistry.set(widgetId, sdk);
3193
3382
  await sdk.init();
3194
3383
  return sdk;
3195
3384
  }
3385
+ /**
3386
+ * Explicitly destroy a WeldSDK instance by widgetId.
3387
+ * Use this for logout or when you need to fully remove the widget.
3388
+ */
3389
+ function destroyWeldSDK(widgetId) {
3390
+ const sdk = sdkRegistry.get(widgetId);
3391
+ if (sdk) {
3392
+ sdk.destroy();
3393
+ }
3394
+ }
3196
3395
 
3197
- export { DEFAULT_CONFIG, WeldSDK as HelpdeskWidget, IframeManager, IframeType, LogLevel, Logger, MessageBroker, RateLimiter, SecurityManager, StateCoordinator, TokenValidator, WeldSDK, createInitialState, createMessage, createWeldSDK, deepClone, deepMerge, WeldSDK as default, defaultLogger, formatFileSize, getStateValue, hasRequiredProperties, createWeldSDK as initHelpdeskWidget, isBaseMessage, isInRange, isPayloadMessage, isPlainObject, isValidApiKey, isValidArrayLength, isValidColor, isValidEmail, isValidFileSize, isValidFileType, isValidLength, isValidMessageText, isValidUrl, isValidWorkspaceId, resolveConfig, sanitizeHtml, sanitizeInput, setStateValue, validateConfig };
3396
+ export { DEFAULT_CONFIG, WeldSDK as HelpdeskWidget, IframeManager, IframeType, LogLevel, Logger, MessageBroker, RateLimiter, SecurityManager, StateCoordinator, TokenValidator, WeldSDK, createInitialState, createMessage, createWeldSDK, deepClone, deepMerge, WeldSDK as default, defaultLogger, destroyWeldSDK as destroyHelpdeskWidget, destroyWeldSDK, formatFileSize, getStateValue, hasRequiredProperties, createWeldSDK as initHelpdeskWidget, isBaseMessage, isInRange, isPayloadMessage, isPlainObject, isValidApiKey, isValidArrayLength, isValidColor, isValidEmail, isValidFileSize, isValidFileType, isValidLength, isValidMessageText, isValidUrl, isValidWorkspaceId, resolveConfig, sanitizeHtml, sanitizeInput, setStateValue, validateConfig };
3198
3397
  //# sourceMappingURL=index.esm.js.map