@meet-sudo/sdk 0.1.7 → 0.1.9

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/sdk.ts","../src/index.ts"],"sourcesContent":["import type {\n MeetSudoConfig,\n UserTraits,\n EventProperties,\n PageProperties,\n Features,\n InitResponse,\n IdentifyResponse,\n ChatAction,\n ChangelogAction,\n} from \"./types\";\n\nconst STORAGE_KEY = \"meetsudo_anon_id\";\nconst FLUSH_INTERVAL = 5000;\nconst REPLAY_FLUSH_INTERVAL = 10000;\nconst INACTIVITY_TIMEOUT = 60000; // 1 minute\n\ninterface EventData {\n name: string;\n properties: EventProperties;\n page_url: string;\n timestamp: string;\n}\n\ninterface State {\n apiKey: string | null;\n apiUrl: string;\n widgetUrl: string;\n anonId: string | null;\n custId: string | null;\n features: Features | null;\n workspaceName: string | null;\n initialized: boolean;\n iframe: HTMLIFrameElement | null;\n eventQ: EventData[];\n flushTimer: ReturnType<typeof setInterval> | null;\n replaySessionId: string | null;\n replaySequence: number;\n replayEvents: unknown[];\n replayFlushTimer: ReturnType<typeof setInterval> | null;\n replayStopFn: (() => void) | null;\n replayTotalEvents: number;\n replayStartedAt: string | null;\n replayRageClickCount: number;\n replayErrorCount: number;\n lastClickTime: number;\n lastClickTarget: EventTarget | null;\n clickCount: number;\n capturedEmails: Record<string, boolean>;\n lastActivityTime: number;\n inactivityTimer: ReturnType<typeof setTimeout> | null;\n replayPaused: boolean;\n unreadChangelogCount: number;\n}\n\nexport class MeetSudo {\n private state: State = {\n apiKey: null,\n apiUrl: \"https://api.meetsudo.com\",\n widgetUrl: \"https://widget.meetsudo.com\",\n anonId: null,\n custId: null,\n features: null,\n workspaceName: null,\n initialized: false,\n iframe: null,\n eventQ: [],\n flushTimer: null,\n replaySessionId: null,\n replaySequence: 0,\n replayEvents: [],\n replayFlushTimer: null,\n replayStopFn: null,\n replayTotalEvents: 0,\n replayStartedAt: null,\n replayRageClickCount: 0,\n replayErrorCount: 0,\n lastClickTime: 0,\n lastClickTarget: null,\n clickCount: 0,\n capturedEmails: {},\n lastActivityTime: Date.now(),\n inactivityTimer: null,\n replayPaused: false,\n unreadChangelogCount: 0,\n };\n\n private config: MeetSudoConfig | null = null;\n\n /**\n * Initialize the MeetSudo SDK\n */\n async init(config: MeetSudoConfig): Promise<void> {\n if (!config.apiKey) {\n throw new Error(\"MeetSudo: apiKey is required\");\n }\n\n this.config = config;\n this.state.apiKey = config.apiKey;\n this.state.apiUrl = config.apiUrl || \"https://api.meetsudo.com\";\n this.state.widgetUrl = config.widgetUrl || \"https://widget.meetsudo.com\";\n this.state.anonId = this.getAnonId();\n\n try {\n const res = await this.api<InitResponse>(\"/widget/init\", {\n anonymous_id: this.state.anonId,\n url: window.location.href,\n referrer: document.referrer,\n });\n\n this.state.custId = res.customer_id;\n this.state.features = res.features;\n this.state.workspaceName = res.workspace_name;\n this.state.unreadChangelogCount = ((res as unknown) as Record<string, number>).unread_changelog_count || 0;\n this.state.initialized = true;\n\n // Create chat iframe if enabled\n if (res.features.chat_enabled && !config.disableChat) {\n this.createIframe(res);\n }\n\n // Start event tracking if enabled\n if (res.features.events_enabled && !config.disableEvents) {\n this.state.flushTimer = setInterval(() => this.flushEvents(), FLUSH_INTERVAL);\n if (res.features.events_auto_page && !config.disableAutoPageView) {\n this.page();\n }\n this.setupEmailCapture();\n }\n\n // Start session replay if enabled and sampled in\n if (this.shouldSampleReplay() && !config.disableReplay) {\n this.startReplay();\n }\n\n // Setup beforeunload handler\n window.addEventListener(\"beforeunload\", () => this.handleUnload());\n } catch (error) {\n console.error(\"MeetSudo: init failed\", error);\n throw error;\n }\n }\n\n /**\n * Identify a user\n */\n async identify(userId: string, traits?: UserTraits): Promise<void> {\n if (!this.state.initialized) {\n console.warn(\"MeetSudo: call init() before identify()\");\n return;\n }\n\n try {\n const res = await this.api<IdentifyResponse>(\"/widget/identify\", {\n anonymous_id: this.state.anonId,\n external_id: userId,\n properties: traits || {},\n });\n\n this.state.custId = res.customer_id;\n\n // Notify chat iframe about identity change\n if (this.state.iframe?.contentWindow) {\n this.state.iframe.contentWindow.postMessage(\n {\n type: \"fi:identify\",\n customerId: res.customer_id,\n merged: res.merged,\n },\n \"*\"\n );\n }\n } catch (error) {\n console.error(\"MeetSudo: identify failed\", error);\n }\n }\n\n /**\n * Track a custom event\n */\n track(eventName: string, properties?: EventProperties): void {\n if (!this.state.initialized || !this.state.features?.events_enabled) {\n return;\n }\n\n this.state.eventQ.push({\n name: eventName,\n properties: properties || {},\n page_url: window.location.href,\n timestamp: new Date().toISOString(),\n });\n }\n\n /**\n * Track a page view\n */\n page(properties?: PageProperties): void {\n const props: PageProperties = {\n url: window.location.href,\n title: document.title,\n referrer: document.referrer,\n ...properties,\n };\n this.track(\"page_view\", props);\n }\n\n /**\n * Control the chat widget\n */\n chat(action: ChatAction): void {\n if (!this.state.iframe?.contentWindow) return;\n\n switch (action) {\n case \"open\":\n this.state.iframe.contentWindow.postMessage({ type: \"fi:chat\", action: \"open\" }, \"*\");\n this.state.iframe.style.width = \"400px\";\n this.state.iframe.style.height = \"560px\";\n break;\n case \"close\":\n this.state.iframe.contentWindow.postMessage({ type: \"fi:chat\", action: \"close\" }, \"*\");\n this.state.iframe.style.width = \"80px\";\n this.state.iframe.style.height = \"80px\";\n break;\n case \"hide\":\n this.state.iframe.style.display = \"none\";\n break;\n case \"show\":\n this.state.iframe.style.display = \"\";\n break;\n }\n }\n\n /**\n * Control the changelog view\n */\n changelog(action: ChangelogAction): void {\n if (!this.state.iframe?.contentWindow) return;\n this.state.iframe.contentWindow.postMessage({ type: \"fi:changelog\", action }, \"*\");\n if (action === \"open\") {\n this.state.iframe.style.width = \"400px\";\n this.state.iframe.style.height = \"560px\";\n }\n }\n\n /**\n * Check if SDK is initialized\n */\n isInitialized(): boolean {\n return this.state.initialized;\n }\n\n /**\n * Get the anonymous ID\n */\n getAnonymousId(): string | null {\n return this.state.anonId;\n }\n\n /**\n * Get the customer ID (after identify)\n */\n getCustomerId(): string | null {\n return this.state.custId;\n }\n\n // Private methods\n\n private getAnonId(): string {\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored) return stored;\n } catch {\n /* private browsing */\n }\n\n const id = crypto.randomUUID?.() || this.generateUUID();\n try {\n localStorage.setItem(STORAGE_KEY, id);\n } catch {\n /* ignore */\n }\n return id;\n }\n\n private generateUUID(): string {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n return (c === \"x\" ? r : (r & 0x3) | 0x8).toString(16);\n });\n }\n\n private async api<T>(path: string, data: unknown): Promise<T> {\n const res = await fetch(this.state.apiUrl + path, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": this.state.apiKey!,\n },\n body: JSON.stringify(data),\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n return res.json();\n }\n\n private createIframe(initData: InitResponse): void {\n if (this.state.iframe) return;\n\n const pos = this.state.features?.chat_position || \"bottom-right\";\n const iframe = document.createElement(\"iframe\");\n iframe.id = \"meetsudo-widget\";\n const posCSS = pos === \"bottom-left\" ? \"left:0;\" : \"right:0;\";\n iframe.style.cssText = `position:fixed;bottom:0;${posCSS}width:80px;height:80px;border:none;z-index:999999;background:transparent;color-scheme:normal;`;\n iframe.allow = \"clipboard-write\";\n iframe.src = this.state.widgetUrl;\n\n document.body.appendChild(iframe);\n this.state.iframe = iframe;\n\n iframe.onload = () => {\n iframe.contentWindow?.postMessage(\n {\n type: \"fi:config\",\n apiKey: this.state.apiKey,\n apiUrl: this.state.apiUrl,\n anonymousId: this.state.anonId,\n customerId: this.state.custId,\n workspaceName: this.state.workspaceName,\n features: this.state.features,\n conversationId: initData.open_conversation_id,\n messages: initData.messages || [],\n unreadChangelogCount: this.state.unreadChangelogCount,\n },\n \"*\"\n );\n };\n\n window.addEventListener(\"message\", (e) => {\n if (e.data?.type === \"fi:resize\") {\n if (e.data.state === \"open\") {\n iframe.style.width = \"400px\";\n iframe.style.height = \"560px\";\n } else {\n iframe.style.width = \"80px\";\n iframe.style.height = \"80px\";\n }\n }\n });\n }\n\n private flushEvents(): void {\n if (!this.state.eventQ.length) return;\n\n const batch = this.state.eventQ.splice(0);\n this.api(\"/widget/events\", {\n anonymous_id: this.state.anonId,\n events: batch,\n }).catch(() => {\n // Put events back on failure\n this.state.eventQ = batch.concat(this.state.eventQ);\n });\n }\n\n private shouldSampleReplay(): boolean {\n if (!this.state.features?.replay_enabled) return false;\n return Math.random() < (this.state.features.replay_sample_rate || 0);\n }\n\n private startReplay(): void {\n this.state.replaySessionId = crypto.randomUUID?.() || this.generateUUID();\n this.state.replaySequence = 0;\n this.state.replayEvents = [];\n this.state.replayTotalEvents = 0;\n this.state.replayStartedAt = new Date().toISOString();\n this.state.replayErrorCount = 0;\n this.state.replayRageClickCount = 0;\n\n this.setupRageClickDetection();\n this.setupErrorCapture();\n\n // Load rrweb dynamically\n const script = document.createElement(\"script\");\n script.type = \"module\";\n script.src = this.state.widgetUrl.replace(/\\/?(index\\.html)?$/, \"\") + \"/replay.js\";\n document.head.appendChild(script);\n\n // Wait for rrweb to load\n let attempts = 0;\n const checkRrweb = setInterval(() => {\n attempts++;\n // @ts-expect-error rrweb is loaded dynamically\n if (window.rrweb?.record) {\n clearInterval(checkRrweb);\n this.initRrweb();\n } else if (attempts > 50) {\n clearInterval(checkRrweb);\n console.warn(\"MeetSudo: replay failed to load\");\n }\n }, 100);\n }\n\n private initRrweb(): void {\n // @ts-expect-error rrweb is loaded dynamically\n this.state.replayStopFn = window.rrweb.record({\n emit: (event: unknown) => {\n this.state.replayEvents.push(event);\n this.state.replayTotalEvents++;\n },\n maskAllInputs: false,\n maskInputFn: (text: string, element: HTMLElement) => {\n if (this.isSensitiveInput(element)) {\n return \"*\".repeat(text.length || 8);\n }\n return text;\n },\n blockSelector: \".meetsudo-no-record, [data-meetsudo-no-record]\",\n inlineStylesheet: true,\n sampling: {\n mousemove: 50,\n mouseInteraction: true,\n scroll: 150,\n input: \"last\",\n },\n });\n\n this.state.replayFlushTimer = setInterval(() => this.flushReplayChunk(), REPLAY_FLUSH_INTERVAL);\n\n // Setup inactivity tracking\n this.setupActivityTracking();\n }\n\n private setupActivityTracking(): void {\n const activityEvents = [\"mousemove\", \"keydown\", \"click\", \"scroll\", \"touchstart\"];\n\n const handleActivity = () => {\n this.state.lastActivityTime = Date.now();\n\n // Resume replay if it was paused\n if (this.state.replayPaused) {\n this.resumeReplay();\n }\n\n // Reset inactivity timer\n if (this.state.inactivityTimer) {\n clearTimeout(this.state.inactivityTimer);\n }\n\n this.state.inactivityTimer = setTimeout(() => {\n this.pauseReplayDueToInactivity();\n }, INACTIVITY_TIMEOUT);\n };\n\n // Add event listeners\n activityEvents.forEach((event) => {\n document.addEventListener(event, handleActivity, { passive: true });\n });\n\n // Start initial inactivity timer\n this.state.inactivityTimer = setTimeout(() => {\n this.pauseReplayDueToInactivity();\n }, INACTIVITY_TIMEOUT);\n }\n\n private pauseReplayDueToInactivity(): void {\n if (this.state.replayPaused || !this.state.replaySessionId) return;\n\n this.state.replayPaused = true;\n\n // Stop rrweb recording\n if (this.state.replayStopFn) {\n this.state.replayStopFn();\n this.state.replayStopFn = null;\n }\n\n // Flush remaining events\n this.flushReplayChunk();\n\n // Stop flush timer\n if (this.state.replayFlushTimer) {\n clearInterval(this.state.replayFlushTimer);\n this.state.replayFlushTimer = null;\n }\n\n // Send end signal with inactivity flag\n if (this.state.apiKey) {\n this.api(\"/widget/replay/end\", {\n anonymous_id: this.state.anonId,\n session_id: this.state.replaySessionId,\n ended_at: new Date().toISOString(),\n event_count: this.state.replayTotalEvents,\n error_count: this.state.replayErrorCount,\n rage_click_count: this.state.replayRageClickCount,\n end_reason: \"inactivity\",\n }).catch(() => {});\n }\n }\n\n private resumeReplay(): void {\n if (!this.state.replayPaused || !this.state.features?.replay_enabled) return;\n\n this.state.replayPaused = false;\n\n // Start a new replay session\n this.state.replaySessionId = crypto.randomUUID?.() || this.generateUUID();\n this.state.replaySequence = 0;\n this.state.replayEvents = [];\n this.state.replayTotalEvents = 0;\n this.state.replayStartedAt = new Date().toISOString();\n this.state.replayErrorCount = 0;\n this.state.replayRageClickCount = 0;\n\n // Restart rrweb recording\n // @ts-expect-error rrweb is loaded dynamically\n if (window.rrweb?.record) {\n // @ts-expect-error rrweb is loaded dynamically\n this.state.replayStopFn = window.rrweb.record({\n emit: (event: unknown) => {\n this.state.replayEvents.push(event);\n this.state.replayTotalEvents++;\n },\n maskAllInputs: false,\n maskInputFn: (text: string, element: HTMLElement) => {\n if (this.isSensitiveInput(element)) {\n return \"*\".repeat(text.length || 8);\n }\n return text;\n },\n blockSelector: \".meetsudo-no-record, [data-meetsudo-no-record]\",\n inlineStylesheet: true,\n sampling: {\n mousemove: 50,\n mouseInteraction: true,\n scroll: 150,\n input: \"last\",\n },\n });\n\n this.state.replayFlushTimer = setInterval(() => this.flushReplayChunk(), REPLAY_FLUSH_INTERVAL);\n }\n }\n\n private isSensitiveInput(el: HTMLElement): boolean {\n if (!el) return true;\n const input = el as HTMLInputElement;\n const type = (input.type || \"\").toLowerCase();\n const name = (input.name || \"\").toLowerCase();\n const id = (input.id || \"\").toLowerCase();\n\n if (type === \"password\") return true;\n\n const sensitivePatterns = [/password/i, /card/i, /cvv/i, /cvc/i, /ssn/i, /secret/i, /token/i];\n const identifiers = name + \" \" + id;\n return sensitivePatterns.some((p) => p.test(identifiers));\n }\n\n private flushReplayChunk(): void {\n if (!this.state.replayEvents.length || this.state.replayPaused) return;\n\n const events = this.state.replayEvents.splice(0);\n const seq = this.state.replaySequence++;\n\n const payload: Record<string, unknown> = {\n anonymous_id: this.state.anonId,\n session_id: this.state.replaySessionId,\n sequence: seq,\n events,\n error_count: this.state.replayErrorCount,\n rage_click_count: this.state.replayRageClickCount,\n };\n\n if (seq === 0) {\n payload.page_url = window.location.href;\n payload.user_agent = navigator.userAgent;\n payload.screen_width = window.innerWidth;\n payload.screen_height = window.innerHeight;\n payload.started_at = this.state.replayStartedAt;\n }\n\n this.api(\"/widget/replay/chunk\", payload).catch(() => {\n this.state.replayEvents = events.concat(this.state.replayEvents);\n this.state.replaySequence--;\n });\n }\n\n private setupRageClickDetection(): void {\n document.addEventListener(\n \"click\",\n (e) => {\n if (!this.state.replaySessionId) return;\n\n const now = Date.now();\n const target = e.target;\n\n if (target === this.state.lastClickTarget && now - this.state.lastClickTime < 500) {\n this.state.clickCount++;\n if (this.state.clickCount >= 3) {\n this.state.replayRageClickCount++;\n this.state.clickCount = 0;\n this.track(\"rage_click\", { page_url: window.location.href });\n }\n } else {\n this.state.clickCount = 1;\n }\n\n this.state.lastClickTime = now;\n this.state.lastClickTarget = target;\n },\n true\n );\n }\n\n private setupErrorCapture(): void {\n window.onerror = (message, source, lineno, colno) => {\n if (this.state.replaySessionId) {\n this.state.replayErrorCount++;\n this.track(\"js_error\", {\n message: String(message).substring(0, 500),\n source: source || \"\",\n lineno: lineno || 0,\n });\n }\n return false;\n };\n\n window.addEventListener(\"unhandledrejection\", (e) => {\n if (this.state.replaySessionId) {\n this.state.replayErrorCount++;\n const message = e.reason instanceof Error ? e.reason.message : String(e.reason);\n this.track(\"js_error\", { message: message.substring(0, 500), type: \"unhandledrejection\" });\n }\n });\n }\n\n private setupEmailCapture(): void {\n document.addEventListener(\n \"blur\",\n (e) => {\n const el = e.target as HTMLInputElement;\n if (!el || el.tagName !== \"INPUT\") return;\n\n const type = (el.type || \"\").toLowerCase();\n const name = (el.name || \"\").toLowerCase();\n if (type === \"email\" || /email/.test(name)) {\n const value = el.value?.trim();\n if (value && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value) && !this.state.capturedEmails[value]) {\n this.state.capturedEmails[value] = true;\n this.track(\"email_captured\", { email: value });\n }\n }\n },\n true\n );\n }\n\n private handleUnload(): void {\n if (this.state.flushTimer) {\n clearInterval(this.state.flushTimer);\n }\n\n // Flush remaining events\n if (this.state.eventQ.length && this.state.apiKey) {\n const apiKey = this.state.apiKey;\n try {\n fetch(this.state.apiUrl + \"/widget/events\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": apiKey,\n },\n body: JSON.stringify({\n anonymous_id: this.state.anonId,\n events: this.state.eventQ,\n }),\n keepalive: true,\n }).catch(() => {});\n } catch {\n /* ignore */\n }\n }\n\n // End replay\n if (this.state.replaySessionId && this.state.apiKey) {\n const replayApiKey = this.state.apiKey;\n if (this.state.replayStopFn) {\n this.state.replayStopFn();\n }\n if (this.state.replayFlushTimer) {\n clearInterval(this.state.replayFlushTimer);\n }\n\n try {\n fetch(this.state.apiUrl + \"/widget/replay/end\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": replayApiKey,\n },\n body: JSON.stringify({\n anonymous_id: this.state.anonId,\n session_id: this.state.replaySessionId,\n ended_at: new Date().toISOString(),\n event_count: this.state.replayTotalEvents,\n error_count: this.state.replayErrorCount,\n rage_click_count: this.state.replayRageClickCount,\n }),\n keepalive: true,\n }).catch(() => {});\n } catch {\n /* ignore */\n }\n }\n }\n}\n","export { MeetSudo } from \"./sdk\";\nexport { MeetSudoServer } from \"./server\";\nexport type {\n MeetSudoConfig,\n UserTraits,\n EventProperties,\n PageProperties,\n ChatAction,\n ChangelogAction,\n} from \"./types\";\nexport type {\n MeetSudoServerConfig,\n LogEntry,\n LogQueryRequest,\n LogAssistResponse,\n LogSchemaHintsResponse,\n} from \"./server\";\n\n// Default instance for convenience\nimport { MeetSudo } from \"./sdk\";\nexport const meetsudo = new MeetSudo();\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/sdk.ts","../src/index.ts"],"sourcesContent":["import type {\n MeetSudoConfig,\n UserTraits,\n EventProperties,\n PageProperties,\n Features,\n InitResponse,\n IdentifyResponse,\n ChatAction,\n ChangelogAction,\n BookingAction,\n} from \"./types\";\n\nconst STORAGE_KEY = \"meetsudo_anon_id\";\nconst FLUSH_INTERVAL = 5000;\nconst REPLAY_FLUSH_INTERVAL = 10000;\nconst INACTIVITY_TIMEOUT = 60000; // 1 minute\n\ninterface EventData {\n name: string;\n properties: EventProperties;\n page_url: string;\n timestamp: string;\n}\n\ninterface State {\n apiKey: string | null;\n apiUrl: string;\n widgetUrl: string;\n anonId: string | null;\n custId: string | null;\n features: Features | null;\n workspaceName: string | null;\n initialized: boolean;\n iframe: HTMLIFrameElement | null;\n eventQ: EventData[];\n flushTimer: ReturnType<typeof setInterval> | null;\n replaySessionId: string | null;\n replaySequence: number;\n replayEvents: unknown[];\n replayFlushTimer: ReturnType<typeof setInterval> | null;\n replayStopFn: (() => void) | null;\n replayTotalEvents: number;\n replayStartedAt: string | null;\n replayRageClickCount: number;\n replayErrorCount: number;\n lastClickTime: number;\n lastClickTarget: EventTarget | null;\n clickCount: number;\n capturedEmails: Record<string, boolean>;\n lastActivityTime: number;\n inactivityTimer: ReturnType<typeof setTimeout> | null;\n replayPaused: boolean;\n unreadChangelogCount: number;\n}\n\nexport class MeetSudo {\n private state: State = {\n apiKey: null,\n apiUrl: \"https://api.meetsudo.com\",\n widgetUrl: \"https://widget.meetsudo.com\",\n anonId: null,\n custId: null,\n features: null,\n workspaceName: null,\n initialized: false,\n iframe: null,\n eventQ: [],\n flushTimer: null,\n replaySessionId: null,\n replaySequence: 0,\n replayEvents: [],\n replayFlushTimer: null,\n replayStopFn: null,\n replayTotalEvents: 0,\n replayStartedAt: null,\n replayRageClickCount: 0,\n replayErrorCount: 0,\n lastClickTime: 0,\n lastClickTarget: null,\n clickCount: 0,\n capturedEmails: {},\n lastActivityTime: Date.now(),\n inactivityTimer: null,\n replayPaused: false,\n unreadChangelogCount: 0,\n };\n\n private config: MeetSudoConfig | null = null;\n\n /**\n * Initialize the MeetSudo SDK\n */\n async init(config: MeetSudoConfig): Promise<void> {\n if (!config.apiKey) {\n throw new Error(\"MeetSudo: apiKey is required\");\n }\n\n this.config = config;\n this.state.apiKey = config.apiKey;\n this.state.apiUrl = config.apiUrl || \"https://api.meetsudo.com\";\n this.state.widgetUrl = config.widgetUrl || \"https://widget.meetsudo.com\";\n this.state.anonId = this.getAnonId();\n\n try {\n const res = await this.api<InitResponse>(\"/widget/init\", {\n anonymous_id: this.state.anonId,\n url: window.location.href,\n referrer: document.referrer,\n });\n\n this.state.custId = res.customer_id;\n this.state.features = res.features;\n this.state.workspaceName = res.workspace_name;\n this.state.unreadChangelogCount = ((res as unknown) as Record<string, number>).unread_changelog_count || 0;\n this.state.initialized = true;\n\n // Create widget iframe if any interactive widget view is enabled\n if ((res.features.chat_enabled && !config.disableChat) || res.features.booking_enabled) {\n this.createIframe(res);\n }\n\n // Start event tracking if enabled\n if (res.features.events_enabled && !config.disableEvents) {\n this.state.flushTimer = setInterval(() => this.flushEvents(), FLUSH_INTERVAL);\n if (res.features.events_auto_page && !config.disableAutoPageView) {\n this.page();\n }\n this.setupEmailCapture();\n }\n\n // Start session replay if enabled and sampled in\n if (this.shouldSampleReplay() && !config.disableReplay) {\n this.startReplay();\n }\n\n // Setup beforeunload handler\n window.addEventListener(\"beforeunload\", () => this.handleUnload());\n } catch (error) {\n console.error(\"MeetSudo: init failed\", error);\n throw error;\n }\n }\n\n /**\n * Identify a user\n */\n async identify(userId: string, traits?: UserTraits): Promise<void> {\n if (!this.state.initialized) {\n console.warn(\"MeetSudo: call init() before identify()\");\n return;\n }\n\n try {\n const res = await this.api<IdentifyResponse>(\"/widget/identify\", {\n anonymous_id: this.state.anonId,\n external_id: userId,\n properties: traits || {},\n });\n\n this.state.custId = res.customer_id;\n\n // Notify chat iframe about identity change\n if (this.state.iframe?.contentWindow) {\n this.state.iframe.contentWindow.postMessage(\n {\n type: \"fi:identify\",\n customerId: res.customer_id,\n merged: res.merged,\n },\n \"*\"\n );\n }\n } catch (error) {\n console.error(\"MeetSudo: identify failed\", error);\n }\n }\n\n /**\n * Track a custom event\n */\n track(eventName: string, properties?: EventProperties): void {\n if (!this.state.initialized || !this.state.features?.events_enabled) {\n return;\n }\n\n this.state.eventQ.push({\n name: eventName,\n properties: properties || {},\n page_url: window.location.href,\n timestamp: new Date().toISOString(),\n });\n }\n\n /**\n * Track a page view\n */\n page(properties?: PageProperties): void {\n const props: PageProperties = {\n url: window.location.href,\n title: document.title,\n referrer: document.referrer,\n ...properties,\n };\n this.track(\"page_view\", props);\n }\n\n /**\n * Control the chat widget\n */\n chat(action: ChatAction): void {\n if (!this.state.iframe?.contentWindow) return;\n\n switch (action) {\n case \"open\":\n this.state.iframe.contentWindow.postMessage({ type: \"fi:chat\", action: \"open\" }, \"*\");\n this.state.iframe.style.width = \"400px\";\n this.state.iframe.style.height = \"560px\";\n break;\n case \"close\":\n this.state.iframe.contentWindow.postMessage({ type: \"fi:chat\", action: \"close\" }, \"*\");\n this.state.iframe.style.width = \"80px\";\n this.state.iframe.style.height = \"80px\";\n break;\n case \"hide\":\n this.state.iframe.style.display = \"none\";\n break;\n case \"show\":\n this.state.iframe.style.display = \"\";\n break;\n }\n }\n\n /**\n * Control the changelog view\n */\n changelog(action: ChangelogAction): void {\n if (!this.state.iframe?.contentWindow) return;\n this.state.iframe.contentWindow.postMessage({ type: \"fi:changelog\", action }, \"*\");\n if (action === \"open\") {\n this.state.iframe.style.width = \"400px\";\n this.state.iframe.style.height = \"560px\";\n }\n }\n\n /**\n * Control the booking scheduler view\n */\n booking(action: BookingAction): void {\n if (!this.state.iframe?.contentWindow) return;\n this.state.iframe.contentWindow.postMessage({ type: \"fi:booking\", action }, \"*\");\n if (action === \"open\") {\n this.state.iframe.style.width = \"400px\";\n this.state.iframe.style.height = \"560px\";\n }\n }\n\n /**\n * Check if SDK is initialized\n */\n isInitialized(): boolean {\n return this.state.initialized;\n }\n\n /**\n * Get the anonymous ID\n */\n getAnonymousId(): string | null {\n return this.state.anonId;\n }\n\n /**\n * Get the customer ID (after identify)\n */\n getCustomerId(): string | null {\n return this.state.custId;\n }\n\n // Private methods\n\n private getAnonId(): string {\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored) return stored;\n } catch {\n /* private browsing */\n }\n\n const id = crypto.randomUUID?.() || this.generateUUID();\n try {\n localStorage.setItem(STORAGE_KEY, id);\n } catch {\n /* ignore */\n }\n return id;\n }\n\n private generateUUID(): string {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n return (c === \"x\" ? r : (r & 0x3) | 0x8).toString(16);\n });\n }\n\n private async api<T>(path: string, data: unknown): Promise<T> {\n const res = await fetch(this.state.apiUrl + path, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": this.state.apiKey!,\n },\n body: JSON.stringify(data),\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n return res.json();\n }\n\n private createIframe(initData: InitResponse): void {\n if (this.state.iframe) return;\n\n const pos = this.state.features?.chat_position || \"bottom-right\";\n const iframe = document.createElement(\"iframe\");\n iframe.id = \"meetsudo-widget\";\n const posCSS = pos === \"bottom-left\" ? \"left:0;\" : \"right:0;\";\n iframe.style.cssText = `position:fixed;bottom:0;${posCSS}width:80px;height:80px;border:none;z-index:999999;background:transparent;color-scheme:normal;`;\n iframe.allow = \"clipboard-write\";\n iframe.src = this.state.widgetUrl;\n\n document.body.appendChild(iframe);\n this.state.iframe = iframe;\n\n iframe.onload = () => {\n iframe.contentWindow?.postMessage(\n {\n type: \"fi:config\",\n apiKey: this.state.apiKey,\n apiUrl: this.state.apiUrl,\n anonymousId: this.state.anonId,\n customerId: this.state.custId,\n workspaceName: this.state.workspaceName,\n features: this.state.features,\n conversationId: initData.open_conversation_id,\n messages: initData.messages || [],\n unreadChangelogCount: this.state.unreadChangelogCount,\n },\n \"*\"\n );\n };\n\n window.addEventListener(\"message\", (e) => {\n if (e.data?.type === \"fi:resize\") {\n if (e.data.state === \"open\") {\n iframe.style.width = \"400px\";\n iframe.style.height = \"560px\";\n } else {\n iframe.style.width = \"80px\";\n iframe.style.height = \"80px\";\n }\n }\n });\n }\n\n private flushEvents(): void {\n if (!this.state.eventQ.length) return;\n\n const batch = this.state.eventQ.splice(0);\n this.api(\"/widget/events\", {\n anonymous_id: this.state.anonId,\n events: batch,\n }).catch(() => {\n // Put events back on failure\n this.state.eventQ = batch.concat(this.state.eventQ);\n });\n }\n\n private shouldSampleReplay(): boolean {\n if (!this.state.features?.replay_enabled) return false;\n return Math.random() < (this.state.features.replay_sample_rate || 0);\n }\n\n private startReplay(): void {\n this.state.replaySessionId = crypto.randomUUID?.() || this.generateUUID();\n this.state.replaySequence = 0;\n this.state.replayEvents = [];\n this.state.replayTotalEvents = 0;\n this.state.replayStartedAt = new Date().toISOString();\n this.state.replayErrorCount = 0;\n this.state.replayRageClickCount = 0;\n\n this.setupRageClickDetection();\n this.setupErrorCapture();\n\n // Load rrweb dynamically\n const script = document.createElement(\"script\");\n script.type = \"module\";\n script.src = this.state.widgetUrl.replace(/\\/?(index\\.html)?$/, \"\") + \"/replay.js\";\n document.head.appendChild(script);\n\n // Wait for rrweb to load\n let attempts = 0;\n const checkRrweb = setInterval(() => {\n attempts++;\n // @ts-expect-error rrweb is loaded dynamically\n if (window.rrweb?.record) {\n clearInterval(checkRrweb);\n this.initRrweb();\n } else if (attempts > 50) {\n clearInterval(checkRrweb);\n console.warn(\"MeetSudo: replay failed to load\");\n }\n }, 100);\n }\n\n private initRrweb(): void {\n // @ts-expect-error rrweb is loaded dynamically\n this.state.replayStopFn = window.rrweb.record({\n emit: (event: unknown) => {\n this.state.replayEvents.push(event);\n this.state.replayTotalEvents++;\n },\n maskAllInputs: false,\n maskInputFn: (text: string, element: HTMLElement) => {\n if (this.isSensitiveInput(element)) {\n return \"*\".repeat(text.length || 8);\n }\n return text;\n },\n blockSelector: \".meetsudo-no-record, [data-meetsudo-no-record]\",\n inlineStylesheet: true,\n sampling: {\n mousemove: 50,\n mouseInteraction: true,\n scroll: 150,\n input: \"last\",\n },\n });\n\n this.state.replayFlushTimer = setInterval(() => this.flushReplayChunk(), REPLAY_FLUSH_INTERVAL);\n\n // Setup inactivity tracking\n this.setupActivityTracking();\n }\n\n private setupActivityTracking(): void {\n const activityEvents = [\"mousemove\", \"keydown\", \"click\", \"scroll\", \"touchstart\"];\n\n const handleActivity = () => {\n this.state.lastActivityTime = Date.now();\n\n // Resume replay if it was paused\n if (this.state.replayPaused) {\n this.resumeReplay();\n }\n\n // Reset inactivity timer\n if (this.state.inactivityTimer) {\n clearTimeout(this.state.inactivityTimer);\n }\n\n this.state.inactivityTimer = setTimeout(() => {\n this.pauseReplayDueToInactivity();\n }, INACTIVITY_TIMEOUT);\n };\n\n // Add event listeners\n activityEvents.forEach((event) => {\n document.addEventListener(event, handleActivity, { passive: true });\n });\n\n // Start initial inactivity timer\n this.state.inactivityTimer = setTimeout(() => {\n this.pauseReplayDueToInactivity();\n }, INACTIVITY_TIMEOUT);\n }\n\n private pauseReplayDueToInactivity(): void {\n if (this.state.replayPaused || !this.state.replaySessionId) return;\n\n this.state.replayPaused = true;\n\n // Stop rrweb recording\n if (this.state.replayStopFn) {\n this.state.replayStopFn();\n this.state.replayStopFn = null;\n }\n\n // Flush remaining events\n this.flushReplayChunk();\n\n // Stop flush timer\n if (this.state.replayFlushTimer) {\n clearInterval(this.state.replayFlushTimer);\n this.state.replayFlushTimer = null;\n }\n\n // Send end signal with inactivity flag\n if (this.state.apiKey) {\n this.api(\"/widget/replay/end\", {\n anonymous_id: this.state.anonId,\n session_id: this.state.replaySessionId,\n ended_at: new Date().toISOString(),\n event_count: this.state.replayTotalEvents,\n error_count: this.state.replayErrorCount,\n rage_click_count: this.state.replayRageClickCount,\n end_reason: \"inactivity\",\n }).catch(() => {});\n }\n }\n\n private resumeReplay(): void {\n if (!this.state.replayPaused || !this.state.features?.replay_enabled) return;\n\n this.state.replayPaused = false;\n\n // Start a new replay session\n this.state.replaySessionId = crypto.randomUUID?.() || this.generateUUID();\n this.state.replaySequence = 0;\n this.state.replayEvents = [];\n this.state.replayTotalEvents = 0;\n this.state.replayStartedAt = new Date().toISOString();\n this.state.replayErrorCount = 0;\n this.state.replayRageClickCount = 0;\n\n // Restart rrweb recording\n // @ts-expect-error rrweb is loaded dynamically\n if (window.rrweb?.record) {\n // @ts-expect-error rrweb is loaded dynamically\n this.state.replayStopFn = window.rrweb.record({\n emit: (event: unknown) => {\n this.state.replayEvents.push(event);\n this.state.replayTotalEvents++;\n },\n maskAllInputs: false,\n maskInputFn: (text: string, element: HTMLElement) => {\n if (this.isSensitiveInput(element)) {\n return \"*\".repeat(text.length || 8);\n }\n return text;\n },\n blockSelector: \".meetsudo-no-record, [data-meetsudo-no-record]\",\n inlineStylesheet: true,\n sampling: {\n mousemove: 50,\n mouseInteraction: true,\n scroll: 150,\n input: \"last\",\n },\n });\n\n this.state.replayFlushTimer = setInterval(() => this.flushReplayChunk(), REPLAY_FLUSH_INTERVAL);\n }\n }\n\n private isSensitiveInput(el: HTMLElement): boolean {\n if (!el) return true;\n const input = el as HTMLInputElement;\n const type = (input.type || \"\").toLowerCase();\n const name = (input.name || \"\").toLowerCase();\n const id = (input.id || \"\").toLowerCase();\n\n if (type === \"password\") return true;\n\n const sensitivePatterns = [/password/i, /card/i, /cvv/i, /cvc/i, /ssn/i, /secret/i, /token/i];\n const identifiers = name + \" \" + id;\n return sensitivePatterns.some((p) => p.test(identifiers));\n }\n\n private flushReplayChunk(): void {\n if (!this.state.replayEvents.length || this.state.replayPaused) return;\n\n const events = this.state.replayEvents.splice(0);\n const seq = this.state.replaySequence++;\n\n const payload: Record<string, unknown> = {\n anonymous_id: this.state.anonId,\n session_id: this.state.replaySessionId,\n sequence: seq,\n events,\n error_count: this.state.replayErrorCount,\n rage_click_count: this.state.replayRageClickCount,\n };\n\n if (seq === 0) {\n payload.page_url = window.location.href;\n payload.user_agent = navigator.userAgent;\n payload.screen_width = window.innerWidth;\n payload.screen_height = window.innerHeight;\n payload.started_at = this.state.replayStartedAt;\n }\n\n this.api(\"/widget/replay/chunk\", payload).catch(() => {\n this.state.replayEvents = events.concat(this.state.replayEvents);\n this.state.replaySequence--;\n });\n }\n\n private setupRageClickDetection(): void {\n document.addEventListener(\n \"click\",\n (e) => {\n if (!this.state.replaySessionId) return;\n\n const now = Date.now();\n const target = e.target;\n\n if (target === this.state.lastClickTarget && now - this.state.lastClickTime < 500) {\n this.state.clickCount++;\n if (this.state.clickCount >= 3) {\n this.state.replayRageClickCount++;\n this.state.clickCount = 0;\n this.track(\"rage_click\", { page_url: window.location.href });\n }\n } else {\n this.state.clickCount = 1;\n }\n\n this.state.lastClickTime = now;\n this.state.lastClickTarget = target;\n },\n true\n );\n }\n\n private setupErrorCapture(): void {\n window.onerror = (message, source, lineno, colno) => {\n if (this.state.replaySessionId) {\n this.state.replayErrorCount++;\n this.track(\"js_error\", {\n message: String(message).substring(0, 500),\n source: source || \"\",\n lineno: lineno || 0,\n });\n }\n return false;\n };\n\n window.addEventListener(\"unhandledrejection\", (e) => {\n if (this.state.replaySessionId) {\n this.state.replayErrorCount++;\n const message = e.reason instanceof Error ? e.reason.message : String(e.reason);\n this.track(\"js_error\", { message: message.substring(0, 500), type: \"unhandledrejection\" });\n }\n });\n }\n\n private setupEmailCapture(): void {\n document.addEventListener(\n \"blur\",\n (e) => {\n const el = e.target as HTMLInputElement;\n if (!el || el.tagName !== \"INPUT\") return;\n\n const type = (el.type || \"\").toLowerCase();\n const name = (el.name || \"\").toLowerCase();\n if (type === \"email\" || /email/.test(name)) {\n const value = el.value?.trim();\n if (value && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value) && !this.state.capturedEmails[value]) {\n this.state.capturedEmails[value] = true;\n this.track(\"email_captured\", { email: value });\n }\n }\n },\n true\n );\n }\n\n private handleUnload(): void {\n if (this.state.flushTimer) {\n clearInterval(this.state.flushTimer);\n }\n\n // Flush remaining events\n if (this.state.eventQ.length && this.state.apiKey) {\n const apiKey = this.state.apiKey;\n try {\n fetch(this.state.apiUrl + \"/widget/events\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": apiKey,\n },\n body: JSON.stringify({\n anonymous_id: this.state.anonId,\n events: this.state.eventQ,\n }),\n keepalive: true,\n }).catch(() => {});\n } catch {\n /* ignore */\n }\n }\n\n // End replay\n if (this.state.replaySessionId && this.state.apiKey) {\n const replayApiKey = this.state.apiKey;\n if (this.state.replayStopFn) {\n this.state.replayStopFn();\n }\n if (this.state.replayFlushTimer) {\n clearInterval(this.state.replayFlushTimer);\n }\n\n try {\n fetch(this.state.apiUrl + \"/widget/replay/end\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": replayApiKey,\n },\n body: JSON.stringify({\n anonymous_id: this.state.anonId,\n session_id: this.state.replaySessionId,\n ended_at: new Date().toISOString(),\n event_count: this.state.replayTotalEvents,\n error_count: this.state.replayErrorCount,\n rage_click_count: this.state.replayRageClickCount,\n }),\n keepalive: true,\n }).catch(() => {});\n } catch {\n /* ignore */\n }\n }\n }\n}\n","export { MeetSudo } from \"./sdk\";\nexport { MeetSudoServer } from \"./server\";\nexport type {\n MeetSudoConfig,\n UserTraits,\n EventProperties,\n PageProperties,\n ChatAction,\n ChangelogAction,\n BookingAction,\n} from \"./types\";\nexport type {\n MeetSudoServerConfig,\n LogEntry,\n LogQueryRequest,\n LogAssistResponse,\n LogSchemaHintsResponse,\n ChangelogEntry,\n} from \"./server\";\n\n// Default instance for convenience\nimport { MeetSudo } from \"./sdk\";\nexport const meetsudo = new MeetSudo();\n"],"mappings":"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","names":[]}
@@ -1,2 +1,2 @@
1
- "use strict";var MeetSudo=(()=>{var l=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var g=(r,t)=>{for(var e in t)l(r,e,{get:t[e],enumerable:!0})},f=(r,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of y(t))!m.call(r,a)&&a!==e&&l(r,a,{get:()=>t[a],enumerable:!(s=d(t,a))||s.enumerable});return r};var v=r=>f(l({},"__esModule",{value:!0}),r);var w={};g(w,{MeetSudo:()=>o,meetsudo:()=>i});var p="meetsudo_anon_id";var o=class{constructor(){this.state={apiKey:null,apiUrl:"https://api.meetsudo.com",widgetUrl:"https://widget.meetsudo.com",anonId:null,custId:null,features:null,workspaceName:null,initialized:!1,iframe:null,eventQ:[],flushTimer:null,replaySessionId:null,replaySequence:0,replayEvents:[],replayFlushTimer:null,replayStopFn:null,replayTotalEvents:0,replayStartedAt:null,replayRageClickCount:0,replayErrorCount:0,lastClickTime:0,lastClickTarget:null,clickCount:0,capturedEmails:{},lastActivityTime:Date.now(),inactivityTimer:null,replayPaused:!1,unreadChangelogCount:0};this.config=null}async init(t){if(!t.apiKey)throw new Error("MeetSudo: apiKey is required");this.config=t,this.state.apiKey=t.apiKey,this.state.apiUrl=t.apiUrl||"https://api.meetsudo.com",this.state.widgetUrl=t.widgetUrl||"https://widget.meetsudo.com",this.state.anonId=this.getAnonId();try{let e=await this.api("/widget/init",{anonymous_id:this.state.anonId,url:window.location.href,referrer:document.referrer});this.state.custId=e.customer_id,this.state.features=e.features,this.state.workspaceName=e.workspace_name,this.state.unreadChangelogCount=e.unread_changelog_count||0,this.state.initialized=!0,e.features.chat_enabled&&!t.disableChat&&this.createIframe(e),e.features.events_enabled&&!t.disableEvents&&(this.state.flushTimer=setInterval(()=>this.flushEvents(),5e3),e.features.events_auto_page&&!t.disableAutoPageView&&this.page(),this.setupEmailCapture()),this.shouldSampleReplay()&&!t.disableReplay&&this.startReplay(),window.addEventListener("beforeunload",()=>this.handleUnload())}catch(e){throw console.error("MeetSudo: init failed",e),e}}async identify(t,e){if(!this.state.initialized){console.warn("MeetSudo: call init() before identify()");return}try{let s=await this.api("/widget/identify",{anonymous_id:this.state.anonId,external_id:t,properties:e||{}});this.state.custId=s.customer_id,this.state.iframe?.contentWindow&&this.state.iframe.contentWindow.postMessage({type:"fi:identify",customerId:s.customer_id,merged:s.merged},"*")}catch(s){console.error("MeetSudo: identify failed",s)}}track(t,e){!this.state.initialized||!this.state.features?.events_enabled||this.state.eventQ.push({name:t,properties:e||{},page_url:window.location.href,timestamp:new Date().toISOString()})}page(t){let e={url:window.location.href,title:document.title,referrer:document.referrer,...t};this.track("page_view",e)}chat(t){if(this.state.iframe?.contentWindow)switch(t){case"open":this.state.iframe.contentWindow.postMessage({type:"fi:chat",action:"open"},"*"),this.state.iframe.style.width="400px",this.state.iframe.style.height="560px";break;case"close":this.state.iframe.contentWindow.postMessage({type:"fi:chat",action:"close"},"*"),this.state.iframe.style.width="80px",this.state.iframe.style.height="80px";break;case"hide":this.state.iframe.style.display="none";break;case"show":this.state.iframe.style.display="";break}}changelog(t){this.state.iframe?.contentWindow&&(this.state.iframe.contentWindow.postMessage({type:"fi:changelog",action:t},"*"),t==="open"&&(this.state.iframe.style.width="400px",this.state.iframe.style.height="560px"))}isInitialized(){return this.state.initialized}getAnonymousId(){return this.state.anonId}getCustomerId(){return this.state.custId}getAnonId(){try{let e=localStorage.getItem(p);if(e)return e}catch{}let t=crypto.randomUUID?.()||this.generateUUID();try{localStorage.setItem(p,t)}catch{}return t}generateUUID(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=Math.random()*16|0;return(t==="x"?e:e&3|8).toString(16)})}async api(t,e){let s=await fetch(this.state.apiUrl+t,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.state.apiKey},body:JSON.stringify(e)});if(!s.ok)throw new Error(`HTTP ${s.status}`);return s.json()}createIframe(t){if(this.state.iframe)return;let e=this.state.features?.chat_position||"bottom-right",s=document.createElement("iframe");s.id="meetsudo-widget";let a=e==="bottom-left"?"left:0;":"right:0;";s.style.cssText=`position:fixed;bottom:0;${a}width:80px;height:80px;border:none;z-index:999999;background:transparent;color-scheme:normal;`,s.allow="clipboard-write",s.src=this.state.widgetUrl,document.body.appendChild(s),this.state.iframe=s,s.onload=()=>{s.contentWindow?.postMessage({type:"fi:config",apiKey:this.state.apiKey,apiUrl:this.state.apiUrl,anonymousId:this.state.anonId,customerId:this.state.custId,workspaceName:this.state.workspaceName,features:this.state.features,conversationId:t.open_conversation_id,messages:t.messages||[],unreadChangelogCount:this.state.unreadChangelogCount},"*")},window.addEventListener("message",n=>{n.data?.type==="fi:resize"&&(n.data.state==="open"?(s.style.width="400px",s.style.height="560px"):(s.style.width="80px",s.style.height="80px"))})}flushEvents(){if(!this.state.eventQ.length)return;let t=this.state.eventQ.splice(0);this.api("/widget/events",{anonymous_id:this.state.anonId,events:t}).catch(()=>{this.state.eventQ=t.concat(this.state.eventQ)})}shouldSampleReplay(){return this.state.features?.replay_enabled?Math.random()<(this.state.features.replay_sample_rate||0):!1}startReplay(){this.state.replaySessionId=crypto.randomUUID?.()||this.generateUUID(),this.state.replaySequence=0,this.state.replayEvents=[],this.state.replayTotalEvents=0,this.state.replayStartedAt=new Date().toISOString(),this.state.replayErrorCount=0,this.state.replayRageClickCount=0,this.setupRageClickDetection(),this.setupErrorCapture();let t=document.createElement("script");t.type="module",t.src=this.state.widgetUrl.replace(/\/?(index\.html)?$/,"")+"/replay.js",document.head.appendChild(t);let e=0,s=setInterval(()=>{e++,window.rrweb?.record?(clearInterval(s),this.initRrweb()):e>50&&(clearInterval(s),console.warn("MeetSudo: replay failed to load"))},100)}initRrweb(){this.state.replayStopFn=window.rrweb.record({emit:t=>{this.state.replayEvents.push(t),this.state.replayTotalEvents++},maskAllInputs:!1,maskInputFn:(t,e)=>this.isSensitiveInput(e)?"*".repeat(t.length||8):t,blockSelector:".meetsudo-no-record, [data-meetsudo-no-record]",inlineStylesheet:!0,sampling:{mousemove:50,mouseInteraction:!0,scroll:150,input:"last"}}),this.state.replayFlushTimer=setInterval(()=>this.flushReplayChunk(),1e4),this.setupActivityTracking()}setupActivityTracking(){let t=["mousemove","keydown","click","scroll","touchstart"],e=()=>{this.state.lastActivityTime=Date.now(),this.state.replayPaused&&this.resumeReplay(),this.state.inactivityTimer&&clearTimeout(this.state.inactivityTimer),this.state.inactivityTimer=setTimeout(()=>{this.pauseReplayDueToInactivity()},6e4)};t.forEach(s=>{document.addEventListener(s,e,{passive:!0})}),this.state.inactivityTimer=setTimeout(()=>{this.pauseReplayDueToInactivity()},6e4)}pauseReplayDueToInactivity(){this.state.replayPaused||!this.state.replaySessionId||(this.state.replayPaused=!0,this.state.replayStopFn&&(this.state.replayStopFn(),this.state.replayStopFn=null),this.flushReplayChunk(),this.state.replayFlushTimer&&(clearInterval(this.state.replayFlushTimer),this.state.replayFlushTimer=null),this.state.apiKey&&this.api("/widget/replay/end",{anonymous_id:this.state.anonId,session_id:this.state.replaySessionId,ended_at:new Date().toISOString(),event_count:this.state.replayTotalEvents,error_count:this.state.replayErrorCount,rage_click_count:this.state.replayRageClickCount,end_reason:"inactivity"}).catch(()=>{}))}resumeReplay(){!this.state.replayPaused||!this.state.features?.replay_enabled||(this.state.replayPaused=!1,this.state.replaySessionId=crypto.randomUUID?.()||this.generateUUID(),this.state.replaySequence=0,this.state.replayEvents=[],this.state.replayTotalEvents=0,this.state.replayStartedAt=new Date().toISOString(),this.state.replayErrorCount=0,this.state.replayRageClickCount=0,window.rrweb?.record&&(this.state.replayStopFn=window.rrweb.record({emit:t=>{this.state.replayEvents.push(t),this.state.replayTotalEvents++},maskAllInputs:!1,maskInputFn:(t,e)=>this.isSensitiveInput(e)?"*".repeat(t.length||8):t,blockSelector:".meetsudo-no-record, [data-meetsudo-no-record]",inlineStylesheet:!0,sampling:{mousemove:50,mouseInteraction:!0,scroll:150,input:"last"}}),this.state.replayFlushTimer=setInterval(()=>this.flushReplayChunk(),1e4)))}isSensitiveInput(t){if(!t)return!0;let e=t,s=(e.type||"").toLowerCase(),a=(e.name||"").toLowerCase(),n=(e.id||"").toLowerCase();if(s==="password")return!0;let h=[/password/i,/card/i,/cvv/i,/cvc/i,/ssn/i,/secret/i,/token/i],u=a+" "+n;return h.some(c=>c.test(u))}flushReplayChunk(){if(!this.state.replayEvents.length||this.state.replayPaused)return;let t=this.state.replayEvents.splice(0),e=this.state.replaySequence++,s={anonymous_id:this.state.anonId,session_id:this.state.replaySessionId,sequence:e,events:t,error_count:this.state.replayErrorCount,rage_click_count:this.state.replayRageClickCount};e===0&&(s.page_url=window.location.href,s.user_agent=navigator.userAgent,s.screen_width=window.innerWidth,s.screen_height=window.innerHeight,s.started_at=this.state.replayStartedAt),this.api("/widget/replay/chunk",s).catch(()=>{this.state.replayEvents=t.concat(this.state.replayEvents),this.state.replaySequence--})}setupRageClickDetection(){document.addEventListener("click",t=>{if(!this.state.replaySessionId)return;let e=Date.now(),s=t.target;s===this.state.lastClickTarget&&e-this.state.lastClickTime<500?(this.state.clickCount++,this.state.clickCount>=3&&(this.state.replayRageClickCount++,this.state.clickCount=0,this.track("rage_click",{page_url:window.location.href}))):this.state.clickCount=1,this.state.lastClickTime=e,this.state.lastClickTarget=s},!0)}setupErrorCapture(){window.onerror=(t,e,s,a)=>(this.state.replaySessionId&&(this.state.replayErrorCount++,this.track("js_error",{message:String(t).substring(0,500),source:e||"",lineno:s||0})),!1),window.addEventListener("unhandledrejection",t=>{if(this.state.replaySessionId){this.state.replayErrorCount++;let e=t.reason instanceof Error?t.reason.message:String(t.reason);this.track("js_error",{message:e.substring(0,500),type:"unhandledrejection"})}})}setupEmailCapture(){document.addEventListener("blur",t=>{let e=t.target;if(!e||e.tagName!=="INPUT")return;let s=(e.type||"").toLowerCase(),a=(e.name||"").toLowerCase();if(s==="email"||/email/.test(a)){let n=e.value?.trim();n&&/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(n)&&!this.state.capturedEmails[n]&&(this.state.capturedEmails[n]=!0,this.track("email_captured",{email:n}))}},!0)}handleUnload(){if(this.state.flushTimer&&clearInterval(this.state.flushTimer),this.state.eventQ.length&&this.state.apiKey){let t=this.state.apiKey;try{fetch(this.state.apiUrl+"/widget/events",{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":t},body:JSON.stringify({anonymous_id:this.state.anonId,events:this.state.eventQ}),keepalive:!0}).catch(()=>{})}catch{}}if(this.state.replaySessionId&&this.state.apiKey){let t=this.state.apiKey;this.state.replayStopFn&&this.state.replayStopFn(),this.state.replayFlushTimer&&clearInterval(this.state.replayFlushTimer);try{fetch(this.state.apiUrl+"/widget/replay/end",{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":t},body:JSON.stringify({anonymous_id:this.state.anonId,session_id:this.state.replaySessionId,ended_at:new Date().toISOString(),event_count:this.state.replayTotalEvents,error_count:this.state.replayErrorCount,rage_click_count:this.state.replayRageClickCount}),keepalive:!0}).catch(()=>{})}catch{}}}};var i=new o;typeof window<"u"&&(window.MeetSudo={MeetSudo:o,meetsudo:i,init:i.init.bind(i),identify:i.identify.bind(i),track:i.track.bind(i),page:i.page.bind(i),chat:i.chat.bind(i),changelog:i.changelog.bind(i)});return v(w);})();
1
+ "use strict";var MeetSudo=(()=>{var l=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var g=(r,t)=>{for(var e in t)l(r,e,{get:t[e],enumerable:!0})},f=(r,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of y(t))!m.call(r,a)&&a!==e&&l(r,a,{get:()=>t[a],enumerable:!(s=d(t,a))||s.enumerable});return r};var v=r=>f(l({},"__esModule",{value:!0}),r);var w={};g(w,{MeetSudo:()=>o,meetsudo:()=>i});var p="meetsudo_anon_id";var o=class{constructor(){this.state={apiKey:null,apiUrl:"https://api.meetsudo.com",widgetUrl:"https://widget.meetsudo.com",anonId:null,custId:null,features:null,workspaceName:null,initialized:!1,iframe:null,eventQ:[],flushTimer:null,replaySessionId:null,replaySequence:0,replayEvents:[],replayFlushTimer:null,replayStopFn:null,replayTotalEvents:0,replayStartedAt:null,replayRageClickCount:0,replayErrorCount:0,lastClickTime:0,lastClickTarget:null,clickCount:0,capturedEmails:{},lastActivityTime:Date.now(),inactivityTimer:null,replayPaused:!1,unreadChangelogCount:0};this.config=null}async init(t){if(!t.apiKey)throw new Error("MeetSudo: apiKey is required");this.config=t,this.state.apiKey=t.apiKey,this.state.apiUrl=t.apiUrl||"https://api.meetsudo.com",this.state.widgetUrl=t.widgetUrl||"https://widget.meetsudo.com",this.state.anonId=this.getAnonId();try{let e=await this.api("/widget/init",{anonymous_id:this.state.anonId,url:window.location.href,referrer:document.referrer});this.state.custId=e.customer_id,this.state.features=e.features,this.state.workspaceName=e.workspace_name,this.state.unreadChangelogCount=e.unread_changelog_count||0,this.state.initialized=!0,(e.features.chat_enabled&&!t.disableChat||e.features.booking_enabled)&&this.createIframe(e),e.features.events_enabled&&!t.disableEvents&&(this.state.flushTimer=setInterval(()=>this.flushEvents(),5e3),e.features.events_auto_page&&!t.disableAutoPageView&&this.page(),this.setupEmailCapture()),this.shouldSampleReplay()&&!t.disableReplay&&this.startReplay(),window.addEventListener("beforeunload",()=>this.handleUnload())}catch(e){throw console.error("MeetSudo: init failed",e),e}}async identify(t,e){if(!this.state.initialized){console.warn("MeetSudo: call init() before identify()");return}try{let s=await this.api("/widget/identify",{anonymous_id:this.state.anonId,external_id:t,properties:e||{}});this.state.custId=s.customer_id,this.state.iframe?.contentWindow&&this.state.iframe.contentWindow.postMessage({type:"fi:identify",customerId:s.customer_id,merged:s.merged},"*")}catch(s){console.error("MeetSudo: identify failed",s)}}track(t,e){!this.state.initialized||!this.state.features?.events_enabled||this.state.eventQ.push({name:t,properties:e||{},page_url:window.location.href,timestamp:new Date().toISOString()})}page(t){let e={url:window.location.href,title:document.title,referrer:document.referrer,...t};this.track("page_view",e)}chat(t){if(this.state.iframe?.contentWindow)switch(t){case"open":this.state.iframe.contentWindow.postMessage({type:"fi:chat",action:"open"},"*"),this.state.iframe.style.width="400px",this.state.iframe.style.height="560px";break;case"close":this.state.iframe.contentWindow.postMessage({type:"fi:chat",action:"close"},"*"),this.state.iframe.style.width="80px",this.state.iframe.style.height="80px";break;case"hide":this.state.iframe.style.display="none";break;case"show":this.state.iframe.style.display="";break}}changelog(t){this.state.iframe?.contentWindow&&(this.state.iframe.contentWindow.postMessage({type:"fi:changelog",action:t},"*"),t==="open"&&(this.state.iframe.style.width="400px",this.state.iframe.style.height="560px"))}booking(t){this.state.iframe?.contentWindow&&(this.state.iframe.contentWindow.postMessage({type:"fi:booking",action:t},"*"),t==="open"&&(this.state.iframe.style.width="400px",this.state.iframe.style.height="560px"))}isInitialized(){return this.state.initialized}getAnonymousId(){return this.state.anonId}getCustomerId(){return this.state.custId}getAnonId(){try{let e=localStorage.getItem(p);if(e)return e}catch{}let t=crypto.randomUUID?.()||this.generateUUID();try{localStorage.setItem(p,t)}catch{}return t}generateUUID(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=Math.random()*16|0;return(t==="x"?e:e&3|8).toString(16)})}async api(t,e){let s=await fetch(this.state.apiUrl+t,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.state.apiKey},body:JSON.stringify(e)});if(!s.ok)throw new Error(`HTTP ${s.status}`);return s.json()}createIframe(t){if(this.state.iframe)return;let e=this.state.features?.chat_position||"bottom-right",s=document.createElement("iframe");s.id="meetsudo-widget";let a=e==="bottom-left"?"left:0;":"right:0;";s.style.cssText=`position:fixed;bottom:0;${a}width:80px;height:80px;border:none;z-index:999999;background:transparent;color-scheme:normal;`,s.allow="clipboard-write",s.src=this.state.widgetUrl,document.body.appendChild(s),this.state.iframe=s,s.onload=()=>{s.contentWindow?.postMessage({type:"fi:config",apiKey:this.state.apiKey,apiUrl:this.state.apiUrl,anonymousId:this.state.anonId,customerId:this.state.custId,workspaceName:this.state.workspaceName,features:this.state.features,conversationId:t.open_conversation_id,messages:t.messages||[],unreadChangelogCount:this.state.unreadChangelogCount},"*")},window.addEventListener("message",n=>{n.data?.type==="fi:resize"&&(n.data.state==="open"?(s.style.width="400px",s.style.height="560px"):(s.style.width="80px",s.style.height="80px"))})}flushEvents(){if(!this.state.eventQ.length)return;let t=this.state.eventQ.splice(0);this.api("/widget/events",{anonymous_id:this.state.anonId,events:t}).catch(()=>{this.state.eventQ=t.concat(this.state.eventQ)})}shouldSampleReplay(){return this.state.features?.replay_enabled?Math.random()<(this.state.features.replay_sample_rate||0):!1}startReplay(){this.state.replaySessionId=crypto.randomUUID?.()||this.generateUUID(),this.state.replaySequence=0,this.state.replayEvents=[],this.state.replayTotalEvents=0,this.state.replayStartedAt=new Date().toISOString(),this.state.replayErrorCount=0,this.state.replayRageClickCount=0,this.setupRageClickDetection(),this.setupErrorCapture();let t=document.createElement("script");t.type="module",t.src=this.state.widgetUrl.replace(/\/?(index\.html)?$/,"")+"/replay.js",document.head.appendChild(t);let e=0,s=setInterval(()=>{e++,window.rrweb?.record?(clearInterval(s),this.initRrweb()):e>50&&(clearInterval(s),console.warn("MeetSudo: replay failed to load"))},100)}initRrweb(){this.state.replayStopFn=window.rrweb.record({emit:t=>{this.state.replayEvents.push(t),this.state.replayTotalEvents++},maskAllInputs:!1,maskInputFn:(t,e)=>this.isSensitiveInput(e)?"*".repeat(t.length||8):t,blockSelector:".meetsudo-no-record, [data-meetsudo-no-record]",inlineStylesheet:!0,sampling:{mousemove:50,mouseInteraction:!0,scroll:150,input:"last"}}),this.state.replayFlushTimer=setInterval(()=>this.flushReplayChunk(),1e4),this.setupActivityTracking()}setupActivityTracking(){let t=["mousemove","keydown","click","scroll","touchstart"],e=()=>{this.state.lastActivityTime=Date.now(),this.state.replayPaused&&this.resumeReplay(),this.state.inactivityTimer&&clearTimeout(this.state.inactivityTimer),this.state.inactivityTimer=setTimeout(()=>{this.pauseReplayDueToInactivity()},6e4)};t.forEach(s=>{document.addEventListener(s,e,{passive:!0})}),this.state.inactivityTimer=setTimeout(()=>{this.pauseReplayDueToInactivity()},6e4)}pauseReplayDueToInactivity(){this.state.replayPaused||!this.state.replaySessionId||(this.state.replayPaused=!0,this.state.replayStopFn&&(this.state.replayStopFn(),this.state.replayStopFn=null),this.flushReplayChunk(),this.state.replayFlushTimer&&(clearInterval(this.state.replayFlushTimer),this.state.replayFlushTimer=null),this.state.apiKey&&this.api("/widget/replay/end",{anonymous_id:this.state.anonId,session_id:this.state.replaySessionId,ended_at:new Date().toISOString(),event_count:this.state.replayTotalEvents,error_count:this.state.replayErrorCount,rage_click_count:this.state.replayRageClickCount,end_reason:"inactivity"}).catch(()=>{}))}resumeReplay(){!this.state.replayPaused||!this.state.features?.replay_enabled||(this.state.replayPaused=!1,this.state.replaySessionId=crypto.randomUUID?.()||this.generateUUID(),this.state.replaySequence=0,this.state.replayEvents=[],this.state.replayTotalEvents=0,this.state.replayStartedAt=new Date().toISOString(),this.state.replayErrorCount=0,this.state.replayRageClickCount=0,window.rrweb?.record&&(this.state.replayStopFn=window.rrweb.record({emit:t=>{this.state.replayEvents.push(t),this.state.replayTotalEvents++},maskAllInputs:!1,maskInputFn:(t,e)=>this.isSensitiveInput(e)?"*".repeat(t.length||8):t,blockSelector:".meetsudo-no-record, [data-meetsudo-no-record]",inlineStylesheet:!0,sampling:{mousemove:50,mouseInteraction:!0,scroll:150,input:"last"}}),this.state.replayFlushTimer=setInterval(()=>this.flushReplayChunk(),1e4)))}isSensitiveInput(t){if(!t)return!0;let e=t,s=(e.type||"").toLowerCase(),a=(e.name||"").toLowerCase(),n=(e.id||"").toLowerCase();if(s==="password")return!0;let h=[/password/i,/card/i,/cvv/i,/cvc/i,/ssn/i,/secret/i,/token/i],u=a+" "+n;return h.some(c=>c.test(u))}flushReplayChunk(){if(!this.state.replayEvents.length||this.state.replayPaused)return;let t=this.state.replayEvents.splice(0),e=this.state.replaySequence++,s={anonymous_id:this.state.anonId,session_id:this.state.replaySessionId,sequence:e,events:t,error_count:this.state.replayErrorCount,rage_click_count:this.state.replayRageClickCount};e===0&&(s.page_url=window.location.href,s.user_agent=navigator.userAgent,s.screen_width=window.innerWidth,s.screen_height=window.innerHeight,s.started_at=this.state.replayStartedAt),this.api("/widget/replay/chunk",s).catch(()=>{this.state.replayEvents=t.concat(this.state.replayEvents),this.state.replaySequence--})}setupRageClickDetection(){document.addEventListener("click",t=>{if(!this.state.replaySessionId)return;let e=Date.now(),s=t.target;s===this.state.lastClickTarget&&e-this.state.lastClickTime<500?(this.state.clickCount++,this.state.clickCount>=3&&(this.state.replayRageClickCount++,this.state.clickCount=0,this.track("rage_click",{page_url:window.location.href}))):this.state.clickCount=1,this.state.lastClickTime=e,this.state.lastClickTarget=s},!0)}setupErrorCapture(){window.onerror=(t,e,s,a)=>(this.state.replaySessionId&&(this.state.replayErrorCount++,this.track("js_error",{message:String(t).substring(0,500),source:e||"",lineno:s||0})),!1),window.addEventListener("unhandledrejection",t=>{if(this.state.replaySessionId){this.state.replayErrorCount++;let e=t.reason instanceof Error?t.reason.message:String(t.reason);this.track("js_error",{message:e.substring(0,500),type:"unhandledrejection"})}})}setupEmailCapture(){document.addEventListener("blur",t=>{let e=t.target;if(!e||e.tagName!=="INPUT")return;let s=(e.type||"").toLowerCase(),a=(e.name||"").toLowerCase();if(s==="email"||/email/.test(a)){let n=e.value?.trim();n&&/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(n)&&!this.state.capturedEmails[n]&&(this.state.capturedEmails[n]=!0,this.track("email_captured",{email:n}))}},!0)}handleUnload(){if(this.state.flushTimer&&clearInterval(this.state.flushTimer),this.state.eventQ.length&&this.state.apiKey){let t=this.state.apiKey;try{fetch(this.state.apiUrl+"/widget/events",{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":t},body:JSON.stringify({anonymous_id:this.state.anonId,events:this.state.eventQ}),keepalive:!0}).catch(()=>{})}catch{}}if(this.state.replaySessionId&&this.state.apiKey){let t=this.state.apiKey;this.state.replayStopFn&&this.state.replayStopFn(),this.state.replayFlushTimer&&clearInterval(this.state.replayFlushTimer);try{fetch(this.state.apiUrl+"/widget/replay/end",{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":t},body:JSON.stringify({anonymous_id:this.state.anonId,session_id:this.state.replaySessionId,ended_at:new Date().toISOString(),event_count:this.state.replayTotalEvents,error_count:this.state.replayErrorCount,rage_click_count:this.state.replayRageClickCount}),keepalive:!0}).catch(()=>{})}catch{}}}};var i=new o;typeof window<"u"&&(window.MeetSudo={MeetSudo:o,meetsudo:i,init:i.init.bind(i),identify:i.identify.bind(i),track:i.track.bind(i),page:i.page.bind(i),chat:i.chat.bind(i),changelog:i.changelog.bind(i),booking:i.booking.bind(i)});return v(w);})();
2
2
  //# sourceMappingURL=meetsudo.global.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/browser.ts","../src/sdk.ts"],"sourcesContent":["/**\n * Browser bundle entry point for script tag usage\n * This file is bundled as an IIFE and exposes window.MeetSudo\n */\nimport { MeetSudo } from \"./sdk\";\nimport type { MeetSudoConfig, UserTraits, EventProperties, PageProperties, ChatAction, ChangelogAction } from \"./types\";\n\n// Create default instance\nconst meetsudo = new MeetSudo();\n\n// Export everything for the IIFE global\nexport { MeetSudo, meetsudo };\nexport type { MeetSudoConfig, UserTraits, EventProperties, PageProperties, ChatAction, ChangelogAction };\n\n// Make it available globally\nif (typeof window !== \"undefined\") {\n (window as unknown as Record<string, unknown>).MeetSudo = {\n MeetSudo,\n meetsudo,\n init: meetsudo.init.bind(meetsudo),\n identify: meetsudo.identify.bind(meetsudo),\n track: meetsudo.track.bind(meetsudo),\n page: meetsudo.page.bind(meetsudo),\n chat: meetsudo.chat.bind(meetsudo),\n changelog: meetsudo.changelog.bind(meetsudo),\n };\n}\n","import type {\n MeetSudoConfig,\n UserTraits,\n EventProperties,\n PageProperties,\n Features,\n InitResponse,\n IdentifyResponse,\n ChatAction,\n ChangelogAction,\n} from \"./types\";\n\nconst STORAGE_KEY = \"meetsudo_anon_id\";\nconst FLUSH_INTERVAL = 5000;\nconst REPLAY_FLUSH_INTERVAL = 10000;\nconst INACTIVITY_TIMEOUT = 60000; // 1 minute\n\ninterface EventData {\n name: string;\n properties: EventProperties;\n page_url: string;\n timestamp: string;\n}\n\ninterface State {\n apiKey: string | null;\n apiUrl: string;\n widgetUrl: string;\n anonId: string | null;\n custId: string | null;\n features: Features | null;\n workspaceName: string | null;\n initialized: boolean;\n iframe: HTMLIFrameElement | null;\n eventQ: EventData[];\n flushTimer: ReturnType<typeof setInterval> | null;\n replaySessionId: string | null;\n replaySequence: number;\n replayEvents: unknown[];\n replayFlushTimer: ReturnType<typeof setInterval> | null;\n replayStopFn: (() => void) | null;\n replayTotalEvents: number;\n replayStartedAt: string | null;\n replayRageClickCount: number;\n replayErrorCount: number;\n lastClickTime: number;\n lastClickTarget: EventTarget | null;\n clickCount: number;\n capturedEmails: Record<string, boolean>;\n lastActivityTime: number;\n inactivityTimer: ReturnType<typeof setTimeout> | null;\n replayPaused: boolean;\n unreadChangelogCount: number;\n}\n\nexport class MeetSudo {\n private state: State = {\n apiKey: null,\n apiUrl: \"https://api.meetsudo.com\",\n widgetUrl: \"https://widget.meetsudo.com\",\n anonId: null,\n custId: null,\n features: null,\n workspaceName: null,\n initialized: false,\n iframe: null,\n eventQ: [],\n flushTimer: null,\n replaySessionId: null,\n replaySequence: 0,\n replayEvents: [],\n replayFlushTimer: null,\n replayStopFn: null,\n replayTotalEvents: 0,\n replayStartedAt: null,\n replayRageClickCount: 0,\n replayErrorCount: 0,\n lastClickTime: 0,\n lastClickTarget: null,\n clickCount: 0,\n capturedEmails: {},\n lastActivityTime: Date.now(),\n inactivityTimer: null,\n replayPaused: false,\n unreadChangelogCount: 0,\n };\n\n private config: MeetSudoConfig | null = null;\n\n /**\n * Initialize the MeetSudo SDK\n */\n async init(config: MeetSudoConfig): Promise<void> {\n if (!config.apiKey) {\n throw new Error(\"MeetSudo: apiKey is required\");\n }\n\n this.config = config;\n this.state.apiKey = config.apiKey;\n this.state.apiUrl = config.apiUrl || \"https://api.meetsudo.com\";\n this.state.widgetUrl = config.widgetUrl || \"https://widget.meetsudo.com\";\n this.state.anonId = this.getAnonId();\n\n try {\n const res = await this.api<InitResponse>(\"/widget/init\", {\n anonymous_id: this.state.anonId,\n url: window.location.href,\n referrer: document.referrer,\n });\n\n this.state.custId = res.customer_id;\n this.state.features = res.features;\n this.state.workspaceName = res.workspace_name;\n this.state.unreadChangelogCount = ((res as unknown) as Record<string, number>).unread_changelog_count || 0;\n this.state.initialized = true;\n\n // Create chat iframe if enabled\n if (res.features.chat_enabled && !config.disableChat) {\n this.createIframe(res);\n }\n\n // Start event tracking if enabled\n if (res.features.events_enabled && !config.disableEvents) {\n this.state.flushTimer = setInterval(() => this.flushEvents(), FLUSH_INTERVAL);\n if (res.features.events_auto_page && !config.disableAutoPageView) {\n this.page();\n }\n this.setupEmailCapture();\n }\n\n // Start session replay if enabled and sampled in\n if (this.shouldSampleReplay() && !config.disableReplay) {\n this.startReplay();\n }\n\n // Setup beforeunload handler\n window.addEventListener(\"beforeunload\", () => this.handleUnload());\n } catch (error) {\n console.error(\"MeetSudo: init failed\", error);\n throw error;\n }\n }\n\n /**\n * Identify a user\n */\n async identify(userId: string, traits?: UserTraits): Promise<void> {\n if (!this.state.initialized) {\n console.warn(\"MeetSudo: call init() before identify()\");\n return;\n }\n\n try {\n const res = await this.api<IdentifyResponse>(\"/widget/identify\", {\n anonymous_id: this.state.anonId,\n external_id: userId,\n properties: traits || {},\n });\n\n this.state.custId = res.customer_id;\n\n // Notify chat iframe about identity change\n if (this.state.iframe?.contentWindow) {\n this.state.iframe.contentWindow.postMessage(\n {\n type: \"fi:identify\",\n customerId: res.customer_id,\n merged: res.merged,\n },\n \"*\"\n );\n }\n } catch (error) {\n console.error(\"MeetSudo: identify failed\", error);\n }\n }\n\n /**\n * Track a custom event\n */\n track(eventName: string, properties?: EventProperties): void {\n if (!this.state.initialized || !this.state.features?.events_enabled) {\n return;\n }\n\n this.state.eventQ.push({\n name: eventName,\n properties: properties || {},\n page_url: window.location.href,\n timestamp: new Date().toISOString(),\n });\n }\n\n /**\n * Track a page view\n */\n page(properties?: PageProperties): void {\n const props: PageProperties = {\n url: window.location.href,\n title: document.title,\n referrer: document.referrer,\n ...properties,\n };\n this.track(\"page_view\", props);\n }\n\n /**\n * Control the chat widget\n */\n chat(action: ChatAction): void {\n if (!this.state.iframe?.contentWindow) return;\n\n switch (action) {\n case \"open\":\n this.state.iframe.contentWindow.postMessage({ type: \"fi:chat\", action: \"open\" }, \"*\");\n this.state.iframe.style.width = \"400px\";\n this.state.iframe.style.height = \"560px\";\n break;\n case \"close\":\n this.state.iframe.contentWindow.postMessage({ type: \"fi:chat\", action: \"close\" }, \"*\");\n this.state.iframe.style.width = \"80px\";\n this.state.iframe.style.height = \"80px\";\n break;\n case \"hide\":\n this.state.iframe.style.display = \"none\";\n break;\n case \"show\":\n this.state.iframe.style.display = \"\";\n break;\n }\n }\n\n /**\n * Control the changelog view\n */\n changelog(action: ChangelogAction): void {\n if (!this.state.iframe?.contentWindow) return;\n this.state.iframe.contentWindow.postMessage({ type: \"fi:changelog\", action }, \"*\");\n if (action === \"open\") {\n this.state.iframe.style.width = \"400px\";\n this.state.iframe.style.height = \"560px\";\n }\n }\n\n /**\n * Check if SDK is initialized\n */\n isInitialized(): boolean {\n return this.state.initialized;\n }\n\n /**\n * Get the anonymous ID\n */\n getAnonymousId(): string | null {\n return this.state.anonId;\n }\n\n /**\n * Get the customer ID (after identify)\n */\n getCustomerId(): string | null {\n return this.state.custId;\n }\n\n // Private methods\n\n private getAnonId(): string {\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored) return stored;\n } catch {\n /* private browsing */\n }\n\n const id = crypto.randomUUID?.() || this.generateUUID();\n try {\n localStorage.setItem(STORAGE_KEY, id);\n } catch {\n /* ignore */\n }\n return id;\n }\n\n private generateUUID(): string {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n return (c === \"x\" ? r : (r & 0x3) | 0x8).toString(16);\n });\n }\n\n private async api<T>(path: string, data: unknown): Promise<T> {\n const res = await fetch(this.state.apiUrl + path, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": this.state.apiKey!,\n },\n body: JSON.stringify(data),\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n return res.json();\n }\n\n private createIframe(initData: InitResponse): void {\n if (this.state.iframe) return;\n\n const pos = this.state.features?.chat_position || \"bottom-right\";\n const iframe = document.createElement(\"iframe\");\n iframe.id = \"meetsudo-widget\";\n const posCSS = pos === \"bottom-left\" ? \"left:0;\" : \"right:0;\";\n iframe.style.cssText = `position:fixed;bottom:0;${posCSS}width:80px;height:80px;border:none;z-index:999999;background:transparent;color-scheme:normal;`;\n iframe.allow = \"clipboard-write\";\n iframe.src = this.state.widgetUrl;\n\n document.body.appendChild(iframe);\n this.state.iframe = iframe;\n\n iframe.onload = () => {\n iframe.contentWindow?.postMessage(\n {\n type: \"fi:config\",\n apiKey: this.state.apiKey,\n apiUrl: this.state.apiUrl,\n anonymousId: this.state.anonId,\n customerId: this.state.custId,\n workspaceName: this.state.workspaceName,\n features: this.state.features,\n conversationId: initData.open_conversation_id,\n messages: initData.messages || [],\n unreadChangelogCount: this.state.unreadChangelogCount,\n },\n \"*\"\n );\n };\n\n window.addEventListener(\"message\", (e) => {\n if (e.data?.type === \"fi:resize\") {\n if (e.data.state === \"open\") {\n iframe.style.width = \"400px\";\n iframe.style.height = \"560px\";\n } else {\n iframe.style.width = \"80px\";\n iframe.style.height = \"80px\";\n }\n }\n });\n }\n\n private flushEvents(): void {\n if (!this.state.eventQ.length) return;\n\n const batch = this.state.eventQ.splice(0);\n this.api(\"/widget/events\", {\n anonymous_id: this.state.anonId,\n events: batch,\n }).catch(() => {\n // Put events back on failure\n this.state.eventQ = batch.concat(this.state.eventQ);\n });\n }\n\n private shouldSampleReplay(): boolean {\n if (!this.state.features?.replay_enabled) return false;\n return Math.random() < (this.state.features.replay_sample_rate || 0);\n }\n\n private startReplay(): void {\n this.state.replaySessionId = crypto.randomUUID?.() || this.generateUUID();\n this.state.replaySequence = 0;\n this.state.replayEvents = [];\n this.state.replayTotalEvents = 0;\n this.state.replayStartedAt = new Date().toISOString();\n this.state.replayErrorCount = 0;\n this.state.replayRageClickCount = 0;\n\n this.setupRageClickDetection();\n this.setupErrorCapture();\n\n // Load rrweb dynamically\n const script = document.createElement(\"script\");\n script.type = \"module\";\n script.src = this.state.widgetUrl.replace(/\\/?(index\\.html)?$/, \"\") + \"/replay.js\";\n document.head.appendChild(script);\n\n // Wait for rrweb to load\n let attempts = 0;\n const checkRrweb = setInterval(() => {\n attempts++;\n // @ts-expect-error rrweb is loaded dynamically\n if (window.rrweb?.record) {\n clearInterval(checkRrweb);\n this.initRrweb();\n } else if (attempts > 50) {\n clearInterval(checkRrweb);\n console.warn(\"MeetSudo: replay failed to load\");\n }\n }, 100);\n }\n\n private initRrweb(): void {\n // @ts-expect-error rrweb is loaded dynamically\n this.state.replayStopFn = window.rrweb.record({\n emit: (event: unknown) => {\n this.state.replayEvents.push(event);\n this.state.replayTotalEvents++;\n },\n maskAllInputs: false,\n maskInputFn: (text: string, element: HTMLElement) => {\n if (this.isSensitiveInput(element)) {\n return \"*\".repeat(text.length || 8);\n }\n return text;\n },\n blockSelector: \".meetsudo-no-record, [data-meetsudo-no-record]\",\n inlineStylesheet: true,\n sampling: {\n mousemove: 50,\n mouseInteraction: true,\n scroll: 150,\n input: \"last\",\n },\n });\n\n this.state.replayFlushTimer = setInterval(() => this.flushReplayChunk(), REPLAY_FLUSH_INTERVAL);\n\n // Setup inactivity tracking\n this.setupActivityTracking();\n }\n\n private setupActivityTracking(): void {\n const activityEvents = [\"mousemove\", \"keydown\", \"click\", \"scroll\", \"touchstart\"];\n\n const handleActivity = () => {\n this.state.lastActivityTime = Date.now();\n\n // Resume replay if it was paused\n if (this.state.replayPaused) {\n this.resumeReplay();\n }\n\n // Reset inactivity timer\n if (this.state.inactivityTimer) {\n clearTimeout(this.state.inactivityTimer);\n }\n\n this.state.inactivityTimer = setTimeout(() => {\n this.pauseReplayDueToInactivity();\n }, INACTIVITY_TIMEOUT);\n };\n\n // Add event listeners\n activityEvents.forEach((event) => {\n document.addEventListener(event, handleActivity, { passive: true });\n });\n\n // Start initial inactivity timer\n this.state.inactivityTimer = setTimeout(() => {\n this.pauseReplayDueToInactivity();\n }, INACTIVITY_TIMEOUT);\n }\n\n private pauseReplayDueToInactivity(): void {\n if (this.state.replayPaused || !this.state.replaySessionId) return;\n\n this.state.replayPaused = true;\n\n // Stop rrweb recording\n if (this.state.replayStopFn) {\n this.state.replayStopFn();\n this.state.replayStopFn = null;\n }\n\n // Flush remaining events\n this.flushReplayChunk();\n\n // Stop flush timer\n if (this.state.replayFlushTimer) {\n clearInterval(this.state.replayFlushTimer);\n this.state.replayFlushTimer = null;\n }\n\n // Send end signal with inactivity flag\n if (this.state.apiKey) {\n this.api(\"/widget/replay/end\", {\n anonymous_id: this.state.anonId,\n session_id: this.state.replaySessionId,\n ended_at: new Date().toISOString(),\n event_count: this.state.replayTotalEvents,\n error_count: this.state.replayErrorCount,\n rage_click_count: this.state.replayRageClickCount,\n end_reason: \"inactivity\",\n }).catch(() => {});\n }\n }\n\n private resumeReplay(): void {\n if (!this.state.replayPaused || !this.state.features?.replay_enabled) return;\n\n this.state.replayPaused = false;\n\n // Start a new replay session\n this.state.replaySessionId = crypto.randomUUID?.() || this.generateUUID();\n this.state.replaySequence = 0;\n this.state.replayEvents = [];\n this.state.replayTotalEvents = 0;\n this.state.replayStartedAt = new Date().toISOString();\n this.state.replayErrorCount = 0;\n this.state.replayRageClickCount = 0;\n\n // Restart rrweb recording\n // @ts-expect-error rrweb is loaded dynamically\n if (window.rrweb?.record) {\n // @ts-expect-error rrweb is loaded dynamically\n this.state.replayStopFn = window.rrweb.record({\n emit: (event: unknown) => {\n this.state.replayEvents.push(event);\n this.state.replayTotalEvents++;\n },\n maskAllInputs: false,\n maskInputFn: (text: string, element: HTMLElement) => {\n if (this.isSensitiveInput(element)) {\n return \"*\".repeat(text.length || 8);\n }\n return text;\n },\n blockSelector: \".meetsudo-no-record, [data-meetsudo-no-record]\",\n inlineStylesheet: true,\n sampling: {\n mousemove: 50,\n mouseInteraction: true,\n scroll: 150,\n input: \"last\",\n },\n });\n\n this.state.replayFlushTimer = setInterval(() => this.flushReplayChunk(), REPLAY_FLUSH_INTERVAL);\n }\n }\n\n private isSensitiveInput(el: HTMLElement): boolean {\n if (!el) return true;\n const input = el as HTMLInputElement;\n const type = (input.type || \"\").toLowerCase();\n const name = (input.name || \"\").toLowerCase();\n const id = (input.id || \"\").toLowerCase();\n\n if (type === \"password\") return true;\n\n const sensitivePatterns = [/password/i, /card/i, /cvv/i, /cvc/i, /ssn/i, /secret/i, /token/i];\n const identifiers = name + \" \" + id;\n return sensitivePatterns.some((p) => p.test(identifiers));\n }\n\n private flushReplayChunk(): void {\n if (!this.state.replayEvents.length || this.state.replayPaused) return;\n\n const events = this.state.replayEvents.splice(0);\n const seq = this.state.replaySequence++;\n\n const payload: Record<string, unknown> = {\n anonymous_id: this.state.anonId,\n session_id: this.state.replaySessionId,\n sequence: seq,\n events,\n error_count: this.state.replayErrorCount,\n rage_click_count: this.state.replayRageClickCount,\n };\n\n if (seq === 0) {\n payload.page_url = window.location.href;\n payload.user_agent = navigator.userAgent;\n payload.screen_width = window.innerWidth;\n payload.screen_height = window.innerHeight;\n payload.started_at = this.state.replayStartedAt;\n }\n\n this.api(\"/widget/replay/chunk\", payload).catch(() => {\n this.state.replayEvents = events.concat(this.state.replayEvents);\n this.state.replaySequence--;\n });\n }\n\n private setupRageClickDetection(): void {\n document.addEventListener(\n \"click\",\n (e) => {\n if (!this.state.replaySessionId) return;\n\n const now = Date.now();\n const target = e.target;\n\n if (target === this.state.lastClickTarget && now - this.state.lastClickTime < 500) {\n this.state.clickCount++;\n if (this.state.clickCount >= 3) {\n this.state.replayRageClickCount++;\n this.state.clickCount = 0;\n this.track(\"rage_click\", { page_url: window.location.href });\n }\n } else {\n this.state.clickCount = 1;\n }\n\n this.state.lastClickTime = now;\n this.state.lastClickTarget = target;\n },\n true\n );\n }\n\n private setupErrorCapture(): void {\n window.onerror = (message, source, lineno, colno) => {\n if (this.state.replaySessionId) {\n this.state.replayErrorCount++;\n this.track(\"js_error\", {\n message: String(message).substring(0, 500),\n source: source || \"\",\n lineno: lineno || 0,\n });\n }\n return false;\n };\n\n window.addEventListener(\"unhandledrejection\", (e) => {\n if (this.state.replaySessionId) {\n this.state.replayErrorCount++;\n const message = e.reason instanceof Error ? e.reason.message : String(e.reason);\n this.track(\"js_error\", { message: message.substring(0, 500), type: \"unhandledrejection\" });\n }\n });\n }\n\n private setupEmailCapture(): void {\n document.addEventListener(\n \"blur\",\n (e) => {\n const el = e.target as HTMLInputElement;\n if (!el || el.tagName !== \"INPUT\") return;\n\n const type = (el.type || \"\").toLowerCase();\n const name = (el.name || \"\").toLowerCase();\n if (type === \"email\" || /email/.test(name)) {\n const value = el.value?.trim();\n if (value && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value) && !this.state.capturedEmails[value]) {\n this.state.capturedEmails[value] = true;\n this.track(\"email_captured\", { email: value });\n }\n }\n },\n true\n );\n }\n\n private handleUnload(): void {\n if (this.state.flushTimer) {\n clearInterval(this.state.flushTimer);\n }\n\n // Flush remaining events\n if (this.state.eventQ.length && this.state.apiKey) {\n const apiKey = this.state.apiKey;\n try {\n fetch(this.state.apiUrl + \"/widget/events\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": apiKey,\n },\n body: JSON.stringify({\n anonymous_id: this.state.anonId,\n events: this.state.eventQ,\n }),\n keepalive: true,\n }).catch(() => {});\n } catch {\n /* ignore */\n }\n }\n\n // End replay\n if (this.state.replaySessionId && this.state.apiKey) {\n const replayApiKey = this.state.apiKey;\n if (this.state.replayStopFn) {\n this.state.replayStopFn();\n }\n if (this.state.replayFlushTimer) {\n clearInterval(this.state.replayFlushTimer);\n }\n\n try {\n fetch(this.state.apiUrl + \"/widget/replay/end\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": replayApiKey,\n },\n body: JSON.stringify({\n anonymous_id: this.state.anonId,\n session_id: this.state.replaySessionId,\n ended_at: new Date().toISOString(),\n event_count: this.state.replayTotalEvents,\n error_count: this.state.replayErrorCount,\n rage_click_count: this.state.replayRageClickCount,\n }),\n keepalive: true,\n }).catch(() => {});\n } catch {\n /* ignore */\n }\n }\n }\n}\n"],"mappings":"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","names":["browser_exports","__export","MeetSudo","meetsudo","STORAGE_KEY","MeetSudo","config","res","error","userId","traits","eventName","properties","props","action","stored","STORAGE_KEY","id","c","r","path","data","initData","pos","iframe","posCSS","e","batch","script","attempts","checkRrweb","event","text","element","activityEvents","handleActivity","el","input","type","name","sensitivePatterns","identifiers","p","events","seq","payload","now","target","message","source","lineno","colno","value","apiKey","replayApiKey","meetsudo","MeetSudo","MeetSudo","meetsudo"]}
