@mushi-mushi/web 0.5.0 → 0.5.1

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.cts CHANGED
@@ -56,6 +56,7 @@ declare class MushiWidget {
56
56
  private autoCloseTimer;
57
57
  constructor(config: MushiWidgetConfig | undefined, callbacks: WidgetCallbacks);
58
58
  mount(): void;
59
+ updateConfig(config?: MushiWidgetConfig): void;
59
60
  open(options?: {
60
61
  category?: MushiReportCategory;
61
62
  }): void;
package/dist/index.d.ts CHANGED
@@ -56,6 +56,7 @@ declare class MushiWidget {
56
56
  private autoCloseTimer;
57
57
  constructor(config: MushiWidgetConfig | undefined, callbacks: WidgetCallbacks);
58
58
  mount(): void;
59
+ updateConfig(config?: MushiWidgetConfig): void;
59
60
  open(options?: {
60
61
  category?: MushiReportCategory;
61
62
  }): void;
package/dist/index.js CHANGED
@@ -891,6 +891,20 @@ var MushiWidget = class {
891
891
  document.body.appendChild(this.host);
892
892
  this.render();
893
893
  }
894
+ updateConfig(config = {}) {
895
+ this.config = {
896
+ ...this.config,
897
+ ...config.position ? { position: config.position } : {},
898
+ ...config.theme ? { theme: config.theme } : {},
899
+ ...config.triggerText !== void 0 ? { triggerText: config.triggerText || "\u{1F41B}" } : {},
900
+ ...config.expandedTitle !== void 0 ? { expandedTitle: config.expandedTitle } : {},
901
+ ...config.mode ? { mode: config.mode } : {},
902
+ ...config.locale ? { locale: config.locale } : {},
903
+ ...config.zIndex !== void 0 ? { zIndex: config.zIndex } : {}
904
+ };
905
+ this.locale = getLocale(this.config.locale === "auto" ? void 0 : this.config.locale);
906
+ this.render();
907
+ }
894
908
  open(options) {
895
909
  if (this.isOpen) return;
896
910
  this.isOpen = true;
@@ -1804,6 +1818,8 @@ var Mushi = class {
1804
1818
  }
1805
1819
  };
1806
1820
  function createInstance(config) {
1821
+ const bootstrapConfig = config;
1822
+ let activeConfig = config;
1807
1823
  const log = config.debug ?? false ? createLogger({ scope: "mushi", level: "debug", format: "pretty" }) : noopLogger;
1808
1824
  const apiClient = createApiClient({
1809
1825
  projectId: config.projectId,
@@ -1814,20 +1830,50 @@ function createInstance(config) {
1814
1830
  const offlineQueue = createOfflineQueue(config.offline);
1815
1831
  const rateLimiter = createRateLimiter({ maxBurst: 10, refillRate: 1, refillIntervalMs: 5e3 });
1816
1832
  const piiScrubber = createPiiScrubber();
1817
- const consoleCap = config.capture?.console !== false ? createConsoleCapture() : null;
1818
- const networkCap = config.capture?.network !== false ? createNetworkCapture() : null;
1819
- const perfCap = config.capture?.performance !== false ? createPerformanceCapture() : null;
1820
- const screenshotCap = config.capture?.screenshot !== "off" ? createScreenshotCapture() : null;
1821
- const elementSelector = config.capture?.elementSelector !== false ? createElementSelector() : null;
1833
+ let consoleCap = null;
1834
+ let networkCap = null;
1835
+ let perfCap = null;
1836
+ let screenshotCap = null;
1837
+ let elementSelector = null;
1838
+ function syncCaptureModules() {
1839
+ if (activeConfig.capture?.console !== false) {
1840
+ consoleCap ??= createConsoleCapture();
1841
+ } else {
1842
+ consoleCap?.destroy();
1843
+ consoleCap = null;
1844
+ }
1845
+ if (activeConfig.capture?.network !== false) {
1846
+ networkCap ??= createNetworkCapture();
1847
+ } else {
1848
+ networkCap?.destroy();
1849
+ networkCap = null;
1850
+ }
1851
+ if (activeConfig.capture?.performance !== false) {
1852
+ perfCap ??= createPerformanceCapture();
1853
+ } else {
1854
+ perfCap?.destroy();
1855
+ perfCap = null;
1856
+ }
1857
+ screenshotCap = activeConfig.capture?.screenshot !== "off" ? screenshotCap ?? createScreenshotCapture() : null;
1858
+ if (!screenshotCap) pendingScreenshot = null;
1859
+ if (activeConfig.capture?.elementSelector !== false) {
1860
+ elementSelector ??= createElementSelector();
1861
+ } else {
1862
+ elementSelector?.deactivate();
1863
+ elementSelector = null;
1864
+ pendingElement = null;
1865
+ }
1866
+ }
1822
1867
  const listeners = /* @__PURE__ */ new Map();
1823
1868
  function emit(type, data) {
1824
1869
  listeners.get(type)?.forEach((handler) => handler({ type, data }));
1825
1870
  }
1826
- let userInfo = null;
1827
- const customMetadata = {};
1828
1871
  let pendingScreenshot = null;
1829
1872
  let pendingElement = null;
1830
1873
  let pendingProactiveTrigger = null;
1874
+ let userInfo = null;
1875
+ const customMetadata = {};
1876
+ syncCaptureModules();
1831
1877
  const widget = new MushiWidget(config.widget, {
1832
1878
  onSubmit: async ({ category, description, intent }) => {
1833
1879
  log.info("Report submitted", { category, intent });
@@ -1850,13 +1896,13 @@ function createInstance(config) {
1850
1896
  emit("widget:closed");
1851
1897
  },
1852
1898
  onScreenshotRequest: async () => {
1853
- if (!screenshotCap) return;
1899
+ if (!screenshotCap || activeConfig.capture?.screenshot === "off") return;
1854
1900
  log.debug("Taking screenshot");
1855
1901
  pendingScreenshot = await screenshotCap.take();
1856
1902
  widget.setScreenshotAttached(pendingScreenshot !== null);
1857
1903
  },
1858
1904
  onElementSelectorRequest: async () => {
1859
- if (!elementSelector) return;
1905
+ if (!elementSelector || activeConfig.capture?.elementSelector === false) return;
1860
1906
  log.debug("Element selector activated");
1861
1907
  const el = await elementSelector.activate();
1862
1908
  if (el) {
@@ -1910,6 +1956,34 @@ function createInstance(config) {
1910
1956
  offlineQueue.flush(apiClient).then((result) => {
1911
1957
  if (result.sent > 0) log.info("Synced offline reports", { sent: result.sent });
1912
1958
  });
1959
+ function applyRuntimeConfig(runtime) {
1960
+ if (runtime.enabled === false) {
1961
+ activeConfig = bootstrapConfig;
1962
+ clearCachedRuntimeConfig(config.projectId);
1963
+ syncCaptureModules();
1964
+ widget.updateConfig(activeConfig.widget);
1965
+ log.debug("Runtime SDK config disabled; using bootstrap config", { version: runtime.version });
1966
+ return;
1967
+ }
1968
+ activeConfig = mergeRuntimeConfig(activeConfig, runtime);
1969
+ syncCaptureModules();
1970
+ if (runtime.widget) widget.updateConfig(activeConfig.widget);
1971
+ log.debug("Applied runtime SDK config", { version: runtime.version });
1972
+ }
1973
+ if (config.runtimeConfig !== false) {
1974
+ const cached = readCachedRuntimeConfig(config.projectId);
1975
+ if (cached) applyRuntimeConfig(cached);
1976
+ apiClient.getSdkConfig().then((result) => {
1977
+ if (result.ok && result.data) {
1978
+ cacheRuntimeConfig(config.projectId, result.data);
1979
+ applyRuntimeConfig(result.data);
1980
+ } else if (result.error) {
1981
+ log.debug("Runtime SDK config unavailable", result.error);
1982
+ }
1983
+ }).catch((err) => {
1984
+ log.debug("Runtime SDK config fetch failed", { error: err instanceof Error ? err.message : String(err) });
1985
+ });
1986
+ }
1913
1987
  log.info("Initialized", { projectId: config.projectId });
1914
1988
  async function submitReport(category, description, intent) {
1915
1989
  const filterResult = preFilter.check(description);
@@ -1959,9 +2033,9 @@ function createInstance(config) {
1959
2033
  description: scrubbedDescription,
1960
2034
  userIntent: intent,
1961
2035
  environment: captureEnvironment(),
1962
- consoleLogs: consoleCap?.getEntries(),
1963
- networkLogs: networkCap?.getEntries(),
1964
- performanceMetrics: perfCap?.getMetrics(),
2036
+ consoleLogs: activeConfig.capture?.console === false ? void 0 : consoleCap?.getEntries(),
2037
+ networkLogs: activeConfig.capture?.network === false ? void 0 : networkCap?.getEntries(),
2038
+ performanceMetrics: activeConfig.capture?.performance === false ? void 0 : perfCap?.getMetrics(),
1965
2039
  screenshotDataUrl: pendingScreenshot ?? void 0,
1966
2040
  selectedElement: pendingElement ?? void 0,
1967
2041
  metadata: {
@@ -2036,6 +2110,9 @@ function createInstance(config) {
2036
2110
  close() {
2037
2111
  widget.close();
2038
2112
  },
2113
+ updateConfig(runtimeConfig) {
2114
+ applyRuntimeConfig(runtimeConfig);
2115
+ },
2039
2116
  destroy() {
2040
2117
  proactiveTriggers?.destroy();
2041
2118
  proactiveManager?.reset();
@@ -2104,6 +2181,50 @@ function createInstance(config) {
2104
2181
  };
2105
2182
  return sdk;
2106
2183
  }
2184
+ function mergeRuntimeConfig(config, runtime) {
2185
+ return {
2186
+ ...config,
2187
+ widget: {
2188
+ ...config.widget,
2189
+ ...runtime.widget
2190
+ },
2191
+ capture: {
2192
+ ...config.capture,
2193
+ ...runtime.capture
2194
+ }
2195
+ };
2196
+ }
2197
+ function runtimeConfigCacheKey(projectId) {
2198
+ return `mushi:sdk-config:${projectId}`;
2199
+ }
2200
+ function readCachedRuntimeConfig(projectId) {
2201
+ if (typeof localStorage === "undefined") return null;
2202
+ try {
2203
+ const raw = localStorage.getItem(runtimeConfigCacheKey(projectId));
2204
+ if (!raw) return null;
2205
+ const parsed = JSON.parse(raw);
2206
+ return parsed.config ?? null;
2207
+ } catch {
2208
+ return null;
2209
+ }
2210
+ }
2211
+ function cacheRuntimeConfig(projectId, config) {
2212
+ if (typeof localStorage === "undefined") return;
2213
+ try {
2214
+ localStorage.setItem(runtimeConfigCacheKey(projectId), JSON.stringify({
2215
+ cachedAt: Date.now(),
2216
+ config
2217
+ }));
2218
+ } catch {
2219
+ }
2220
+ }
2221
+ function clearCachedRuntimeConfig(projectId) {
2222
+ if (typeof localStorage === "undefined") return;
2223
+ try {
2224
+ localStorage.removeItem(runtimeConfigCacheKey(projectId));
2225
+ } catch {
2226
+ }
2227
+ }
2107
2228
  function createNoopInstance() {
2108
2229
  return {
2109
2230
  report: () => {
@@ -2119,6 +2240,8 @@ function createNoopInstance() {
2119
2240
  },
2120
2241
  close: () => {
2121
2242
  },
2243
+ updateConfig: () => {
2244
+ },
2122
2245
  destroy: () => {
2123
2246
  instance = null;
2124
2247
  },