1
+ {"version":3,"sources":["../src/browser.ts","../src/sdk.ts"],"sourcesContent":["/**\n * Browser bundle entry point for script tag usage\n * This file is bundled as an IIFE and exposes window.MeetSudo\n */\nimport { MeetSudo } from \"./sdk\";\nimport type {\n MeetSudoConfig,\n UserTraits,\n EventProperties,\n PageProperties,\n ChatAction,\n ChangelogAction,\n BookingAction,\n} from \"./types\";\n\n// Create default instance\nconst meetsudo = new MeetSudo();\n\n// Export everything for the IIFE global\nexport { MeetSudo, meetsudo };\nexport type {\n MeetSudoConfig,\n UserTraits,\n EventProperties,\n PageProperties,\n ChatAction,\n ChangelogAction,\n BookingAction,\n};\n\n// Make it available globally\nif (typeof window !== \"undefined\") {\n (window as unknown as Record<string, unknown>).MeetSudo = {\n MeetSudo,\n meetsudo,\n init: meetsudo.init.bind(meetsudo),\n identify: meetsudo.identify.bind(meetsudo),\n track: meetsudo.track.bind(meetsudo),\n page: meetsudo.page.bind(meetsudo),\n chat: meetsudo.chat.bind(meetsudo),\n changelog: meetsudo.changelog.bind(meetsudo),\n booking: meetsudo.booking.bind(meetsudo),\n };\n}\n","import type {\n MeetSudoConfig,\n UserTraits,\n EventProperties,\n PageProperties,\n Features,\n InitResponse,\n IdentifyResponse,\n ChatAction,\n ChangelogAction,\n BookingAction,\n} from \"./types\";\n\nconst STORAGE_KEY = \"meetsudo_anon_id\";\nconst FLUSH_INTERVAL = 5000;\nconst REPLAY_FLUSH_INTERVAL = 10000;\nconst INACTIVITY_TIMEOUT = 60000; // 1 minute\n\ninterface EventData {\n name: string;\n properties: EventProperties;\n page_url: string;\n timestamp: string;\n}\n\ninterface State {\n apiKey: string | null;\n apiUrl: string;\n widgetUrl: string;\n anonId: string | null;\n custId: string | null;\n features: Features | null;\n workspaceName: string | null;\n initialized: boolean;\n iframe: HTMLIFrameElement | null;\n eventQ: EventData[];\n flushTimer: ReturnType<typeof setInterval> | null;\n replaySessionId: string | null;\n replaySequence: number;\n replayEvents: unknown[];\n replayFlushTimer: ReturnType<typeof setInterval> | null;\n replayStopFn: (() => void) | null;\n replayTotalEvents: number;\n replayStartedAt: string | null;\n replayRageClickCount: number;\n replayErrorCount: number;\n lastClickTime: number;\n lastClickTarget: EventTarget | null;\n clickCount: number;\n capturedEmails: Record<string, boolean>;\n lastActivityTime: number;\n inactivityTimer: ReturnType<typeof setTimeout> | null;\n replayPaused: boolean;\n unreadChangelogCount: number;\n}\n\nexport class MeetSudo {\n private state: State = {\n apiKey: null,\n apiUrl: \"https://api.meetsudo.com\",\n widgetUrl: \"https://widget.meetsudo.com\",\n anonId: null,\n custId: null,\n features: null,\n workspaceName: null,\n initialized: false,\n iframe: null,\n eventQ: [],\n flushTimer: null,\n replaySessionId: null,\n replaySequence: 0,\n replayEvents: [],\n replayFlushTimer: null,\n replayStopFn: null,\n replayTotalEvents: 0,\n replayStartedAt: null,\n replayRageClickCount: 0,\n replayErrorCount: 0,\n lastClickTime: 0,\n lastClickTarget: null,\n clickCount: 0,\n capturedEmails: {},\n lastActivityTime: Date.now(),\n inactivityTimer: null,\n replayPaused: false,\n unreadChangelogCount: 0,\n };\n\n private config: MeetSudoConfig | null = null;\n\n /**\n * Initialize the MeetSudo SDK\n */\n async init(config: MeetSudoConfig): Promise<void> {\n if (!config.apiKey) {\n throw new Error(\"MeetSudo: apiKey is required\");\n }\n\n this.config = config;\n this.state.apiKey = config.apiKey;\n this.state.apiUrl = config.apiUrl || \"https://api.meetsudo.com\";\n this.state.widgetUrl = config.widgetUrl || \"https://widget.meetsudo.com\";\n this.state.anonId = this.getAnonId();\n\n try {\n const res = await this.api<InitResponse>(\"/widget/init\", {\n anonymous_id: this.state.anonId,\n url: window.location.href,\n referrer: document.referrer,\n });\n\n this.state.custId = res.customer_id;\n this.state.features = res.features;\n this.state.workspaceName = res.workspace_name;\n this.state.unreadChangelogCount = ((res as unknown) as Record<string, number>).unread_changelog_count || 0;\n this.state.initialized = true;\n\n // Create widget iframe if any interactive widget view is enabled\n if ((res.features.chat_enabled && !config.disableChat) || res.features.booking_enabled) {\n this.createIframe(res);\n }\n\n // Start event tracking if enabled\n if (res.features.events_enabled && !config.disableEvents) {\n this.state.flushTimer = setInterval(() => this.flushEvents(), FLUSH_INTERVAL);\n if (res.features.events_auto_page && !config.disableAutoPageView) {\n this.page();\n }\n this.setupEmailCapture();\n }\n\n // Start session replay if enabled and sampled in\n if (this.shouldSampleReplay() && !config.disableReplay) {\n this.startReplay();\n }\n\n // Setup beforeunload handler\n window.addEventListener(\"beforeunload\", () => this.handleUnload());\n } catch (error) {\n console.error(\"MeetSudo: init failed\", error);\n throw error;\n }\n }\n\n /**\n * Identify a user\n */\n async identify(userId: string, traits?: UserTraits): Promise<void> {\n if (!this.state.initialized) {\n console.warn(\"MeetSudo: call init() before identify()\");\n return;\n }\n\n try {\n const res = await this.api<IdentifyResponse>(\"/widget/identify\", {\n anonymous_id: this.state.anonId,\n external_id: userId,\n properties: traits || {},\n });\n\n this.state.custId = res.customer_id;\n\n // Notify chat iframe about identity change\n if (this.state.iframe?.contentWindow) {\n this.state.iframe.contentWindow.postMessage(\n {\n type: \"fi:identify\",\n customerId: res.customer_id,\n merged: res.merged,\n },\n \"*\"\n );\n }\n } catch (error) {\n console.error(\"MeetSudo: identify failed\", error);\n }\n }\n\n /**\n * Track a custom event\n */\n track(eventName: string, properties?: EventProperties): void {\n if (!this.state.initialized || !this.state.features?.events_enabled) {\n return;\n }\n\n this.state.eventQ.push({\n name: eventName,\n properties: properties || {},\n page_url: window.location.href,\n timestamp: new Date().toISOString(),\n });\n }\n\n /**\n * Track a page view\n */\n page(properties?: PageProperties): void {\n const props: PageProperties = {\n url: window.location.href,\n title: document.title,\n referrer: document.referrer,\n ...properties,\n };\n this.track(\"page_view\", props);\n }\n\n /**\n * Control the chat widget\n */\n chat(action: ChatAction): void {\n if (!this.state.iframe?.contentWindow) return;\n\n switch (action) {\n case \"open\":\n this.state.iframe.contentWindow.postMessage({ type: \"fi:chat\", action: \"open\" }, \"*\");\n this.state.iframe.style.width = \"400px\";\n this.state.iframe.style.height = \"560px\";\n break;\n case \"close\":\n this.state.iframe.contentWindow.postMessage({ type: \"fi:chat\", action: \"close\" }, \"*\");\n this.state.iframe.style.width = \"80px\";\n this.state.iframe.style.height = \"80px\";\n break;\n case \"hide\":\n this.state.iframe.style.display = \"none\";\n break;\n case \"show\":\n this.state.iframe.style.display = \"\";\n break;\n }\n }\n\n /**\n * Control the changelog view\n */\n changelog(action: ChangelogAction): void {\n if (!this.state.iframe?.contentWindow) return;\n this.state.iframe.contentWindow.postMessage({ type: \"fi:changelog\", action }, \"*\");\n if (action === \"open\") {\n this.state.iframe.style.width = \"400px\";\n this.state.iframe.style.height = \"560px\";\n }\n }\n\n /**\n * Control the booking scheduler view\n */\n booking(action: BookingAction): void {\n if (!this.state.iframe?.contentWindow) return;\n this.state.iframe.contentWindow.postMessage({ type: \"fi:booking\", action }, \"*\");\n if (action === \"open\") {\n this.state.iframe.style.width = \"400px\";\n this.state.iframe.style.height = \"560px\";\n }\n }\n\n /**\n * Check if SDK is initialized\n */\n isInitialized(): boolean {\n return this.state.initialized;\n }\n\n /**\n * Get the anonymous ID\n */\n getAnonymousId(): string | null {\n return this.state.anonId;\n }\n\n /**\n * Get the customer ID (after identify)\n */\n getCustomerId(): string | null {\n return this.state.custId;\n }\n\n // Private methods\n\n private getAnonId(): string {\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored) return stored;\n } catch {\n /* private browsing */\n }\n\n const id = crypto.randomUUID?.() || this.generateUUID();\n try {\n localStorage.setItem(STORAGE_KEY, id);\n } catch {\n /* ignore */\n }\n return id;\n }\n\n private generateUUID(): string {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n return (c === \"x\" ? r : (r & 0x3) | 0x8).toString(16);\n });\n }\n\n private async api<T>(path: string, data: unknown): Promise<T> {\n const res = await fetch(this.state.apiUrl + path, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": this.state.apiKey!,\n },\n body: JSON.stringify(data),\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n return res.json();\n }\n\n private createIframe(initData: InitResponse): void {\n if (this.state.iframe) return;\n\n const pos = this.state.features?.chat_position || \"bottom-right\";\n const iframe = document.createElement(\"iframe\");\n iframe.id = \"meetsudo-widget\";\n const posCSS = pos === \"bottom-left\" ? \"left:0;\" : \"right:0;\";\n iframe.style.cssText = `position:fixed;bottom:0;${posCSS}width:80px;height:80px;border:none;z-index:999999;background:transparent;color-scheme:normal;`;\n iframe.allow = \"clipboard-write\";\n iframe.src = this.state.widgetUrl;\n\n document.body.appendChild(iframe);\n this.state.iframe = iframe;\n\n iframe.onload = () => {\n iframe.contentWindow?.postMessage(\n {\n type: \"fi:config\",\n apiKey: this.state.apiKey,\n apiUrl: this.state.apiUrl,\n anonymousId: this.state.anonId,\n customerId: this.state.custId,\n workspaceName: this.state.workspaceName,\n features: this.state.features,\n conversationId: initData.open_conversation_id,\n messages: initData.messages || [],\n unreadChangelogCount: this.state.unreadChangelogCount,\n },\n \"*\"\n );\n };\n\n window.addEventListener(\"message\", (e) => {\n if (e.data?.type === \"fi:resize\") {\n if (e.data.state === \"open\") {\n iframe.style.width = \"400px\";\n iframe.style.height = \"560px\";\n } else {\n iframe.style.width = \"80px\";\n iframe.style.height = \"80px\";\n }\n }\n });\n }\n\n private flushEvents(): void {\n if (!this.state.eventQ.length) return;\n\n const batch = this.state.eventQ.splice(0);\n this.api(\"/widget/events\", {\n anonymous_id: this.state.anonId,\n events: batch,\n }).catch(() => {\n // Put events back on failure\n this.state.eventQ = batch.concat(this.state.eventQ);\n });\n }\n\n private shouldSampleReplay(): boolean {\n if (!this.state.features?.replay_enabled) return false;\n return Math.random() < (this.state.features.replay_sample_rate || 0);\n }\n\n private startReplay(): void {\n this.state.replaySessionId = crypto.randomUUID?.() || this.generateUUID();\n this.state.replaySequence = 0;\n this.state.replayEvents = [];\n this.state.replayTotalEvents = 0;\n this.state.replayStartedAt = new Date().toISOString();\n this.state.replayErrorCount = 0;\n this.state.replayRageClickCount = 0;\n\n this.setupRageClickDetection();\n this.setupErrorCapture();\n\n // Load rrweb dynamically\n const script = document.createElement(\"script\");\n script.type = \"module\";\n script.src = this.state.widgetUrl.replace(/\\/?(index\\.html)?$/, \"\") + \"/replay.js\";\n document.head.appendChild(script);\n\n // Wait for rrweb to load\n let attempts = 0;\n const checkRrweb = setInterval(() => {\n attempts++;\n // @ts-expect-error rrweb is loaded dynamically\n if (window.rrweb?.record) {\n clearInterval(checkRrweb);\n this.initRrweb();\n } else if (attempts > 50) {\n clearInterval(checkRrweb);\n console.warn(\"MeetSudo: replay failed to load\");\n }\n }, 100);\n }\n\n private initRrweb(): void {\n // @ts-expect-error rrweb is loaded dynamically\n this.state.replayStopFn = window.rrweb.record({\n emit: (event: unknown) => {\n this.state.replayEvents.push(event);\n this.state.replayTotalEvents++;\n },\n maskAllInputs: false,\n maskInputFn: (text: string, element: HTMLElement) => {\n if (this.isSensitiveInput(element)) {\n return \"*\".repeat(text.length || 8);\n }\n return text;\n },\n blockSelector: \".meetsudo-no-record, [data-meetsudo-no-record]\",\n inlineStylesheet: true,\n sampling: {\n mousemove: 50,\n mouseInteraction: true,\n scroll: 150,\n input: \"last\",\n },\n });\n\n this.state.replayFlushTimer = setInterval(() => this.flushReplayChunk(), REPLAY_FLUSH_INTERVAL);\n\n // Setup inactivity tracking\n this.setupActivityTracking();\n }\n\n private setupActivityTracking(): void {\n const activityEvents = [\"mousemove\", \"keydown\", \"click\", \"scroll\", \"touchstart\"];\n\n const handleActivity = () => {\n this.state.lastActivityTime = Date.now();\n\n // Resume replay if it was paused\n if (this.state.replayPaused) {\n this.resumeReplay();\n }\n\n // Reset inactivity timer\n if (this.state.inactivityTimer) {\n clearTimeout(this.state.inactivityTimer);\n }\n\n this.state.inactivityTimer = setTimeout(() => {\n this.pauseReplayDueToInactivity();\n }, INACTIVITY_TIMEOUT);\n };\n\n // Add event listeners\n activityEvents.forEach((event) => {\n document.addEventListener(event, handleActivity, { passive: true });\n });\n\n // Start initial inactivity timer\n this.state.inactivityTimer = setTimeout(() => {\n this.pauseReplayDueToInactivity();\n }, INACTIVITY_TIMEOUT);\n }\n\n private pauseReplayDueToInactivity(): void {\n if (this.state.replayPaused || !this.state.replaySessionId) return;\n\n this.state.replayPaused = true;\n\n // Stop rrweb recording\n if (this.state.replayStopFn) {\n this.state.replayStopFn();\n this.state.replayStopFn = null;\n }\n\n // Flush remaining events\n this.flushReplayChunk();\n\n // Stop flush timer\n if (this.state.replayFlushTimer) {\n clearInterval(this.state.replayFlushTimer);\n this.state.replayFlushTimer = null;\n }\n\n // Send end signal with inactivity flag\n if (this.state.apiKey) {\n this.api(\"/widget/replay/end\", {\n anonymous_id: this.state.anonId,\n session_id: this.state.replaySessionId,\n ended_at: new Date().toISOString(),\n event_count: this.state.replayTotalEvents,\n error_count: this.state.replayErrorCount,\n rage_click_count: this.state.replayRageClickCount,\n end_reason: \"inactivity\",\n }).catch(() => {});\n }\n }\n\n private resumeReplay(): void {\n if (!this.state.replayPaused || !this.state.features?.replay_enabled) return;\n\n this.state.replayPaused = false;\n\n // Start a new replay session\n this.state.replaySessionId = crypto.randomUUID?.() || this.generateUUID();\n this.state.replaySequence = 0;\n this.state.replayEvents = [];\n this.state.replayTotalEvents = 0;\n this.state.replayStartedAt = new Date().toISOString();\n this.state.replayErrorCount = 0;\n this.state.replayRageClickCount = 0;\n\n // Restart rrweb recording\n // @ts-expect-error rrweb is loaded dynamically\n if (window.rrweb?.record) {\n // @ts-expect-error rrweb is loaded dynamically\n this.state.replayStopFn = window.rrweb.record({\n emit: (event: unknown) => {\n this.state.replayEvents.push(event);\n this.state.replayTotalEvents++;\n },\n maskAllInputs: false,\n maskInputFn: (text: string, element: HTMLElement) => {\n if (this.isSensitiveInput(element)) {\n return \"*\".repeat(text.length || 8);\n }\n return text;\n },\n blockSelector: \".meetsudo-no-record, [data-meetsudo-no-record]\",\n inlineStylesheet: true,\n sampling: {\n mousemove: 50,\n mouseInteraction: true,\n scroll: 150,\n input: \"last\",\n },\n });\n\n this.state.replayFlushTimer = setInterval(() => this.flushReplayChunk(), REPLAY_FLUSH_INTERVAL);\n }\n }\n\n private isSensitiveInput(el: HTMLElement): boolean {\n if (!el) return true;\n const input = el as HTMLInputElement;\n const type = (input.type || \"\").toLowerCase();\n const name = (input.name || \"\").toLowerCase();\n const id = (input.id || \"\").toLowerCase();\n\n if (type === \"password\") return true;\n\n const sensitivePatterns = [/password/i, /card/i, /cvv/i, /cvc/i, /ssn/i, /secret/i, /token/i];\n const identifiers = name + \" \" + id;\n return sensitivePatterns.some((p) => p.test(identifiers));\n }\n\n private flushReplayChunk(): void {\n if (!this.state.replayEvents.length || this.state.replayPaused) return;\n\n const events = this.state.replayEvents.splice(0);\n const seq = this.state.replaySequence++;\n\n const payload: Record<string, unknown> = {\n anonymous_id: this.state.anonId,\n session_id: this.state.replaySessionId,\n sequence: seq,\n events,\n error_count: this.state.replayErrorCount,\n rage_click_count: this.state.replayRageClickCount,\n };\n\n if (seq === 0) {\n payload.page_url = window.location.href;\n payload.user_agent = navigator.userAgent;\n payload.screen_width = window.innerWidth;\n payload.screen_height = window.innerHeight;\n payload.started_at = this.state.replayStartedAt;\n }\n\n this.api(\"/widget/replay/chunk\", payload).catch(() => {\n this.state.replayEvents = events.concat(this.state.replayEvents);\n this.state.replaySequence--;\n });\n }\n\n private setupRageClickDetection(): void {\n document.addEventListener(\n \"click\",\n (e) => {\n if (!this.state.replaySessionId) return;\n\n const now = Date.now();\n const target = e.target;\n\n if (target === this.state.lastClickTarget && now - this.state.lastClickTime < 500) {\n this.state.clickCount++;\n if (this.state.clickCount >= 3) {\n this.state.replayRageClickCount++;\n this.state.clickCount = 0;\n this.track(\"rage_click\", { page_url: window.location.href });\n }\n } else {\n this.state.clickCount = 1;\n }\n\n this.state.lastClickTime = now;\n this.state.lastClickTarget = target;\n },\n true\n );\n }\n\n private setupErrorCapture(): void {\n window.onerror = (message, source, lineno, colno) => {\n if (this.state.replaySessionId) {\n this.state.replayErrorCount++;\n this.track(\"js_error\", {\n message: String(message).substring(0, 500),\n source: source || \"\",\n lineno: lineno || 0,\n });\n }\n return false;\n };\n\n window.addEventListener(\"unhandledrejection\", (e) => {\n if (this.state.replaySessionId) {\n this.state.replayErrorCount++;\n const message = e.reason instanceof Error ? e.reason.message : String(e.reason);\n this.track(\"js_error\", { message: message.substring(0, 500), type: \"unhandledrejection\" });\n }\n });\n }\n\n private setupEmailCapture(): void {\n document.addEventListener(\n \"blur\",\n (e) => {\n const el = e.target as HTMLInputElement;\n if (!el || el.tagName !== \"INPUT\") return;\n\n const type = (el.type || \"\").toLowerCase();\n const name = (el.name || \"\").toLowerCase();\n if (type === \"email\" || /email/.test(name)) {\n const value = el.value?.trim();\n if (value && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value) && !this.state.capturedEmails[value]) {\n this.state.capturedEmails[value] = true;\n this.track(\"email_captured\", { email: value });\n }\n }\n },\n true\n );\n }\n\n private handleUnload(): void {\n if (this.state.flushTimer) {\n clearInterval(this.state.flushTimer);\n }\n\n // Flush remaining events\n if (this.state.eventQ.length && this.state.apiKey) {\n const apiKey = this.state.apiKey;\n try {\n fetch(this.state.apiUrl + \"/widget/events\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": apiKey,\n },\n body: JSON.stringify({\n anonymous_id: this.state.anonId,\n events: this.state.eventQ,\n }),\n keepalive: true,\n }).catch(() => {});\n } catch {\n /* ignore */\n }\n }\n\n // End replay\n if (this.state.replaySessionId && this.state.apiKey) {\n const replayApiKey = this.state.apiKey;\n if (this.state.replayStopFn) {\n this.state.replayStopFn();\n }\n if (this.state.replayFlushTimer) {\n clearInterval(this.state.replayFlushTimer);\n }\n\n try {\n fetch(this.state.apiUrl + \"/widget/replay/end\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": replayApiKey,\n },\n body: JSON.stringify({\n anonymous_id: this.state.anonId,\n session_id: this.state.replaySessionId,\n ended_at: new Date().toISOString(),\n event_count: this.state.replayTotalEvents,\n error_count: this.state.replayErrorCount,\n rage_click_count: this.state.replayRageClickCount,\n }),\n keepalive: true,\n }).catch(() => {});\n } catch {\n /* ignore */\n }\n }\n }\n}\n"],"mappings":"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","names":["browser_exports","__export","MeetSudo","meetsudo","STORAGE_KEY","MeetSudo","config","res","error","userId","traits","eventName","properties","props","action","stored","STORAGE_KEY","id","c","r","path","data","initData","pos","iframe","posCSS","e","batch","script","attempts","checkRrweb","event","text","element","activityEvents","handleActivity","el","input","type","name","sensitivePatterns","identifiers","p","events","seq","payload","now","target","message","source","lineno","colno","value","apiKey","replayApiKey","meetsudo","MeetSudo","MeetSudo","meetsudo"]}
package/dist/server.d.mts CHANGED
@@ -45,6 +45,16 @@ interface LogSchemaHintsResponse {
45
45
  levels: string[];
46
46
  sources: string[];
47
47
  }
48
+ interface ChangelogEntry {
49
+ id: string;
50
+ workspace_id: string;
51
+ title: string;
52
+ content: string;
53
+ is_published: boolean;
54
+ published_at: string | null;
55
+ created_at: string;
56
+ updated_at: string;
57
+ }
48
58
  declare class MeetSudoServer {
49
59
  private apiKey;
50
60
  private secretKey;
@@ -147,6 +157,27 @@ declare class MeetSudoServer {
147
157
  * Get observed workspace log schema hints (services/events/prop keys).
148
158
  */
149
159
  getLogSchemaHints(): Promise<LogSchemaHintsResponse>;
160
+ /**
161
+ * Publish a What's New entry (changelog) immediately.
162
+ * Requires secretKey.
163
+ */
164
+ publishWhatsNew(title: string, content: string): Promise<{
165
+ entry: ChangelogEntry;
166
+ }>;
167
+ /**
168
+ * Create a What's New draft (not published).
169
+ * Requires secretKey.
170
+ */
171
+ createWhatsNewDraft(title: string, content: string): Promise<{
172
+ entry: ChangelogEntry;
173
+ }>;
174
+ /**
175
+ * Publish or unpublish an existing What's New entry.
176
+ * Requires secretKey.
177
+ */
178
+ setWhatsNewPublished(entryId: string, isPublished?: boolean): Promise<{
179
+ entry: ChangelogEntry;
180
+ }>;
150
181
  }
151
182
 
152
- export { type EventProperties, type LogAssistResponse, type LogEntry, type LogQueryRequest, type LogSchemaHintsResponse, MeetSudoServer, type MeetSudoServerConfig, type UserTraits, MeetSudoServer as default };
183
+ export { type ChangelogEntry, type EventProperties, type LogAssistResponse, type LogEntry, type LogQueryRequest, type LogSchemaHintsResponse, MeetSudoServer, type MeetSudoServerConfig, type UserTraits, MeetSudoServer as default };
package/dist/server.d.ts CHANGED
@@ -45,6 +45,16 @@ interface LogSchemaHintsResponse {
45
45
  levels: string[];
46
46
  sources: string[];
47
47
  }
48
+ interface ChangelogEntry {
49
+ id: string;
50
+ workspace_id: string;
51
+ title: string;
52
+ content: string;
53
+ is_published: boolean;
54
+ published_at: string | null;
55
+ created_at: string;
56
+ updated_at: string;
57
+ }
48
58
  declare class MeetSudoServer {
49
59
  private apiKey;
50
60
  private secretKey;
@@ -147,6 +157,27 @@ declare class MeetSudoServer {
147
157
  * Get observed workspace log schema hints (services/events/prop keys).
148
158
  */
149
159
  getLogSchemaHints(): Promise<LogSchemaHintsResponse>;
160
+ /**
161
+ * Publish a What's New entry (changelog) immediately.
162
+ * Requires secretKey.
163
+ */
164
+ publishWhatsNew(title: string, content: string): Promise<{
165
+ entry: ChangelogEntry;
166
+ }>;
167
+ /**
168
+ * Create a What's New draft (not published).
169
+ * Requires secretKey.
170
+ */
171
+ createWhatsNewDraft(title: string, content: string): Promise<{
172
+ entry: ChangelogEntry;
173
+ }>;
174
+ /**
175
+ * Publish or unpublish an existing What's New entry.
176
+ * Requires secretKey.
177
+ */
178
+ setWhatsNewPublished(entryId: string, isPublished?: boolean): Promise<{
179
+ entry: ChangelogEntry;
180
+ }>;
150
181
  }
151
182
 
152
- export { type EventProperties, type LogAssistResponse, type LogEntry, type LogQueryRequest, type LogSchemaHintsResponse, MeetSudoServer, type MeetSudoServerConfig, type UserTraits, MeetSudoServer as default };
183
+ export { type ChangelogEntry, type EventProperties, type LogAssistResponse, type LogEntry, type LogQueryRequest, type LogSchemaHintsResponse, MeetSudoServer, type MeetSudoServerConfig, type UserTraits, MeetSudoServer as default };
package/dist/server.js CHANGED
@@ -191,6 +191,46 @@ var MeetSudoServer = class {
191
191
  async getLogSchemaHints() {
192
192
  return this.requestSecret("GET", "/logs/schema-hints/secret");
193
193
  }
194
+ /**
195
+ * Publish a What's New entry (changelog) immediately.
196
+ * Requires secretKey.
197
+ */
198
+ async publishWhatsNew(title, content) {
199
+ if (!title.trim() || !content.trim()) {
200
+ throw new Error("MeetSudoServer: title and content are required");
201
+ }
202
+ return this.requestSecret("POST", "/changelog/secret", {
203
+ title: title.trim(),
204
+ content: content.trim(),
205
+ is_published: true
206
+ });
207
+ }
208
+ /**
209
+ * Create a What's New draft (not published).
210
+ * Requires secretKey.
211
+ */
212
+ async createWhatsNewDraft(title, content) {
213
+ if (!title.trim() || !content.trim()) {
214
+ throw new Error("MeetSudoServer: title and content are required");
215
+ }
216
+ return this.requestSecret("POST", "/changelog/secret", {
217
+ title: title.trim(),
218
+ content: content.trim(),
219
+ is_published: false
220
+ });
221
+ }
222
+ /**
223
+ * Publish or unpublish an existing What's New entry.
224
+ * Requires secretKey.
225
+ */
226
+ async setWhatsNewPublished(entryId, isPublished = true) {
227
+ if (!entryId.trim()) {
228
+ throw new Error("MeetSudoServer: entryId is required");
229
+ }
230
+ return this.requestSecret("PATCH", `/changelog/secret/${entryId}/publish`, {
231
+ is_published: isPublished
232
+ });
233
+ }
194
234
  };
195
235
  var server_default = MeetSudoServer;
196
236
  // Annotate the CommonJS export names for ESM import in node:
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\n * MeetSudo Server SDK\n * Use this for server-side event tracking, user identification, and API calls.\n */\n\nexport interface MeetSudoServerConfig {\n apiKey?: string;\n secretKey?: string;\n apiUrl?: string;\n}\n\nexport interface UserTraits {\n email?: string;\n name?: string;\n [key: string]: unknown;\n}\n\nexport interface EventProperties {\n [key: string]: unknown;\n}\n\nexport interface LogEntry {\n ts?: string;\n level?: \"debug\" | \"info\" | \"warn\" | \"error\";\n source?: \"backend\" | \"frontend\" | \"sdk\" | \"system\";\n service?: string;\n event?: string;\n message: string;\n user_id?: string;\n request_id?: string;\n trace_id?: string;\n tags?: Record<string, string>;\n props?: Record<string, unknown>;\n}\n\nexport interface LogQueryRequest {\n query?: string;\n from?: string;\n to?: string;\n limit?: number;\n}\n\nexport interface LogAssistResponse {\n query: string;\n explanation: string;\n}\n\nexport interface LogSchemaHintsResponse {\n services: string[];\n events: string[];\n prop_keys: string[];\n levels: string[];\n sources: string[];\n}\n\nexport class MeetSudoServer {\n private apiKey: string | null;\n private secretKey: string | null;\n private apiUrl: string;\n\n constructor(config: MeetSudoServerConfig) {\n if (!config.apiKey && !config.secretKey) {\n throw new Error(\"MeetSudoServer: apiKey or secretKey is required\");\n }\n this.apiKey = config.apiKey ?? null;\n this.secretKey = config.secretKey ?? null;\n this.apiUrl = config.apiUrl || \"https://api.meetsudo.com\";\n }\n\n private async requestWithKey<T>(\n method: string,\n path: string,\n key: string,\n body?: unknown\n ): Promise<T> {\n const res = await fetch(`${this.apiUrl}${path}`, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": key,\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!res.ok) {\n const error = await res.json().catch(() => ({ error: \"Request failed\" }));\n throw new Error(error.error || `Request failed: ${res.status}`);\n }\n\n return res.json();\n }\n\n private async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n if (!this.apiKey) {\n throw new Error(\"MeetSudoServer: apiKey is required for this call\");\n }\n return this.requestWithKey(method, path, this.apiKey, body);\n }\n\n private async requestSecret<T>(method: string, path: string, body?: unknown): Promise<T> {\n if (!this.secretKey) {\n throw new Error(\"MeetSudoServer: secretKey is required for logs\");\n }\n if (!this.secretKey.startsWith(\"sk_\")) {\n throw new Error(\"MeetSudoServer: secretKey must start with sk_\");\n }\n return this.requestWithKey(method, path, this.secretKey, body);\n }\n\n /**\n * Identify a user with traits.\n * Creates or updates the customer in MeetSudo.\n *\n * @param userId - Unique identifier for the user (your internal user ID)\n * @param traits - User properties like email, name, plan, etc.\n *\n * @example\n * await meetsudo.identify('user_123', {\n * email: 'jane@example.com',\n * name: 'Jane Smith',\n * plan: 'pro'\n * });\n */\n async identify(userId: string, traits?: UserTraits): Promise<{ customer_id: string }> {\n return this.request(\"POST\", \"/widget/identify\", {\n anonymous_id: `server_${userId}`,\n external_id: userId,\n properties: traits || {},\n });\n }\n\n /**\n * Track a custom event.\n *\n * @param userId - The user ID (same as used in identify)\n * @param eventName - Name of the event (e.g., 'purchase_completed')\n * @param properties - Additional event properties\n *\n * @example\n * await meetsudo.track('user_123', 'purchase_completed', {\n * order_id: 'ord_456',\n * amount: 99.00,\n * currency: 'USD'\n * });\n */\n async track(\n userId: string,\n eventName: string,\n properties?: EventProperties\n ): Promise<{ received: number }> {\n // First ensure customer exists\n await this.request(\"POST\", \"/widget/init\", {\n anonymous_id: `server_${userId}`,\n });\n\n return this.request(\"POST\", \"/widget/events\", {\n anonymous_id: `server_${userId}`,\n events: [\n {\n name: eventName,\n properties: properties || {},\n page_url: \"server\",\n timestamp: new Date().toISOString(),\n },\n ],\n });\n }\n\n /**\n * Track multiple events at once (batch).\n *\n * @param userId - The user ID\n * @param events - Array of events to track\n *\n * @example\n * await meetsudo.trackBatch('user_123', [\n * { name: 'page_viewed', properties: { page: '/pricing' } },\n * { name: 'button_clicked', properties: { button: 'cta' } }\n * ]);\n */\n async trackBatch(\n userId: string,\n events: Array<{ name: string; properties?: EventProperties }>\n ): Promise<{ received: number }> {\n // First ensure customer exists\n await this.request(\"POST\", \"/widget/init\", {\n anonymous_id: `server_${userId}`,\n });\n\n return this.request(\"POST\", \"/widget/events\", {\n anonymous_id: `server_${userId}`,\n events: events.map((e) => ({\n name: e.name,\n properties: e.properties || {},\n page_url: \"server\",\n timestamp: new Date().toISOString(),\n })),\n });\n }\n\n /**\n * Get customer information.\n *\n * @param customerId - The MeetSudo customer ID\n */\n async getCustomer(customerId: string): Promise<unknown> {\n return this.request(\"GET\", `/customers/${customerId}`);\n }\n\n /**\n * Get customer timeline (events, messages, sessions).\n *\n * @param customerId - The MeetSudo customer ID\n * @param limit - Maximum number of items to return\n */\n async getCustomerTimeline(\n customerId: string,\n limit?: number\n ): Promise<unknown> {\n const qs = limit ? `?limit=${limit}` : \"\";\n return this.request(\"GET\", `/customers/${customerId}/timeline${qs}`);\n }\n\n /**\n * Ingest one backend log entry (requires secretKey).\n */\n async log(entry: LogEntry): Promise<{ ok: boolean; inserted: number }> {\n return this.requestSecret(\"POST\", \"/logs/ingest\", { logs: [entry] });\n }\n\n /**\n * Ingest multiple backend log entries (requires secretKey).\n */\n async logBatch(entries: LogEntry[]): Promise<{ ok: boolean; inserted: number }> {\n return this.requestSecret(\"POST\", \"/logs/ingest\", { logs: entries });\n }\n\n /**\n * Query logs with Splunk-like commands:\n * - count\n * - stats count by level|source|service|event|user_id\n * - timechart span=1h\n */\n async queryLogs(params: LogQueryRequest): Promise<unknown> {\n return this.requestSecret(\"POST\", \"/logs/query/secret\", params);\n }\n\n /**\n * Convert plain English into a MeetSudo logs query (requires secretKey).\n */\n async assistLogQuery(prompt: string): Promise<LogAssistResponse> {\n return this.requestSecret(\"POST\", \"/logs/assist/secret\", { prompt });\n }\n\n /**\n * Get observed workspace log schema hints (services/events/prop keys).\n */\n async getLogSchemaHints(): Promise<LogSchemaHintsResponse> {\n return this.requestSecret(\"GET\", \"/logs/schema-hints/secret\");\n }\n}\n\n// Default export for convenience\nexport default MeetSudoServer;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\n * MeetSudo Server SDK\n * Use this for server-side event tracking, user identification, and API calls.\n */\n\nexport interface MeetSudoServerConfig {\n apiKey?: string;\n secretKey?: string;\n apiUrl?: string;\n}\n\nexport interface UserTraits {\n email?: string;\n name?: string;\n [key: string]: unknown;\n}\n\nexport interface EventProperties {\n [key: string]: unknown;\n}\n\nexport interface LogEntry {\n ts?: string;\n level?: \"debug\" | \"info\" | \"warn\" | \"error\";\n source?: \"backend\" | \"frontend\" | \"sdk\" | \"system\";\n service?: string;\n event?: string;\n message: string;\n user_id?: string;\n request_id?: string;\n trace_id?: string;\n tags?: Record<string, string>;\n props?: Record<string, unknown>;\n}\n\nexport interface LogQueryRequest {\n query?: string;\n from?: string;\n to?: string;\n limit?: number;\n}\n\nexport interface LogAssistResponse {\n query: string;\n explanation: string;\n}\n\nexport interface LogSchemaHintsResponse {\n services: string[];\n events: string[];\n prop_keys: string[];\n levels: string[];\n sources: string[];\n}\n\nexport interface ChangelogEntry {\n id: string;\n workspace_id: string;\n title: string;\n content: string;\n is_published: boolean;\n published_at: string | null;\n created_at: string;\n updated_at: string;\n}\n\nexport class MeetSudoServer {\n private apiKey: string | null;\n private secretKey: string | null;\n private apiUrl: string;\n\n constructor(config: MeetSudoServerConfig) {\n if (!config.apiKey && !config.secretKey) {\n throw new Error(\"MeetSudoServer: apiKey or secretKey is required\");\n }\n this.apiKey = config.apiKey ?? null;\n this.secretKey = config.secretKey ?? null;\n this.apiUrl = config.apiUrl || \"https://api.meetsudo.com\";\n }\n\n private async requestWithKey<T>(\n method: string,\n path: string,\n key: string,\n body?: unknown\n ): Promise<T> {\n const res = await fetch(`${this.apiUrl}${path}`, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": key,\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!res.ok) {\n const error = await res.json().catch(() => ({ error: \"Request failed\" }));\n throw new Error(error.error || `Request failed: ${res.status}`);\n }\n\n return res.json();\n }\n\n private async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n if (!this.apiKey) {\n throw new Error(\"MeetSudoServer: apiKey is required for this call\");\n }\n return this.requestWithKey(method, path, this.apiKey, body);\n }\n\n private async requestSecret<T>(method: string, path: string, body?: unknown): Promise<T> {\n if (!this.secretKey) {\n throw new Error(\"MeetSudoServer: secretKey is required for logs\");\n }\n if (!this.secretKey.startsWith(\"sk_\")) {\n throw new Error(\"MeetSudoServer: secretKey must start with sk_\");\n }\n return this.requestWithKey(method, path, this.secretKey, body);\n }\n\n /**\n * Identify a user with traits.\n * Creates or updates the customer in MeetSudo.\n *\n * @param userId - Unique identifier for the user (your internal user ID)\n * @param traits - User properties like email, name, plan, etc.\n *\n * @example\n * await meetsudo.identify('user_123', {\n * email: 'jane@example.com',\n * name: 'Jane Smith',\n * plan: 'pro'\n * });\n */\n async identify(userId: string, traits?: UserTraits): Promise<{ customer_id: string }> {\n return this.request(\"POST\", \"/widget/identify\", {\n anonymous_id: `server_${userId}`,\n external_id: userId,\n properties: traits || {},\n });\n }\n\n /**\n * Track a custom event.\n *\n * @param userId - The user ID (same as used in identify)\n * @param eventName - Name of the event (e.g., 'purchase_completed')\n * @param properties - Additional event properties\n *\n * @example\n * await meetsudo.track('user_123', 'purchase_completed', {\n * order_id: 'ord_456',\n * amount: 99.00,\n * currency: 'USD'\n * });\n */\n async track(\n userId: string,\n eventName: string,\n properties?: EventProperties\n ): Promise<{ received: number }> {\n // First ensure customer exists\n await this.request(\"POST\", \"/widget/init\", {\n anonymous_id: `server_${userId}`,\n });\n\n return this.request(\"POST\", \"/widget/events\", {\n anonymous_id: `server_${userId}`,\n events: [\n {\n name: eventName,\n properties: properties || {},\n page_url: \"server\",\n timestamp: new Date().toISOString(),\n },\n ],\n });\n }\n\n /**\n * Track multiple events at once (batch).\n *\n * @param userId - The user ID\n * @param events - Array of events to track\n *\n * @example\n * await meetsudo.trackBatch('user_123', [\n * { name: 'page_viewed', properties: { page: '/pricing' } },\n * { name: 'button_clicked', properties: { button: 'cta' } }\n * ]);\n */\n async trackBatch(\n userId: string,\n events: Array<{ name: string; properties?: EventProperties }>\n ): Promise<{ received: number }> {\n // First ensure customer exists\n await this.request(\"POST\", \"/widget/init\", {\n anonymous_id: `server_${userId}`,\n });\n\n return this.request(\"POST\", \"/widget/events\", {\n anonymous_id: `server_${userId}`,\n events: events.map((e) => ({\n name: e.name,\n properties: e.properties || {},\n page_url: \"server\",\n timestamp: new Date().toISOString(),\n })),\n });\n }\n\n /**\n * Get customer information.\n *\n * @param customerId - The MeetSudo customer ID\n */\n async getCustomer(customerId: string): Promise<unknown> {\n return this.request(\"GET\", `/customers/${customerId}`);\n }\n\n /**\n * Get customer timeline (events, messages, sessions).\n *\n * @param customerId - The MeetSudo customer ID\n * @param limit - Maximum number of items to return\n */\n async getCustomerTimeline(\n customerId: string,\n limit?: number\n ): Promise<unknown> {\n const qs = limit ? `?limit=${limit}` : \"\";\n return this.request(\"GET\", `/customers/${customerId}/timeline${qs}`);\n }\n\n /**\n * Ingest one backend log entry (requires secretKey).\n */\n async log(entry: LogEntry): Promise<{ ok: boolean; inserted: number }> {\n return this.requestSecret(\"POST\", \"/logs/ingest\", { logs: [entry] });\n }\n\n /**\n * Ingest multiple backend log entries (requires secretKey).\n */\n async logBatch(entries: LogEntry[]): Promise<{ ok: boolean; inserted: number }> {\n return this.requestSecret(\"POST\", \"/logs/ingest\", { logs: entries });\n }\n\n /**\n * Query logs with Splunk-like commands:\n * - count\n * - stats count by level|source|service|event|user_id\n * - timechart span=1h\n */\n async queryLogs(params: LogQueryRequest): Promise<unknown> {\n return this.requestSecret(\"POST\", \"/logs/query/secret\", params);\n }\n\n /**\n * Convert plain English into a MeetSudo logs query (requires secretKey).\n */\n async assistLogQuery(prompt: string): Promise<LogAssistResponse> {\n return this.requestSecret(\"POST\", \"/logs/assist/secret\", { prompt });\n }\n\n /**\n * Get observed workspace log schema hints (services/events/prop keys).\n */\n async getLogSchemaHints(): Promise<LogSchemaHintsResponse> {\n return this.requestSecret(\"GET\", \"/logs/schema-hints/secret\");\n }\n\n /**\n * Publish a What's New entry (changelog) immediately.\n * Requires secretKey.\n */\n async publishWhatsNew(\n title: string,\n content: string\n ): Promise<{ entry: ChangelogEntry }> {\n if (!title.trim() || !content.trim()) {\n throw new Error(\"MeetSudoServer: title and content are required\");\n }\n return this.requestSecret(\"POST\", \"/changelog/secret\", {\n title: title.trim(),\n content: content.trim(),\n is_published: true,\n });\n }\n\n /**\n * Create a What's New draft (not published).\n * Requires secretKey.\n */\n async createWhatsNewDraft(\n title: string,\n content: string\n ): Promise<{ entry: ChangelogEntry }> {\n if (!title.trim() || !content.trim()) {\n throw new Error(\"MeetSudoServer: title and content are required\");\n }\n return this.requestSecret(\"POST\", \"/changelog/secret\", {\n title: title.trim(),\n content: content.trim(),\n is_published: false,\n });\n }\n\n /**\n * Publish or unpublish an existing What's New entry.\n * Requires secretKey.\n */\n async setWhatsNewPublished(\n entryId: string,\n isPublished: boolean = true\n ): Promise<{ entry: ChangelogEntry }> {\n if (!entryId.trim()) {\n throw new Error(\"MeetSudoServer: entryId is required\");\n }\n return this.requestSecret(\"PATCH\", `/changelog/secret/${entryId}/publish`, {\n is_published: isPublished,\n });\n }\n}\n\n// Default export for convenience\nexport default MeetSudoServer;\n"],"mappings":"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","names":[]}