@feedvalue/core 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -575,8 +575,11 @@ declare class ApiClient {
575
575
  /**
576
576
  * Fetch widget configuration
577
577
  * Uses caching and request deduplication
578
+ *
579
+ * @param widgetId - Widget ID to fetch config for
580
+ * @param forceRefresh - Skip cache and fetch fresh config (used for token refresh)
578
581
  */
579
- fetchConfig(widgetId: string): Promise<ConfigResponse>;
582
+ fetchConfig(widgetId: string, forceRefresh?: boolean): Promise<ConfigResponse>;
580
583
  /**
581
584
  * Actually fetch config from API
582
585
  */
@@ -601,20 +604,23 @@ declare class ApiClient {
601
604
 
602
605
  /**
603
606
  * Simple fingerprint generation for anti-abuse protection.
604
- * Uses a session-based UUID stored in sessionStorage.
607
+ * Uses a session-based hex string stored in sessionStorage.
605
608
  *
606
609
  * This replaces the previous complex fingerprinting system (canvas, WebGL, audio)
607
610
  * which was overkill for an MVP feedback widget and raised privacy concerns.
611
+ *
612
+ * The fingerprint is a 32-character hex string (16 random bytes), matching
613
+ * the format expected by the core-api's TokenPayload validator.
608
614
  */
609
615
  /**
610
616
  * Generate or retrieve a session fingerprint.
611
617
  *
612
618
  * The fingerprint is:
613
- * - Generated once per browser session using crypto.randomUUID()
619
+ * - Generated once per browser session as a 32-character hex string
614
620
  * - Stored in sessionStorage for consistency within a session
615
621
  * - Automatically cleared when the browser tab/window is closed
616
622
  *
617
- * @returns A unique fingerprint string for the current session
623
+ * @returns A unique fingerprint hex string for the current session
618
624
  */
619
625
  declare function generateFingerprint(): string;
620
626
  /**
package/dist/index.js CHANGED
@@ -138,14 +138,21 @@ var ApiClient = class {
138
138
  /**
139
139
  * Fetch widget configuration
140
140
  * Uses caching and request deduplication
141
+ *
142
+ * @param widgetId - Widget ID to fetch config for
143
+ * @param forceRefresh - Skip cache and fetch fresh config (used for token refresh)
141
144
  */
142
- async fetchConfig(widgetId) {
145
+ async fetchConfig(widgetId, forceRefresh = false) {
143
146
  this.validateWidgetId(widgetId);
144
147
  const cacheKey = `config:${widgetId}`;
145
- const cached = this.configCache.get(cacheKey);
146
- if (cached && Date.now() < cached.expiresAt) {
147
- this.log("Config cache hit", { widgetId });
148
- return cached.data;
148
+ if (!forceRefresh) {
149
+ const cached = this.configCache.get(cacheKey);
150
+ if (cached && Date.now() < cached.expiresAt) {
151
+ this.log("Config cache hit", { widgetId });
152
+ return cached.data;
153
+ }
154
+ } else {
155
+ this.log("Bypassing cache for token refresh", { widgetId });
149
156
  }
150
157
  const pendingKey = `fetchConfig:${widgetId}`;
151
158
  const pending = this.pendingRequests.get(pendingKey);
@@ -171,7 +178,12 @@ var ApiClient = class {
171
178
  if (this.fingerprint) {
172
179
  headers["X-Client-Fingerprint"] = this.fingerprint;
173
180
  }
174
- this.log("Fetching config", { widgetId, url });
181
+ this.log("Fetching config", {
182
+ widgetId,
183
+ url,
184
+ hasFingerprint: !!this.fingerprint,
185
+ fingerprintPreview: this.fingerprint ? `${this.fingerprint.substring(0, 8)}...` : null
186
+ });
175
187
  const response = await fetch(url, {
176
188
  method: "GET",
177
189
  headers
@@ -187,6 +199,12 @@ var ApiClient = class {
187
199
  this.log("Submission token stored", {
188
200
  expiresAt: this.tokenExpiresAt ? new Date(this.tokenExpiresAt * 1e3).toISOString() : "unknown"
189
201
  });
202
+ } else {
203
+ this.log("No submission token in response", {
204
+ hasWidgetId: !!data.widget_id,
205
+ hasConfig: !!data.config,
206
+ responseKeys: Object.keys(data)
207
+ });
190
208
  }
191
209
  const cacheKey = `config:${widgetId}`;
192
210
  this.configCache.set(cacheKey, {
@@ -204,7 +222,7 @@ var ApiClient = class {
204
222
  const url = `${this.baseUrl}/api/v1/widgets/${widgetId}/feedback`;
205
223
  if (!this.hasValidToken()) {
206
224
  this.log("Token expired, refreshing...");
207
- await this.fetchConfig(widgetId);
225
+ await this.fetchConfig(widgetId, true);
208
226
  }
209
227
  if (!this.submissionToken) {
210
228
  throw new Error("No submission token available");
@@ -217,17 +235,20 @@ var ApiClient = class {
217
235
  headers["X-Client-Fingerprint"] = this.fingerprint;
218
236
  }
219
237
  this.log("Submitting feedback", { widgetId });
238
+ const mergedMetadata = {
239
+ ...feedback.metadata,
240
+ ...userData && Object.keys(userData).length > 0 && {
241
+ user: userData
242
+ }
243
+ };
220
244
  const response = await fetch(url, {
221
245
  method: "POST",
222
246
  headers,
223
247
  body: JSON.stringify({
224
248
  message: feedback.message,
225
- metadata: feedback.metadata,
249
+ metadata: Object.keys(mergedMetadata).length > 0 ? mergedMetadata : void 0,
226
250
  ...feedback.customFieldValues && {
227
251
  customFieldValues: feedback.customFieldValues
228
- },
229
- ...userData && Object.keys(userData).length > 0 && {
230
- user: userData
231
252
  }
232
253
  })
233
254
  });
@@ -245,7 +266,7 @@ var ApiClient = class {
245
266
  if (errorMessage.includes("token") || errorMessage.includes("expired")) {
246
267
  this.log("Token rejected, refreshing...");
247
268
  this.submissionToken = null;
248
- await this.fetchConfig(widgetId);
269
+ await this.fetchConfig(widgetId, true);
249
270
  if (this.submissionToken) {
250
271
  headers["X-Submission-Token"] = this.submissionToken;
251
272
  const retryResponse = await fetch(url, {
@@ -312,33 +333,33 @@ var ApiClient = class {
312
333
 
313
334
  // src/fingerprint.ts
314
335
  var FINGERPRINT_STORAGE_KEY = "fv_fingerprint";
315
- function generateUUID() {
316
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
317
- return crypto.randomUUID();
318
- }
319
- if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
320
- const bytes = new Uint8Array(16);
321
- crypto.getRandomValues(bytes);
322
- bytes[6] = bytes[6] & 15 | 64;
323
- bytes[8] = bytes[8] & 63 | 128;
324
- const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
325
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
326
- }
327
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
328
- const r = Math.random() * 16 | 0;
329
- const v = c === "x" ? r : r & 3 | 8;
330
- return v.toString(16);
331
- });
336
+ function generateHexFingerprint() {
337
+ if (typeof crypto === "undefined" || typeof crypto.getRandomValues !== "function") {
338
+ throw new Error(
339
+ "crypto.getRandomValues is required but not available. Ensure you are running in a modern browser or Node.js 15+."
340
+ );
341
+ }
342
+ const bytes = new Uint8Array(16);
343
+ crypto.getRandomValues(bytes);
344
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
332
345
  }
333
346
  function generateFingerprint() {
334
347
  if (typeof window === "undefined" || typeof sessionStorage === "undefined") {
335
- return generateUUID();
348
+ return generateHexFingerprint();
336
349
  }
337
350
  const stored = sessionStorage.getItem(FINGERPRINT_STORAGE_KEY);
338
351
  if (stored) {
352
+ if (stored.includes("-")) {
353
+ const hexFingerprint = stored.replace(/-/g, "");
354
+ try {
355
+ sessionStorage.setItem(FINGERPRINT_STORAGE_KEY, hexFingerprint);
356
+ } catch {
357
+ }
358
+ return hexFingerprint;
359
+ }
339
360
  return stored;
340
361
  }
341
- const fingerprint = generateUUID();
362
+ const fingerprint = generateHexFingerprint();
342
363
  try {
343
364
  sessionStorage.setItem(FINGERPRINT_STORAGE_KEY, fingerprint);
344
365
  } catch {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/event-emitter.ts","../src/api-client.ts","../src/fingerprint.ts","../src/feedvalue.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @feedvalue/core - Type-Safe Event Emitter\n *\n * A minimal, type-safe event emitter for FeedValue events.\n * Provides compile-time type checking for event names and handlers.\n */\n\nimport type { FeedValueEvents, EventHandler } from './types';\n\n/**\n * Type-safe event emitter for FeedValue events\n *\n * @example\n * ```ts\n * const emitter = new TypedEventEmitter();\n *\n * emitter.on('ready', () => console.log('Ready!'));\n * emitter.on('submit', (feedback) => console.log('Submitted:', feedback));\n *\n * emitter.emit('ready');\n * emitter.emit('submit', { message: 'Great app!' });\n * ```\n */\nexport class TypedEventEmitter {\n // Using a Map with proper typing - the inner Function type is acceptable here\n // because we handle type safety at the public API level (on/off/emit methods)\n private listeners = new Map<keyof FeedValueEvents, Set<(...args: unknown[]) => void>>();\n\n /**\n * Subscribe to an event\n *\n * @param event - Event name\n * @param handler - Event handler function\n */\n on<K extends keyof FeedValueEvents>(event: K, handler: EventHandler<K>): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler as (...args: unknown[]) => void);\n }\n\n /**\n * Subscribe to an event for a single emission.\n * The handler will be automatically removed after the first call.\n *\n * @param event - Event name\n * @param handler - Event handler function\n */\n once<K extends keyof FeedValueEvents>(event: K, handler: EventHandler<K>): void {\n const wrappedHandler = ((...args: unknown[]) => {\n this.off(event, wrappedHandler as EventHandler<K>);\n (handler as (...args: unknown[]) => void)(...args);\n }) as EventHandler<K>;\n\n this.on(event, wrappedHandler);\n }\n\n /**\n * Unsubscribe from an event\n *\n * @param event - Event name\n * @param handler - Optional handler to remove (removes all if not provided)\n */\n off<K extends keyof FeedValueEvents>(event: K, handler?: EventHandler<K>): void {\n if (!handler) {\n // Remove all handlers for this event\n this.listeners.delete(event);\n return;\n }\n\n const handlers = this.listeners.get(event);\n if (handlers) {\n handlers.delete(handler as (...args: unknown[]) => void);\n if (handlers.size === 0) {\n this.listeners.delete(event);\n }\n }\n }\n\n /**\n * Emit an event to all subscribers\n *\n * @param event - Event name\n * @param args - Arguments to pass to handlers\n */\n emit<K extends keyof FeedValueEvents>(\n event: K,\n ...args: Parameters<EventHandler<K>>\n ): void {\n const handlers = this.listeners.get(event);\n if (handlers) {\n for (const handler of handlers) {\n try {\n handler(...args);\n } catch (error) {\n // Prevent one handler's error from breaking others\n console.error(`[FeedValue] Error in ${event} handler:`, error);\n }\n }\n }\n }\n\n /**\n * Remove all event listeners\n */\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","/**\n * @feedvalue/core - API Client\n *\n * Handles all communication with the FeedValue API.\n * Includes request deduplication, caching, and error handling.\n */\n\nimport type { ConfigResponse, FeedbackResponse, FeedbackData, SubmissionUserData } from './types';\n\n/**\n * Default API base URL\n */\nexport const DEFAULT_API_BASE_URL = 'https://api.feedvalue.com';\n\n/** Buffer time before token is considered expired (seconds) */\nconst TOKEN_EXPIRY_BUFFER_SECONDS = 30;\n\n/** How long to cache widget config (milliseconds) */\nconst CONFIG_CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes\n\n/**\n * Cache entry with TTL\n */\ninterface CacheEntry<T> {\n data: T;\n expiresAt: number;\n}\n\n/**\n * API client for FeedValue\n */\nexport class ApiClient {\n private baseUrl: string;\n private debug: boolean;\n\n // Request deduplication\n private pendingRequests = new Map<string, Promise<unknown>>();\n\n // Config cache\n private configCache = new Map<string, CacheEntry<ConfigResponse>>();\n\n // Anti-abuse tokens\n private submissionToken: string | null = null;\n private tokenExpiresAt: number | null = null;\n private fingerprint: string | null = null;\n\n constructor(baseUrl: string = DEFAULT_API_BASE_URL, debug = false) {\n this.baseUrl = baseUrl.replace(/\\/$/, ''); // Remove trailing slash\n this.debug = debug;\n }\n\n /**\n * Validate widget ID to prevent path injection attacks\n * @throws Error if widget ID is invalid\n */\n private validateWidgetId(widgetId: string): void {\n if (!widgetId || typeof widgetId !== 'string') {\n throw new Error('Widget ID is required');\n }\n if (!/^[a-zA-Z0-9_-]+$/.test(widgetId)) {\n throw new Error('Invalid widget ID format: only alphanumeric characters, underscores, and hyphens are allowed');\n }\n if (widgetId.length > 64) {\n throw new Error('Widget ID exceeds maximum length of 64 characters');\n }\n }\n\n /**\n * Set client fingerprint for anti-abuse protection\n */\n setFingerprint(fingerprint: string): void {\n this.fingerprint = fingerprint;\n }\n\n /**\n * Get client fingerprint\n */\n getFingerprint(): string | null {\n return this.fingerprint;\n }\n\n /**\n * Check if submission token is valid\n */\n hasValidToken(): boolean {\n if (!this.submissionToken || !this.tokenExpiresAt) {\n return false;\n }\n // Add buffer before expiry\n return Date.now() / 1000 < this.tokenExpiresAt - TOKEN_EXPIRY_BUFFER_SECONDS;\n }\n\n /**\n * Fetch widget configuration\n * Uses caching and request deduplication\n */\n async fetchConfig(widgetId: string): Promise<ConfigResponse> {\n this.validateWidgetId(widgetId);\n const cacheKey = `config:${widgetId}`;\n\n // Check cache first\n const cached = this.configCache.get(cacheKey);\n if (cached && Date.now() < cached.expiresAt) {\n this.log('Config cache hit', { widgetId });\n return cached.data;\n }\n\n // Deduplicate concurrent requests\n const pendingKey = `fetchConfig:${widgetId}`;\n const pending = this.pendingRequests.get(pendingKey);\n if (pending) {\n this.log('Deduplicating config request', { widgetId });\n return pending as Promise<ConfigResponse>;\n }\n\n const request = this.doFetchConfig(widgetId);\n this.pendingRequests.set(pendingKey, request);\n\n try {\n const result = await request;\n return result;\n } finally {\n this.pendingRequests.delete(pendingKey);\n }\n }\n\n /**\n * Actually fetch config from API\n */\n private async doFetchConfig(widgetId: string): Promise<ConfigResponse> {\n const url = `${this.baseUrl}/api/v1/widgets/${widgetId}/config`;\n\n const headers: Record<string, string> = {};\n if (this.fingerprint) {\n headers['X-Client-Fingerprint'] = this.fingerprint;\n }\n\n this.log('Fetching config', { widgetId, url });\n\n const response = await fetch(url, {\n method: 'GET',\n headers,\n });\n\n if (!response.ok) {\n const error = await this.parseError(response);\n throw new Error(error);\n }\n\n const data = await response.json() as ConfigResponse;\n\n // Store submission token\n if (data.submission_token) {\n this.submissionToken = data.submission_token;\n this.tokenExpiresAt = data.token_expires_at ?? null;\n this.log('Submission token stored', {\n expiresAt: this.tokenExpiresAt ? new Date(this.tokenExpiresAt * 1000).toISOString() : 'unknown',\n });\n }\n\n // Cache the response\n const cacheKey = `config:${widgetId}`;\n this.configCache.set(cacheKey, {\n data,\n expiresAt: Date.now() + CONFIG_CACHE_TTL_MS,\n });\n\n this.log('Config fetched', { widgetId });\n return data;\n }\n\n /**\n * Submit feedback with optional user data\n */\n async submitFeedback(\n widgetId: string,\n feedback: FeedbackData,\n userData?: SubmissionUserData\n ): Promise<FeedbackResponse> {\n this.validateWidgetId(widgetId);\n const url = `${this.baseUrl}/api/v1/widgets/${widgetId}/feedback`;\n\n // Refresh token if needed\n if (!this.hasValidToken()) {\n this.log('Token expired, refreshing...');\n await this.fetchConfig(widgetId);\n }\n\n if (!this.submissionToken) {\n throw new Error('No submission token available');\n }\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Submission-Token': this.submissionToken,\n };\n\n if (this.fingerprint) {\n headers['X-Client-Fingerprint'] = this.fingerprint;\n }\n\n this.log('Submitting feedback', { widgetId });\n\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n message: feedback.message,\n metadata: feedback.metadata,\n ...(feedback.customFieldValues && {\n customFieldValues: feedback.customFieldValues,\n }),\n ...(userData && Object.keys(userData).length > 0 && {\n user: userData,\n }),\n }),\n });\n\n // Handle rate limiting\n if (response.status === 429) {\n const resetAt = response.headers.get('X-RateLimit-Reset');\n const retryAfter = resetAt\n ? Math.ceil(parseInt(resetAt, 10) - Date.now() / 1000)\n : 60;\n throw new Error(`Rate limited. Try again in ${retryAfter} seconds.`);\n }\n\n // Handle forbidden (token issues)\n if (response.status === 403) {\n const errorData = await response.json().catch(() => ({ detail: 'Access denied' }));\n\n // Check for subscription limit\n if (errorData.detail?.code && errorData.detail?.message) {\n throw new Error(errorData.detail.message);\n }\n\n // Try token refresh and retry once\n const errorMessage = typeof errorData.detail === 'string' ? errorData.detail : '';\n if (errorMessage.includes('token') || errorMessage.includes('expired')) {\n this.log('Token rejected, refreshing...');\n this.submissionToken = null;\n await this.fetchConfig(widgetId);\n\n if (this.submissionToken) {\n // Retry with new token\n headers['X-Submission-Token'] = this.submissionToken;\n const retryResponse = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n message: feedback.message,\n metadata: feedback.metadata,\n ...(feedback.customFieldValues && {\n customFieldValues: feedback.customFieldValues,\n }),\n ...(userData && Object.keys(userData).length > 0 && {\n user: userData,\n }),\n }),\n });\n\n if (retryResponse.ok) {\n return retryResponse.json();\n }\n }\n }\n\n throw new Error(errorMessage || 'Access denied');\n }\n\n if (!response.ok) {\n const error = await this.parseError(response);\n throw new Error(error);\n }\n\n const data = await response.json() as FeedbackResponse;\n\n // Check for soft blocks\n if (data.blocked) {\n throw new Error(data.message || 'Unable to submit feedback');\n }\n\n this.log('Feedback submitted', { feedbackId: data.feedback_id });\n return data;\n }\n\n /**\n * Parse error from response\n */\n private async parseError(response: Response): Promise<string> {\n try {\n const data = await response.json();\n return data.detail || data.message || data.error || `HTTP ${response.status}`;\n } catch {\n return `HTTP ${response.status}: ${response.statusText}`;\n }\n }\n\n /**\n * Clear all caches\n */\n clearCache(): void {\n this.configCache.clear();\n this.submissionToken = null;\n this.tokenExpiresAt = null;\n this.log('Cache cleared');\n }\n\n /**\n * Debug logging\n */\n private log(message: string, data?: Record<string, unknown>): void {\n if (this.debug) {\n console.log(`[FeedValue API] ${message}`, data ?? '');\n }\n }\n}\n","/**\n * Simple fingerprint generation for anti-abuse protection.\n * Uses a session-based UUID stored in sessionStorage.\n *\n * This replaces the previous complex fingerprinting system (canvas, WebGL, audio)\n * which was overkill for an MVP feedback widget and raised privacy concerns.\n */\n\n/**\n * Storage key for the fingerprint\n */\nconst FINGERPRINT_STORAGE_KEY = 'fv_fingerprint';\n\n/**\n * Generate a UUID v4.\n * Uses crypto.randomUUID() if available, otherwise falls back to a manual implementation.\n */\nfunction generateUUID(): string {\n // Use native crypto.randomUUID if available\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n\n // Fallback: manual UUID v4 generation using crypto.getRandomValues\n if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n\n // Set version (4) and variant (RFC 4122)\n // Using non-null assertions since we know the array has 16 elements\n bytes[6] = (bytes[6]! & 0x0f) | 0x40;\n bytes[8] = (bytes[8]! & 0x3f) | 0x80;\n\n const hex = Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n }\n\n // Last resort fallback using Math.random (less secure but functional)\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * Generate or retrieve a session fingerprint.\n *\n * The fingerprint is:\n * - Generated once per browser session using crypto.randomUUID()\n * - Stored in sessionStorage for consistency within a session\n * - Automatically cleared when the browser tab/window is closed\n *\n * @returns A unique fingerprint string for the current session\n */\nexport function generateFingerprint(): string {\n // Check for SSR environment\n if (typeof window === 'undefined' || typeof sessionStorage === 'undefined') {\n return generateUUID();\n }\n\n // Try to get existing fingerprint from session\n const stored = sessionStorage.getItem(FINGERPRINT_STORAGE_KEY);\n if (stored) {\n return stored;\n }\n\n // Generate new fingerprint\n const fingerprint = generateUUID();\n\n try {\n sessionStorage.setItem(FINGERPRINT_STORAGE_KEY, fingerprint);\n } catch {\n // sessionStorage may be unavailable (private browsing, quota exceeded)\n // Fall through and return the generated fingerprint anyway\n }\n\n return fingerprint;\n}\n\n/**\n * Clear the stored fingerprint.\n * Useful for testing or when user requests data reset.\n */\nexport function clearFingerprint(): void {\n if (typeof sessionStorage !== 'undefined') {\n try {\n sessionStorage.removeItem(FINGERPRINT_STORAGE_KEY);\n } catch {\n // Ignore errors\n }\n }\n}\n","/**\n * @feedvalue/core - FeedValue Class\n *\n * Main FeedValue SDK class. Provides the public API for interacting\n * with the feedback widget.\n *\n * For vanilla JavaScript usage, this class also handles DOM rendering.\n * Framework packages (React, Vue) use this class as a headless core.\n */\n\nimport type {\n FeedValueOptions,\n FeedValueConfig,\n FeedValueState,\n FeedValueInstance,\n FeedValueEvents,\n EventHandler,\n UserData,\n UserTraits,\n FeedbackData,\n WidgetConfig,\n EmojiSentiment,\n SubmissionUserData,\n} from './types';\nimport { TypedEventEmitter } from './event-emitter';\nimport { ApiClient, DEFAULT_API_BASE_URL } from './api-client';\nimport { generateFingerprint } from './fingerprint';\n\n/** Delay before auto-closing the success message (milliseconds) */\nconst SUCCESS_AUTO_CLOSE_DELAY_MS = 3000;\n\n/**\n * Valid sentiment values for feedback validation\n */\nconst VALID_SENTIMENTS: readonly EmojiSentiment[] = ['angry', 'disappointed', 'satisfied', 'excited'] as const;\n\n/**\n * Maximum allowed message length (10,000 characters)\n */\nconst MAX_MESSAGE_LENGTH = 10000;\n\n/**\n * Maximum allowed length for metadata string values (1,000 characters)\n */\nconst MAX_METADATA_VALUE_LENGTH = 1000;\n\n/**\n * Default configuration\n */\nconst DEFAULT_CONFIG: FeedValueConfig = {\n theme: 'auto',\n autoShow: true,\n debug: false,\n locale: 'en',\n};\n\n/**\n * Instance registry for singleton per widgetId\n */\nconst instances = new Map<string, FeedValue>();\n\n/**\n * FeedValue SDK\n *\n * @example\n * ```ts\n * // Initialize\n * const feedvalue = FeedValue.init({ widgetId: 'abc123' });\n *\n * // Control\n * feedvalue.open();\n * feedvalue.close();\n *\n * // User data\n * feedvalue.setData({ email: 'user@example.com' });\n * feedvalue.identify('user-123', { plan: 'pro' });\n *\n * // Events\n * feedvalue.on('submit', (feedback) => {\n * console.log('Feedback submitted:', feedback);\n * });\n * ```\n */\nexport class FeedValue implements FeedValueInstance {\n private readonly widgetId: string;\n private readonly apiClient: ApiClient;\n private readonly emitter: TypedEventEmitter;\n private readonly headless: boolean;\n private config: FeedValueConfig;\n private widgetConfig: WidgetConfig | null = null;\n\n // State\n private state: FeedValueState = {\n isReady: false,\n isOpen: false,\n isVisible: true,\n error: null,\n isSubmitting: false,\n };\n\n // State subscribers (for React useSyncExternalStore)\n private stateSubscribers = new Set<() => void>();\n private stateSnapshot: FeedValueState;\n\n // User data (stored for future API submissions)\n private _userData: UserData = {};\n private _userId: string | null = null;\n private _userTraits: UserTraits = {};\n\n // DOM elements (for vanilla usage)\n private triggerButton: HTMLElement | null = null;\n private modal: HTMLElement | null = null;\n private overlay: HTMLElement | null = null;\n private stylesInjected = false;\n\n // Auto-close timeout reference (for cleanup on destroy)\n private autoCloseTimeout: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Create a new FeedValue instance\n * Use FeedValue.init() for public API\n */\n private constructor(options: FeedValueOptions) {\n this.widgetId = options.widgetId;\n this.headless = options.headless ?? false;\n this.config = { ...DEFAULT_CONFIG, ...options.config };\n\n this.apiClient = new ApiClient(\n options.apiBaseUrl ?? DEFAULT_API_BASE_URL,\n this.config.debug\n );\n\n this.emitter = new TypedEventEmitter();\n this.stateSnapshot = { ...this.state };\n\n this.log('Instance created', { widgetId: this.widgetId, headless: this.headless });\n }\n\n /**\n * Initialize FeedValue\n * Returns existing instance if already initialized for this widgetId\n */\n static init(options: FeedValueOptions): FeedValue {\n // Return existing instance if available\n const existing = instances.get(options.widgetId);\n if (existing) {\n return existing;\n }\n\n // Create new instance\n const instance = new FeedValue(options);\n instances.set(options.widgetId, instance);\n\n // Auto-initialize\n instance.init().catch((error) => {\n console.error('[FeedValue] Initialization failed:', error);\n });\n\n return instance;\n }\n\n /**\n * Get existing instance by widgetId\n */\n static getInstance(widgetId: string): FeedValue | undefined {\n return instances.get(widgetId);\n }\n\n // ===========================================================================\n // Lifecycle\n // ===========================================================================\n\n /**\n * Initialize the widget\n */\n async init(): Promise<void> {\n if (this.state.isReady) {\n this.log('Already initialized');\n return;\n }\n\n try {\n this.log('Initializing...');\n\n // Generate fingerprint\n const fingerprint = generateFingerprint();\n this.apiClient.setFingerprint(fingerprint);\n\n // Fetch config\n const configResponse = await this.apiClient.fetchConfig(this.widgetId);\n\n // Build widget config\n this.widgetConfig = {\n widgetId: configResponse.widget_id,\n widgetKey: configResponse.widget_key,\n appId: '',\n config: {\n position: configResponse.config.position ?? 'bottom-right',\n triggerText: configResponse.config.triggerText ?? 'Feedback',\n triggerIcon: configResponse.config.triggerIcon ?? 'none',\n formTitle: configResponse.config.formTitle ?? 'Share your feedback',\n submitButtonText: configResponse.config.submitButtonText ?? 'Submit',\n thankYouMessage: configResponse.config.thankYouMessage ?? 'Thank you for your feedback!',\n showBranding: configResponse.config.showBranding ?? true,\n customFields: configResponse.config.customFields,\n },\n styling: {\n primaryColor: configResponse.styling.primaryColor ?? '#3b82f6',\n backgroundColor: configResponse.styling.backgroundColor ?? '#ffffff',\n textColor: configResponse.styling.textColor ?? '#1f2937',\n buttonTextColor: configResponse.styling.buttonTextColor ?? '#ffffff',\n borderRadius: configResponse.styling.borderRadius ?? '8px',\n customCSS: configResponse.styling.customCSS,\n },\n };\n\n // Render DOM (for vanilla usage, skip in headless mode)\n if (!this.headless && typeof window !== 'undefined' && typeof document !== 'undefined') {\n this.renderWidget();\n }\n\n // Update state\n this.updateState({ isReady: true, error: null });\n this.emitter.emit('ready');\n\n this.log('Initialized successfully');\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.updateState({ error: err });\n this.emitter.emit('error', err);\n throw err;\n }\n }\n\n /**\n * Destroy the widget\n */\n destroy(): void {\n this.log('Destroying...');\n\n // Clear auto-close timeout to prevent memory leak\n if (this.autoCloseTimeout) {\n clearTimeout(this.autoCloseTimeout);\n this.autoCloseTimeout = null;\n }\n\n // Remove DOM elements\n this.triggerButton?.remove();\n this.modal?.remove();\n this.overlay?.remove();\n document.getElementById('fv-widget-styles')?.remove();\n document.getElementById('fv-widget-custom-styles')?.remove();\n\n // Clear references\n this.triggerButton = null;\n this.modal = null;\n this.overlay = null;\n this.widgetConfig = null;\n\n // Clear state\n this.stateSubscribers.clear();\n this.emitter.removeAllListeners();\n this.apiClient.clearCache();\n\n // Remove from registry\n instances.delete(this.widgetId);\n\n // Reset state\n this.state = {\n isReady: false,\n isOpen: false,\n isVisible: false,\n error: null,\n isSubmitting: false,\n };\n\n this.log('Destroyed');\n }\n\n // ===========================================================================\n // Widget Control\n // ===========================================================================\n\n open(): void {\n if (!this.state.isReady) {\n this.log('Cannot open: not ready');\n return;\n }\n\n this.updateState({ isOpen: true });\n\n // Only manipulate DOM in non-headless mode\n if (!this.headless) {\n this.overlay?.classList.add('fv-widget-open');\n this.modal?.classList.add('fv-widget-open');\n }\n\n this.emitter.emit('open');\n this.log('Opened');\n }\n\n close(): void {\n this.updateState({ isOpen: false });\n\n // Only manipulate DOM in non-headless mode\n if (!this.headless) {\n this.overlay?.classList.remove('fv-widget-open');\n this.modal?.classList.remove('fv-widget-open');\n }\n\n this.emitter.emit('close');\n this.log('Closed');\n }\n\n toggle(): void {\n if (this.state.isOpen) {\n this.close();\n } else {\n this.open();\n }\n }\n\n show(): void {\n this.updateState({ isVisible: true });\n\n // Only manipulate DOM in non-headless mode\n if (!this.headless && this.triggerButton) {\n this.triggerButton.style.display = '';\n }\n\n this.log('Shown');\n }\n\n hide(): void {\n this.updateState({ isVisible: false });\n\n // Only manipulate DOM in non-headless mode\n if (!this.headless && this.triggerButton) {\n this.triggerButton.style.display = 'none';\n }\n\n this.log('Hidden');\n }\n\n // ===========================================================================\n // State Queries\n // ===========================================================================\n\n isOpen(): boolean {\n return this.state.isOpen;\n }\n\n isVisible(): boolean {\n return this.state.isVisible;\n }\n\n isReady(): boolean {\n return this.state.isReady;\n }\n\n isHeadless(): boolean {\n return this.headless;\n }\n\n // ===========================================================================\n // User Data\n // ===========================================================================\n\n setData(data: Partial<UserData>): void {\n this._userData = { ...this._userData, ...data };\n this.log('User data set', data);\n }\n\n identify(userId: string, traits?: UserTraits): void {\n this._userId = userId;\n if (traits) {\n this._userTraits = { ...this._userTraits, ...traits };\n }\n this.log('User identified', { userId, traits });\n }\n\n reset(): void {\n this._userData = {};\n this._userId = null;\n this._userTraits = {};\n this.log('User data reset');\n }\n\n /**\n * Get current user data (for debugging/testing)\n */\n getUserData(): { userId: string | null; data: UserData; traits: UserTraits } {\n return {\n userId: this._userId,\n data: { ...this._userData },\n traits: { ...this._userTraits },\n };\n }\n\n // ===========================================================================\n // Feedback\n // ===========================================================================\n\n async submit(feedback: Partial<FeedbackData>): Promise<void> {\n if (!this.state.isReady) {\n throw new Error('Widget not ready');\n }\n\n // Validate feedback data before submission\n this.validateFeedback(feedback);\n\n this.updateState({ isSubmitting: true });\n\n try {\n const fullFeedback: FeedbackData = {\n message: feedback.message!,\n sentiment: feedback.sentiment,\n customFieldValues: feedback.customFieldValues,\n metadata: {\n page_url: typeof window !== 'undefined' ? window.location.href : '',\n referrer: typeof document !== 'undefined' ? document.referrer : undefined,\n user_agent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined,\n ...feedback.metadata,\n },\n };\n\n // Build user data for submission if any has been set\n const userData = this.buildSubmissionUserData();\n\n await this.apiClient.submitFeedback(this.widgetId, fullFeedback, userData);\n\n this.emitter.emit('submit', fullFeedback);\n this.log('Feedback submitted', userData ? { withUserData: true } : undefined);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.emitter.emit('error', err);\n throw err;\n } finally {\n this.updateState({ isSubmitting: false });\n }\n }\n\n /**\n * Build user data object for API submission\n * Combines data from identify() and setData() calls\n */\n private buildSubmissionUserData(): SubmissionUserData | undefined {\n const hasUserId = this._userId !== null;\n const hasUserData = Object.keys(this._userData).length > 0;\n const hasTraits = Object.keys(this._userTraits).length > 0;\n\n // No user data set, return undefined\n if (!hasUserId && !hasUserData && !hasTraits) {\n return undefined;\n }\n\n const result: SubmissionUserData = {};\n\n // Add user ID if set via identify()\n if (this._userId) {\n result.user_id = this._userId;\n }\n\n // Extract email and name from userData (setData) or traits (identify)\n const email = this._userData.email ?? (this._userTraits.email as string | undefined);\n const name = this._userData.name ?? (this._userTraits.name as string | undefined);\n\n if (email) result.email = email;\n if (name) result.name = name;\n\n // Add traits (excluding email/name which are top-level)\n if (hasTraits) {\n const { email: _e, name: _n, ...otherTraits } = this._userTraits;\n if (Object.keys(otherTraits).length > 0) {\n result.traits = otherTraits;\n }\n }\n\n // Add custom data from setData() (excluding email/name which are top-level)\n if (hasUserData) {\n const { email: _e, name: _n, ...customData } = this._userData;\n // Filter out undefined values\n const filtered: Record<string, string> = {};\n for (const [key, value] of Object.entries(customData)) {\n if (value !== undefined) {\n filtered[key] = value;\n }\n }\n if (Object.keys(filtered).length > 0) {\n result.custom_data = filtered;\n }\n }\n\n return result;\n }\n\n /**\n * Validate feedback data before submission\n * @throws Error if validation fails\n */\n private validateFeedback(feedback: Partial<FeedbackData>): void {\n // Validate message is present and not empty\n if (!feedback.message?.trim()) {\n throw new Error('Feedback message is required');\n }\n\n // Validate message length\n if (feedback.message.length > MAX_MESSAGE_LENGTH) {\n throw new Error(`Feedback message exceeds maximum length of ${MAX_MESSAGE_LENGTH} characters`);\n }\n\n // Validate sentiment if provided\n if (feedback.sentiment !== undefined && !VALID_SENTIMENTS.includes(feedback.sentiment)) {\n throw new Error(`Invalid sentiment value. Must be one of: ${VALID_SENTIMENTS.join(', ')}`);\n }\n\n // Validate customFieldValues are string key-value pairs\n if (feedback.customFieldValues) {\n for (const [key, value] of Object.entries(feedback.customFieldValues)) {\n if (typeof key !== 'string' || typeof value !== 'string') {\n throw new Error('Custom field values must be strings');\n }\n }\n }\n\n // Validate metadata field lengths\n if (feedback.metadata) {\n for (const [key, value] of Object.entries(feedback.metadata)) {\n if (typeof value === 'string' && value.length > MAX_METADATA_VALUE_LENGTH) {\n throw new Error(`Metadata field \"${key}\" exceeds maximum length of ${MAX_METADATA_VALUE_LENGTH} characters`);\n }\n }\n }\n }\n\n // ===========================================================================\n // Events\n // ===========================================================================\n\n on<K extends keyof FeedValueEvents>(event: K, callback: EventHandler<K>): void {\n this.emitter.on(event, callback);\n }\n\n /**\n * Subscribe to an event for a single emission.\n * The handler will be automatically removed after the first call.\n */\n once<K extends keyof FeedValueEvents>(event: K, callback: EventHandler<K>): void {\n this.emitter.once(event, callback);\n }\n\n off<K extends keyof FeedValueEvents>(event: K, callback?: EventHandler<K>): void {\n this.emitter.off(event, callback);\n }\n\n /**\n * Returns a promise that resolves when the widget is ready.\n * Useful for programmatic initialization flows.\n *\n * @throws {Error} If initialization fails\n */\n async waitUntilReady(): Promise<void> {\n if (this.state.isReady) {\n return;\n }\n\n if (this.state.error) {\n throw this.state.error;\n }\n\n return new Promise((resolve, reject) => {\n this.once('ready', () => resolve());\n this.once('error', (error) => reject(error));\n });\n }\n\n // ===========================================================================\n // Configuration\n // ===========================================================================\n\n setConfig(config: Partial<FeedValueConfig>): void {\n this.config = { ...this.config, ...config };\n this.log('Config updated', config);\n }\n\n getConfig(): FeedValueConfig {\n return { ...this.config };\n }\n\n /**\n * Get widget configuration (from API)\n */\n getWidgetConfig(): WidgetConfig | null {\n return this.widgetConfig;\n }\n\n // ===========================================================================\n // Framework Integration\n // ===========================================================================\n\n /**\n * Subscribe to state changes\n * Used by React's useSyncExternalStore\n */\n subscribe(callback: () => void): () => void {\n this.stateSubscribers.add(callback);\n return () => {\n this.stateSubscribers.delete(callback);\n };\n }\n\n /**\n * Get current state snapshot\n * Used by React's useSyncExternalStore\n */\n getSnapshot(): FeedValueState {\n return this.stateSnapshot;\n }\n\n // ===========================================================================\n // Internal Methods\n // ===========================================================================\n\n /**\n * Update state and notify subscribers\n */\n private updateState(partial: Partial<FeedValueState>): void {\n this.state = { ...this.state, ...partial };\n // Create new snapshot (important for React)\n this.stateSnapshot = { ...this.state };\n this.emitter.emit('stateChange', this.stateSnapshot);\n // Notify subscribers\n for (const subscriber of this.stateSubscribers) {\n subscriber();\n }\n }\n\n /**\n * Render widget DOM elements (for vanilla usage)\n */\n private renderWidget(): void {\n if (!this.widgetConfig) return;\n\n // Inject styles once\n if (!this.stylesInjected) {\n this.injectStyles();\n this.stylesInjected = true;\n }\n\n // Create trigger button\n this.renderTrigger();\n\n // Create modal\n this.renderModal();\n }\n\n /**\n * Sanitize CSS to block potentially dangerous patterns\n * Prevents CSS injection attacks via url(), @import, and other vectors\n */\n private sanitizeCSS(css: string): string {\n // Block potentially dangerous CSS patterns\n const BLOCKED_PATTERNS = [\n /url\\s*\\(/gi, // External resources\n /@import/gi, // External stylesheets\n /expression\\s*\\(/gi, // IE expressions\n /javascript:/gi, // JavaScript URLs\n /behavior\\s*:/gi, // IE behaviors\n /-moz-binding/gi, // Firefox XBL\n ];\n\n for (const pattern of BLOCKED_PATTERNS) {\n if (pattern.test(css)) {\n console.warn('[FeedValue] Blocked potentially unsafe CSS pattern');\n return ''; // Block entire CSS if unsafe pattern found\n }\n }\n return css;\n }\n\n /**\n * Inject CSS styles\n */\n private injectStyles(): void {\n if (!this.widgetConfig) return;\n\n const { styling, config } = this.widgetConfig;\n\n const styleEl = document.createElement('style');\n styleEl.id = 'fv-widget-styles';\n styleEl.textContent = this.getBaseStyles(styling, config.position);\n document.head.appendChild(styleEl);\n\n // Custom CSS - sanitize to prevent CSS injection attacks\n if (styling.customCSS) {\n const sanitizedCSS = this.sanitizeCSS(styling.customCSS);\n if (sanitizedCSS) {\n const customStyleEl = document.createElement('style');\n customStyleEl.id = 'fv-widget-custom-styles';\n customStyleEl.textContent = sanitizedCSS;\n document.head.appendChild(customStyleEl);\n }\n }\n }\n\n /**\n * Get base CSS styles\n */\n private getBaseStyles(styling: WidgetConfig['styling'], position: string): string {\n const positionStyles = this.getPositionStyles(position);\n const modalPositionStyles = this.getModalPositionStyles(position);\n\n return `\n .fv-widget-trigger {\n position: fixed;\n ${positionStyles}\n background-color: ${styling.primaryColor};\n color: ${styling.buttonTextColor};\n padding: 12px 24px;\n border-radius: ${styling.borderRadius};\n cursor: pointer;\n z-index: 9998;\n font-family: system-ui, -apple-system, sans-serif;\n font-size: 14px;\n font-weight: 500;\n border: none;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n transition: transform 0.2s, box-shadow 0.2s;\n }\n .fv-widget-trigger:hover {\n transform: translateY(-2px);\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);\n }\n .fv-widget-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, 0.5);\n z-index: 9998;\n display: none;\n backdrop-filter: blur(4px);\n }\n .fv-widget-overlay.fv-widget-open {\n display: block;\n }\n .fv-widget-modal {\n position: fixed;\n ${modalPositionStyles}\n background-color: ${styling.backgroundColor};\n color: ${styling.textColor};\n border-radius: ${styling.borderRadius};\n padding: 24px;\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n overflow-y: auto;\n z-index: 9999;\n display: none;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);\n font-family: system-ui, -apple-system, sans-serif;\n }\n .fv-widget-modal.fv-widget-open {\n display: block;\n }\n .fv-widget-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n }\n .fv-widget-title {\n font-size: 20px;\n font-weight: 600;\n margin: 0;\n }\n .fv-widget-close {\n background: transparent;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: ${styling.textColor};\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .fv-widget-form {\n display: flex;\n flex-direction: column;\n gap: 16px;\n }\n .fv-widget-textarea {\n width: 100%;\n min-height: 120px;\n padding: 12px;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: ${styling.borderRadius};\n font-family: system-ui, -apple-system, sans-serif;\n font-size: 14px;\n resize: vertical;\n box-sizing: border-box;\n background-color: ${styling.backgroundColor};\n color: ${styling.textColor};\n }\n .fv-widget-textarea:focus {\n outline: none;\n border-color: ${styling.primaryColor};\n box-shadow: 0 0 0 2px ${styling.primaryColor}33;\n }\n .fv-widget-submit {\n background-color: ${styling.primaryColor};\n color: ${styling.buttonTextColor};\n padding: 12px 24px;\n border: none;\n border-radius: ${styling.borderRadius};\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: opacity 0.2s;\n }\n .fv-widget-submit:hover:not(:disabled) {\n opacity: 0.9;\n }\n .fv-widget-submit:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n .fv-widget-error {\n color: #ef4444;\n font-size: 14px;\n margin-top: 8px;\n display: none;\n }\n .fv-widget-branding {\n text-align: center;\n font-size: 12px;\n color: ${styling.textColor};\n margin-top: 16px;\n opacity: 0.7;\n }\n .fv-widget-branding a {\n color: ${styling.primaryColor};\n text-decoration: none;\n }\n `;\n }\n\n /**\n * Get trigger button position styles\n */\n private getPositionStyles(position: string): string {\n switch (position) {\n case 'bottom-left':\n return 'bottom: 20px; left: 20px;';\n case 'top-right':\n return 'top: 20px; right: 20px;';\n case 'top-left':\n return 'top: 20px; left: 20px;';\n case 'center':\n return 'top: 50%; left: 50%; transform: translate(-50%, -50%);';\n case 'bottom-right':\n default:\n return 'bottom: 20px; right: 20px;';\n }\n }\n\n /**\n * Get modal position styles\n */\n private getModalPositionStyles(position: string): string {\n switch (position) {\n case 'bottom-left':\n return 'bottom: 20px; left: 20px;';\n case 'bottom-right':\n return 'bottom: 20px; right: 20px;';\n case 'top-right':\n return 'top: 20px; right: 20px;';\n case 'top-left':\n return 'top: 20px; left: 20px;';\n case 'center':\n default:\n return 'top: 50%; left: 50%; transform: translate(-50%, -50%);';\n }\n }\n\n /**\n * Render trigger button using safe DOM methods\n */\n private renderTrigger(): void {\n if (!this.widgetConfig) return;\n\n this.triggerButton = document.createElement('button');\n this.triggerButton.className = 'fv-widget-trigger';\n // textContent is safe - no HTML parsing\n this.triggerButton.textContent = this.widgetConfig.config.triggerText;\n this.triggerButton.addEventListener('click', () => this.open());\n\n document.body.appendChild(this.triggerButton);\n }\n\n /**\n * Render modal using safe DOM methods (no innerHTML)\n */\n private renderModal(): void {\n if (!this.widgetConfig) return;\n\n const { config } = this.widgetConfig;\n\n // Overlay\n this.overlay = document.createElement('div');\n this.overlay.className = 'fv-widget-overlay';\n this.overlay.addEventListener('click', () => this.close());\n document.body.appendChild(this.overlay);\n\n // Modal container\n this.modal = document.createElement('div');\n this.modal.className = 'fv-widget-modal';\n\n // Header\n const header = document.createElement('div');\n header.className = 'fv-widget-header';\n\n const title = document.createElement('h2');\n title.className = 'fv-widget-title';\n title.textContent = config.formTitle; // Safe - textContent\n header.appendChild(title);\n\n const closeBtn = document.createElement('button');\n closeBtn.className = 'fv-widget-close';\n closeBtn.setAttribute('aria-label', 'Close');\n closeBtn.textContent = '×';\n closeBtn.addEventListener('click', () => this.close());\n header.appendChild(closeBtn);\n\n this.modal.appendChild(header);\n\n // Form\n const form = document.createElement('form');\n form.className = 'fv-widget-form';\n form.id = 'fv-feedback-form';\n\n const textarea = document.createElement('textarea');\n textarea.className = 'fv-widget-textarea';\n textarea.id = 'fv-feedback-content';\n textarea.placeholder = 'Tell us what you think...';\n textarea.required = true;\n form.appendChild(textarea);\n\n const submitBtn = document.createElement('button');\n submitBtn.type = 'submit';\n submitBtn.className = 'fv-widget-submit';\n submitBtn.textContent = config.submitButtonText; // Safe - textContent\n form.appendChild(submitBtn);\n\n const errorDiv = document.createElement('div');\n errorDiv.className = 'fv-widget-error';\n errorDiv.id = 'fv-error-message';\n form.appendChild(errorDiv);\n\n form.addEventListener('submit', (e) => this.handleFormSubmit(e));\n this.modal.appendChild(form);\n\n // Branding\n if (config.showBranding) {\n const branding = document.createElement('div');\n branding.className = 'fv-widget-branding';\n\n const brandText = document.createTextNode('Powered by ');\n branding.appendChild(brandText);\n\n const link = document.createElement('a');\n link.href = 'https://feedvalue.com';\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n link.textContent = 'FeedValue';\n branding.appendChild(link);\n\n this.modal.appendChild(branding);\n }\n\n document.body.appendChild(this.modal);\n }\n\n /**\n * Handle form submission\n */\n private async handleFormSubmit(event: Event): Promise<void> {\n event.preventDefault();\n\n const textarea = document.getElementById('fv-feedback-content') as HTMLTextAreaElement;\n const submitBtn = this.modal?.querySelector('.fv-widget-submit') as HTMLButtonElement;\n const errorEl = document.getElementById('fv-error-message');\n\n if (!textarea?.value.trim()) {\n this.showError('Please enter your feedback');\n return;\n }\n\n try {\n submitBtn.disabled = true;\n submitBtn.textContent = 'Submitting...';\n if (errorEl) errorEl.style.display = 'none';\n\n await this.submit({ message: textarea.value.trim() });\n\n // Show success\n this.showSuccess();\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to submit';\n this.showError(message);\n } finally {\n submitBtn.disabled = false;\n submitBtn.textContent = this.widgetConfig?.config.submitButtonText ?? 'Submit';\n }\n }\n\n /**\n * Show error message (safe - uses textContent)\n */\n private showError(message: string): void {\n const errorEl = document.getElementById('fv-error-message');\n if (errorEl) {\n errorEl.textContent = message;\n errorEl.style.display = 'block';\n }\n }\n\n /**\n * Show success message using safe DOM methods\n */\n private showSuccess(): void {\n if (!this.modal || !this.widgetConfig) return;\n\n // Clear any existing auto-close timeout to prevent race conditions\n if (this.autoCloseTimeout) {\n clearTimeout(this.autoCloseTimeout);\n this.autoCloseTimeout = null;\n }\n\n // Clear modal\n this.modal.textContent = '';\n\n // Success container\n const successDiv = document.createElement('div');\n successDiv.style.cssText = 'text-align: center; padding: 40px 20px;';\n\n // Checkmark icon\n const iconDiv = document.createElement('div');\n iconDiv.style.cssText = 'font-size: 48px; margin-bottom: 16px;';\n iconDiv.textContent = '✓';\n successDiv.appendChild(iconDiv);\n\n // Thank you message\n const messageDiv = document.createElement('div');\n messageDiv.style.cssText = 'font-size: 16px; margin-bottom: 24px;';\n messageDiv.textContent = this.widgetConfig.config.thankYouMessage; // Safe\n successDiv.appendChild(messageDiv);\n\n // Close button\n const closeBtn = document.createElement('button');\n closeBtn.className = 'fv-widget-submit';\n closeBtn.textContent = 'Close';\n closeBtn.addEventListener('click', () => {\n this.close();\n this.resetForm();\n });\n successDiv.appendChild(closeBtn);\n\n this.modal.appendChild(successDiv);\n\n // Auto-close after delay (store reference for cleanup)\n this.autoCloseTimeout = setTimeout(() => {\n if (this.state.isOpen) {\n this.close();\n this.resetForm();\n }\n this.autoCloseTimeout = null;\n }, SUCCESS_AUTO_CLOSE_DELAY_MS);\n }\n\n /**\n * Reset form to initial state\n */\n private resetForm(): void {\n if (!this.modal) return;\n\n // Clear and rebuild modal\n this.modal.textContent = '';\n this.modal.remove();\n this.modal = null;\n\n // Re-render\n this.renderModal();\n }\n\n /**\n * Debug logging\n */\n private log(message: string, data?: unknown): void {\n if (this.config.debug) {\n console.log(`[FeedValue] ${message}`, data ?? '');\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/event-emitter.ts","../src/api-client.ts","../src/fingerprint.ts","../src/feedvalue.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @feedvalue/core - Type-Safe Event Emitter\n *\n * A minimal, type-safe event emitter for FeedValue events.\n * Provides compile-time type checking for event names and handlers.\n */\n\nimport type { FeedValueEvents, EventHandler } from './types';\n\n/**\n * Type-safe event emitter for FeedValue events\n *\n * @example\n * ```ts\n * const emitter = new TypedEventEmitter();\n *\n * emitter.on('ready', () => console.log('Ready!'));\n * emitter.on('submit', (feedback) => console.log('Submitted:', feedback));\n *\n * emitter.emit('ready');\n * emitter.emit('submit', { message: 'Great app!' });\n * ```\n */\nexport class TypedEventEmitter {\n // Using a Map with proper typing - the inner Function type is acceptable here\n // because we handle type safety at the public API level (on/off/emit methods)\n private listeners = new Map<keyof FeedValueEvents, Set<(...args: unknown[]) => void>>();\n\n /**\n * Subscribe to an event\n *\n * @param event - Event name\n * @param handler - Event handler function\n */\n on<K extends keyof FeedValueEvents>(event: K, handler: EventHandler<K>): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler as (...args: unknown[]) => void);\n }\n\n /**\n * Subscribe to an event for a single emission.\n * The handler will be automatically removed after the first call.\n *\n * @param event - Event name\n * @param handler - Event handler function\n */\n once<K extends keyof FeedValueEvents>(event: K, handler: EventHandler<K>): void {\n const wrappedHandler = ((...args: unknown[]) => {\n this.off(event, wrappedHandler as EventHandler<K>);\n (handler as (...args: unknown[]) => void)(...args);\n }) as EventHandler<K>;\n\n this.on(event, wrappedHandler);\n }\n\n /**\n * Unsubscribe from an event\n *\n * @param event - Event name\n * @param handler - Optional handler to remove (removes all if not provided)\n */\n off<K extends keyof FeedValueEvents>(event: K, handler?: EventHandler<K>): void {\n if (!handler) {\n // Remove all handlers for this event\n this.listeners.delete(event);\n return;\n }\n\n const handlers = this.listeners.get(event);\n if (handlers) {\n handlers.delete(handler as (...args: unknown[]) => void);\n if (handlers.size === 0) {\n this.listeners.delete(event);\n }\n }\n }\n\n /**\n * Emit an event to all subscribers\n *\n * @param event - Event name\n * @param args - Arguments to pass to handlers\n */\n emit<K extends keyof FeedValueEvents>(\n event: K,\n ...args: Parameters<EventHandler<K>>\n ): void {\n const handlers = this.listeners.get(event);\n if (handlers) {\n for (const handler of handlers) {\n try {\n handler(...args);\n } catch (error) {\n // Prevent one handler's error from breaking others\n console.error(`[FeedValue] Error in ${event} handler:`, error);\n }\n }\n }\n }\n\n /**\n * Remove all event listeners\n */\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","/**\n * @feedvalue/core - API Client\n *\n * Handles all communication with the FeedValue API.\n * Includes request deduplication, caching, and error handling.\n */\n\nimport type { ConfigResponse, FeedbackResponse, FeedbackData, SubmissionUserData } from './types';\n\n/**\n * Default API base URL\n */\nexport const DEFAULT_API_BASE_URL = 'https://api.feedvalue.com';\n\n/** Buffer time before token is considered expired (seconds) */\nconst TOKEN_EXPIRY_BUFFER_SECONDS = 30;\n\n/** How long to cache widget config (milliseconds) */\nconst CONFIG_CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes\n\n/**\n * Cache entry with TTL\n */\ninterface CacheEntry<T> {\n data: T;\n expiresAt: number;\n}\n\n/**\n * API client for FeedValue\n */\nexport class ApiClient {\n private baseUrl: string;\n private debug: boolean;\n\n // Request deduplication\n private pendingRequests = new Map<string, Promise<unknown>>();\n\n // Config cache\n private configCache = new Map<string, CacheEntry<ConfigResponse>>();\n\n // Anti-abuse tokens\n private submissionToken: string | null = null;\n private tokenExpiresAt: number | null = null;\n private fingerprint: string | null = null;\n\n constructor(baseUrl: string = DEFAULT_API_BASE_URL, debug = false) {\n this.baseUrl = baseUrl.replace(/\\/$/, ''); // Remove trailing slash\n this.debug = debug;\n }\n\n /**\n * Validate widget ID to prevent path injection attacks\n * @throws Error if widget ID is invalid\n */\n private validateWidgetId(widgetId: string): void {\n if (!widgetId || typeof widgetId !== 'string') {\n throw new Error('Widget ID is required');\n }\n if (!/^[a-zA-Z0-9_-]+$/.test(widgetId)) {\n throw new Error('Invalid widget ID format: only alphanumeric characters, underscores, and hyphens are allowed');\n }\n if (widgetId.length > 64) {\n throw new Error('Widget ID exceeds maximum length of 64 characters');\n }\n }\n\n /**\n * Set client fingerprint for anti-abuse protection\n */\n setFingerprint(fingerprint: string): void {\n this.fingerprint = fingerprint;\n }\n\n /**\n * Get client fingerprint\n */\n getFingerprint(): string | null {\n return this.fingerprint;\n }\n\n /**\n * Check if submission token is valid\n */\n hasValidToken(): boolean {\n if (!this.submissionToken || !this.tokenExpiresAt) {\n return false;\n }\n // Add buffer before expiry\n return Date.now() / 1000 < this.tokenExpiresAt - TOKEN_EXPIRY_BUFFER_SECONDS;\n }\n\n /**\n * Fetch widget configuration\n * Uses caching and request deduplication\n *\n * @param widgetId - Widget ID to fetch config for\n * @param forceRefresh - Skip cache and fetch fresh config (used for token refresh)\n */\n async fetchConfig(widgetId: string, forceRefresh = false): Promise<ConfigResponse> {\n this.validateWidgetId(widgetId);\n const cacheKey = `config:${widgetId}`;\n\n // Check cache first (unless forcing refresh)\n if (!forceRefresh) {\n const cached = this.configCache.get(cacheKey);\n if (cached && Date.now() < cached.expiresAt) {\n this.log('Config cache hit', { widgetId });\n return cached.data;\n }\n } else {\n this.log('Bypassing cache for token refresh', { widgetId });\n }\n\n // Deduplicate concurrent requests\n const pendingKey = `fetchConfig:${widgetId}`;\n const pending = this.pendingRequests.get(pendingKey);\n if (pending) {\n this.log('Deduplicating config request', { widgetId });\n return pending as Promise<ConfigResponse>;\n }\n\n const request = this.doFetchConfig(widgetId);\n this.pendingRequests.set(pendingKey, request);\n\n try {\n const result = await request;\n return result;\n } finally {\n this.pendingRequests.delete(pendingKey);\n }\n }\n\n /**\n * Actually fetch config from API\n */\n private async doFetchConfig(widgetId: string): Promise<ConfigResponse> {\n const url = `${this.baseUrl}/api/v1/widgets/${widgetId}/config`;\n\n const headers: Record<string, string> = {};\n if (this.fingerprint) {\n headers['X-Client-Fingerprint'] = this.fingerprint;\n }\n\n this.log('Fetching config', {\n widgetId,\n url,\n hasFingerprint: !!this.fingerprint,\n fingerprintPreview: this.fingerprint ? `${this.fingerprint.substring(0, 8)}...` : null,\n });\n\n const response = await fetch(url, {\n method: 'GET',\n headers,\n });\n\n if (!response.ok) {\n const error = await this.parseError(response);\n throw new Error(error);\n }\n\n const data = await response.json() as ConfigResponse;\n\n // Store submission token\n if (data.submission_token) {\n this.submissionToken = data.submission_token;\n this.tokenExpiresAt = data.token_expires_at ?? null;\n this.log('Submission token stored', {\n expiresAt: this.tokenExpiresAt ? new Date(this.tokenExpiresAt * 1000).toISOString() : 'unknown',\n });\n } else {\n this.log('No submission token in response', {\n hasWidgetId: !!data.widget_id,\n hasConfig: !!data.config,\n responseKeys: Object.keys(data),\n });\n }\n\n // Cache the response\n const cacheKey = `config:${widgetId}`;\n this.configCache.set(cacheKey, {\n data,\n expiresAt: Date.now() + CONFIG_CACHE_TTL_MS,\n });\n\n this.log('Config fetched', { widgetId });\n return data;\n }\n\n /**\n * Submit feedback with optional user data\n */\n async submitFeedback(\n widgetId: string,\n feedback: FeedbackData,\n userData?: SubmissionUserData\n ): Promise<FeedbackResponse> {\n this.validateWidgetId(widgetId);\n const url = `${this.baseUrl}/api/v1/widgets/${widgetId}/feedback`;\n\n // Refresh token if needed (force refresh to bypass cache)\n if (!this.hasValidToken()) {\n this.log('Token expired, refreshing...');\n await this.fetchConfig(widgetId, true);\n }\n\n if (!this.submissionToken) {\n throw new Error('No submission token available');\n }\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Submission-Token': this.submissionToken,\n };\n\n if (this.fingerprint) {\n headers['X-Client-Fingerprint'] = this.fingerprint;\n }\n\n this.log('Submitting feedback', { widgetId });\n\n // Merge user data into metadata (core-api stores metadata, not separate user field)\n // User data from identify()/setData() goes into metadata.user\n const mergedMetadata = {\n ...feedback.metadata,\n ...(userData && Object.keys(userData).length > 0 && {\n user: userData,\n }),\n };\n\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n message: feedback.message,\n metadata: Object.keys(mergedMetadata).length > 0 ? mergedMetadata : undefined,\n ...(feedback.customFieldValues && {\n customFieldValues: feedback.customFieldValues,\n }),\n }),\n });\n\n // Handle rate limiting\n if (response.status === 429) {\n const resetAt = response.headers.get('X-RateLimit-Reset');\n const retryAfter = resetAt\n ? Math.ceil(parseInt(resetAt, 10) - Date.now() / 1000)\n : 60;\n throw new Error(`Rate limited. Try again in ${retryAfter} seconds.`);\n }\n\n // Handle forbidden (token issues)\n if (response.status === 403) {\n const errorData = await response.json().catch(() => ({ detail: 'Access denied' }));\n\n // Check for subscription limit\n if (errorData.detail?.code && errorData.detail?.message) {\n throw new Error(errorData.detail.message);\n }\n\n // Try token refresh and retry once\n const errorMessage = typeof errorData.detail === 'string' ? errorData.detail : '';\n if (errorMessage.includes('token') || errorMessage.includes('expired')) {\n this.log('Token rejected, refreshing...');\n this.submissionToken = null;\n await this.fetchConfig(widgetId, true);\n\n if (this.submissionToken) {\n // Retry with new token\n headers['X-Submission-Token'] = this.submissionToken;\n const retryResponse = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n message: feedback.message,\n metadata: feedback.metadata,\n ...(feedback.customFieldValues && {\n customFieldValues: feedback.customFieldValues,\n }),\n ...(userData && Object.keys(userData).length > 0 && {\n user: userData,\n }),\n }),\n });\n\n if (retryResponse.ok) {\n return retryResponse.json();\n }\n }\n }\n\n throw new Error(errorMessage || 'Access denied');\n }\n\n if (!response.ok) {\n const error = await this.parseError(response);\n throw new Error(error);\n }\n\n const data = await response.json() as FeedbackResponse;\n\n // Check for soft blocks\n if (data.blocked) {\n throw new Error(data.message || 'Unable to submit feedback');\n }\n\n this.log('Feedback submitted', { feedbackId: data.feedback_id });\n return data;\n }\n\n /**\n * Parse error from response\n */\n private async parseError(response: Response): Promise<string> {\n try {\n const data = await response.json();\n return data.detail || data.message || data.error || `HTTP ${response.status}`;\n } catch {\n return `HTTP ${response.status}: ${response.statusText}`;\n }\n }\n\n /**\n * Clear all caches\n */\n clearCache(): void {\n this.configCache.clear();\n this.submissionToken = null;\n this.tokenExpiresAt = null;\n this.log('Cache cleared');\n }\n\n /**\n * Debug logging\n */\n private log(message: string, data?: Record<string, unknown>): void {\n if (this.debug) {\n console.log(`[FeedValue API] ${message}`, data ?? '');\n }\n }\n}\n","/**\n * Simple fingerprint generation for anti-abuse protection.\n * Uses a session-based hex string stored in sessionStorage.\n *\n * This replaces the previous complex fingerprinting system (canvas, WebGL, audio)\n * which was overkill for an MVP feedback widget and raised privacy concerns.\n *\n * The fingerprint is a 32-character hex string (16 random bytes), matching\n * the format expected by the core-api's TokenPayload validator.\n */\n\n/**\n * Storage key for the fingerprint\n */\nconst FINGERPRINT_STORAGE_KEY = 'fv_fingerprint';\n\n/**\n * Generate a 32-character hex string (16 random bytes).\n * Uses crypto.getRandomValues which is available in all modern browsers and Node.js 15+.\n */\nfunction generateHexFingerprint(): string {\n if (typeof crypto === 'undefined' || typeof crypto.getRandomValues !== 'function') {\n throw new Error(\n 'crypto.getRandomValues is required but not available. ' +\n 'Ensure you are running in a modern browser or Node.js 15+.'\n );\n }\n\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Generate or retrieve a session fingerprint.\n *\n * The fingerprint is:\n * - Generated once per browser session as a 32-character hex string\n * - Stored in sessionStorage for consistency within a session\n * - Automatically cleared when the browser tab/window is closed\n *\n * @returns A unique fingerprint hex string for the current session\n */\nexport function generateFingerprint(): string {\n // Check for SSR environment\n if (typeof window === 'undefined' || typeof sessionStorage === 'undefined') {\n return generateHexFingerprint();\n }\n\n // Try to get existing fingerprint from session\n const stored = sessionStorage.getItem(FINGERPRINT_STORAGE_KEY);\n if (stored) {\n // Migrate old UUID format to hex format (remove dashes)\n if (stored.includes('-')) {\n const hexFingerprint = stored.replace(/-/g, '');\n try {\n sessionStorage.setItem(FINGERPRINT_STORAGE_KEY, hexFingerprint);\n } catch {\n // Ignore storage errors\n }\n return hexFingerprint;\n }\n return stored;\n }\n\n // Generate new fingerprint\n const fingerprint = generateHexFingerprint();\n\n try {\n sessionStorage.setItem(FINGERPRINT_STORAGE_KEY, fingerprint);\n } catch {\n // sessionStorage may be unavailable (private browsing, quota exceeded)\n // Fall through and return the generated fingerprint anyway\n }\n\n return fingerprint;\n}\n\n/**\n * Clear the stored fingerprint.\n * Useful for testing or when user requests data reset.\n */\nexport function clearFingerprint(): void {\n if (typeof sessionStorage !== 'undefined') {\n try {\n sessionStorage.removeItem(FINGERPRINT_STORAGE_KEY);\n } catch {\n // Ignore errors\n }\n }\n}\n","/**\n * @feedvalue/core - FeedValue Class\n *\n * Main FeedValue SDK class. Provides the public API for interacting\n * with the feedback widget.\n *\n * For vanilla JavaScript usage, this class also handles DOM rendering.\n * Framework packages (React, Vue) use this class as a headless core.\n */\n\nimport type {\n FeedValueOptions,\n FeedValueConfig,\n FeedValueState,\n FeedValueInstance,\n FeedValueEvents,\n EventHandler,\n UserData,\n UserTraits,\n FeedbackData,\n WidgetConfig,\n EmojiSentiment,\n SubmissionUserData,\n} from './types';\nimport { TypedEventEmitter } from './event-emitter';\nimport { ApiClient, DEFAULT_API_BASE_URL } from './api-client';\nimport { generateFingerprint } from './fingerprint';\n\n/** Delay before auto-closing the success message (milliseconds) */\nconst SUCCESS_AUTO_CLOSE_DELAY_MS = 3000;\n\n/**\n * Valid sentiment values for feedback validation\n */\nconst VALID_SENTIMENTS: readonly EmojiSentiment[] = ['angry', 'disappointed', 'satisfied', 'excited'] as const;\n\n/**\n * Maximum allowed message length (10,000 characters)\n */\nconst MAX_MESSAGE_LENGTH = 10000;\n\n/**\n * Maximum allowed length for metadata string values (1,000 characters)\n */\nconst MAX_METADATA_VALUE_LENGTH = 1000;\n\n/**\n * Default configuration\n */\nconst DEFAULT_CONFIG: FeedValueConfig = {\n theme: 'auto',\n autoShow: true,\n debug: false,\n locale: 'en',\n};\n\n/**\n * Instance registry for singleton per widgetId\n */\nconst instances = new Map<string, FeedValue>();\n\n/**\n * FeedValue SDK\n *\n * @example\n * ```ts\n * // Initialize\n * const feedvalue = FeedValue.init({ widgetId: 'abc123' });\n *\n * // Control\n * feedvalue.open();\n * feedvalue.close();\n *\n * // User data\n * feedvalue.setData({ email: 'user@example.com' });\n * feedvalue.identify('user-123', { plan: 'pro' });\n *\n * // Events\n * feedvalue.on('submit', (feedback) => {\n * console.log('Feedback submitted:', feedback);\n * });\n * ```\n */\nexport class FeedValue implements FeedValueInstance {\n private readonly widgetId: string;\n private readonly apiClient: ApiClient;\n private readonly emitter: TypedEventEmitter;\n private readonly headless: boolean;\n private config: FeedValueConfig;\n private widgetConfig: WidgetConfig | null = null;\n\n // State\n private state: FeedValueState = {\n isReady: false,\n isOpen: false,\n isVisible: true,\n error: null,\n isSubmitting: false,\n };\n\n // State subscribers (for React useSyncExternalStore)\n private stateSubscribers = new Set<() => void>();\n private stateSnapshot: FeedValueState;\n\n // User data (stored for future API submissions)\n private _userData: UserData = {};\n private _userId: string | null = null;\n private _userTraits: UserTraits = {};\n\n // DOM elements (for vanilla usage)\n private triggerButton: HTMLElement | null = null;\n private modal: HTMLElement | null = null;\n private overlay: HTMLElement | null = null;\n private stylesInjected = false;\n\n // Auto-close timeout reference (for cleanup on destroy)\n private autoCloseTimeout: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Create a new FeedValue instance\n * Use FeedValue.init() for public API\n */\n private constructor(options: FeedValueOptions) {\n this.widgetId = options.widgetId;\n this.headless = options.headless ?? false;\n this.config = { ...DEFAULT_CONFIG, ...options.config };\n\n this.apiClient = new ApiClient(\n options.apiBaseUrl ?? DEFAULT_API_BASE_URL,\n this.config.debug\n );\n\n this.emitter = new TypedEventEmitter();\n this.stateSnapshot = { ...this.state };\n\n this.log('Instance created', { widgetId: this.widgetId, headless: this.headless });\n }\n\n /**\n * Initialize FeedValue\n * Returns existing instance if already initialized for this widgetId\n */\n static init(options: FeedValueOptions): FeedValue {\n // Return existing instance if available\n const existing = instances.get(options.widgetId);\n if (existing) {\n return existing;\n }\n\n // Create new instance\n const instance = new FeedValue(options);\n instances.set(options.widgetId, instance);\n\n // Auto-initialize\n instance.init().catch((error) => {\n console.error('[FeedValue] Initialization failed:', error);\n });\n\n return instance;\n }\n\n /**\n * Get existing instance by widgetId\n */\n static getInstance(widgetId: string): FeedValue | undefined {\n return instances.get(widgetId);\n }\n\n // ===========================================================================\n // Lifecycle\n // ===========================================================================\n\n /**\n * Initialize the widget\n */\n async init(): Promise<void> {\n if (this.state.isReady) {\n this.log('Already initialized');\n return;\n }\n\n try {\n this.log('Initializing...');\n\n // Generate fingerprint\n const fingerprint = generateFingerprint();\n this.apiClient.setFingerprint(fingerprint);\n\n // Fetch config\n const configResponse = await this.apiClient.fetchConfig(this.widgetId);\n\n // Build widget config\n this.widgetConfig = {\n widgetId: configResponse.widget_id,\n widgetKey: configResponse.widget_key,\n appId: '',\n config: {\n position: configResponse.config.position ?? 'bottom-right',\n triggerText: configResponse.config.triggerText ?? 'Feedback',\n triggerIcon: configResponse.config.triggerIcon ?? 'none',\n formTitle: configResponse.config.formTitle ?? 'Share your feedback',\n submitButtonText: configResponse.config.submitButtonText ?? 'Submit',\n thankYouMessage: configResponse.config.thankYouMessage ?? 'Thank you for your feedback!',\n showBranding: configResponse.config.showBranding ?? true,\n customFields: configResponse.config.customFields,\n },\n styling: {\n primaryColor: configResponse.styling.primaryColor ?? '#3b82f6',\n backgroundColor: configResponse.styling.backgroundColor ?? '#ffffff',\n textColor: configResponse.styling.textColor ?? '#1f2937',\n buttonTextColor: configResponse.styling.buttonTextColor ?? '#ffffff',\n borderRadius: configResponse.styling.borderRadius ?? '8px',\n customCSS: configResponse.styling.customCSS,\n },\n };\n\n // Render DOM (for vanilla usage, skip in headless mode)\n if (!this.headless && typeof window !== 'undefined' && typeof document !== 'undefined') {\n this.renderWidget();\n }\n\n // Update state\n this.updateState({ isReady: true, error: null });\n this.emitter.emit('ready');\n\n this.log('Initialized successfully');\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.updateState({ error: err });\n this.emitter.emit('error', err);\n throw err;\n }\n }\n\n /**\n * Destroy the widget\n */\n destroy(): void {\n this.log('Destroying...');\n\n // Clear auto-close timeout to prevent memory leak\n if (this.autoCloseTimeout) {\n clearTimeout(this.autoCloseTimeout);\n this.autoCloseTimeout = null;\n }\n\n // Remove DOM elements\n this.triggerButton?.remove();\n this.modal?.remove();\n this.overlay?.remove();\n document.getElementById('fv-widget-styles')?.remove();\n document.getElementById('fv-widget-custom-styles')?.remove();\n\n // Clear references\n this.triggerButton = null;\n this.modal = null;\n this.overlay = null;\n this.widgetConfig = null;\n\n // Clear state\n this.stateSubscribers.clear();\n this.emitter.removeAllListeners();\n this.apiClient.clearCache();\n\n // Remove from registry\n instances.delete(this.widgetId);\n\n // Reset state\n this.state = {\n isReady: false,\n isOpen: false,\n isVisible: false,\n error: null,\n isSubmitting: false,\n };\n\n this.log('Destroyed');\n }\n\n // ===========================================================================\n // Widget Control\n // ===========================================================================\n\n open(): void {\n if (!this.state.isReady) {\n this.log('Cannot open: not ready');\n return;\n }\n\n this.updateState({ isOpen: true });\n\n // Only manipulate DOM in non-headless mode\n if (!this.headless) {\n this.overlay?.classList.add('fv-widget-open');\n this.modal?.classList.add('fv-widget-open');\n }\n\n this.emitter.emit('open');\n this.log('Opened');\n }\n\n close(): void {\n this.updateState({ isOpen: false });\n\n // Only manipulate DOM in non-headless mode\n if (!this.headless) {\n this.overlay?.classList.remove('fv-widget-open');\n this.modal?.classList.remove('fv-widget-open');\n }\n\n this.emitter.emit('close');\n this.log('Closed');\n }\n\n toggle(): void {\n if (this.state.isOpen) {\n this.close();\n } else {\n this.open();\n }\n }\n\n show(): void {\n this.updateState({ isVisible: true });\n\n // Only manipulate DOM in non-headless mode\n if (!this.headless && this.triggerButton) {\n this.triggerButton.style.display = '';\n }\n\n this.log('Shown');\n }\n\n hide(): void {\n this.updateState({ isVisible: false });\n\n // Only manipulate DOM in non-headless mode\n if (!this.headless && this.triggerButton) {\n this.triggerButton.style.display = 'none';\n }\n\n this.log('Hidden');\n }\n\n // ===========================================================================\n // State Queries\n // ===========================================================================\n\n isOpen(): boolean {\n return this.state.isOpen;\n }\n\n isVisible(): boolean {\n return this.state.isVisible;\n }\n\n isReady(): boolean {\n return this.state.isReady;\n }\n\n isHeadless(): boolean {\n return this.headless;\n }\n\n // ===========================================================================\n // User Data\n // ===========================================================================\n\n setData(data: Partial<UserData>): void {\n this._userData = { ...this._userData, ...data };\n this.log('User data set', data);\n }\n\n identify(userId: string, traits?: UserTraits): void {\n this._userId = userId;\n if (traits) {\n this._userTraits = { ...this._userTraits, ...traits };\n }\n this.log('User identified', { userId, traits });\n }\n\n reset(): void {\n this._userData = {};\n this._userId = null;\n this._userTraits = {};\n this.log('User data reset');\n }\n\n /**\n * Get current user data (for debugging/testing)\n */\n getUserData(): { userId: string | null; data: UserData; traits: UserTraits } {\n return {\n userId: this._userId,\n data: { ...this._userData },\n traits: { ...this._userTraits },\n };\n }\n\n // ===========================================================================\n // Feedback\n // ===========================================================================\n\n async submit(feedback: Partial<FeedbackData>): Promise<void> {\n if (!this.state.isReady) {\n throw new Error('Widget not ready');\n }\n\n // Validate feedback data before submission\n this.validateFeedback(feedback);\n\n this.updateState({ isSubmitting: true });\n\n try {\n const fullFeedback: FeedbackData = {\n message: feedback.message!,\n sentiment: feedback.sentiment,\n customFieldValues: feedback.customFieldValues,\n metadata: {\n page_url: typeof window !== 'undefined' ? window.location.href : '',\n referrer: typeof document !== 'undefined' ? document.referrer : undefined,\n user_agent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined,\n ...feedback.metadata,\n },\n };\n\n // Build user data for submission if any has been set\n const userData = this.buildSubmissionUserData();\n\n await this.apiClient.submitFeedback(this.widgetId, fullFeedback, userData);\n\n this.emitter.emit('submit', fullFeedback);\n this.log('Feedback submitted', userData ? { withUserData: true } : undefined);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.emitter.emit('error', err);\n throw err;\n } finally {\n this.updateState({ isSubmitting: false });\n }\n }\n\n /**\n * Build user data object for API submission\n * Combines data from identify() and setData() calls\n */\n private buildSubmissionUserData(): SubmissionUserData | undefined {\n const hasUserId = this._userId !== null;\n const hasUserData = Object.keys(this._userData).length > 0;\n const hasTraits = Object.keys(this._userTraits).length > 0;\n\n // No user data set, return undefined\n if (!hasUserId && !hasUserData && !hasTraits) {\n return undefined;\n }\n\n const result: SubmissionUserData = {};\n\n // Add user ID if set via identify()\n if (this._userId) {\n result.user_id = this._userId;\n }\n\n // Extract email and name from userData (setData) or traits (identify)\n const email = this._userData.email ?? (this._userTraits.email as string | undefined);\n const name = this._userData.name ?? (this._userTraits.name as string | undefined);\n\n if (email) result.email = email;\n if (name) result.name = name;\n\n // Add traits (excluding email/name which are top-level)\n if (hasTraits) {\n const { email: _e, name: _n, ...otherTraits } = this._userTraits;\n if (Object.keys(otherTraits).length > 0) {\n result.traits = otherTraits;\n }\n }\n\n // Add custom data from setData() (excluding email/name which are top-level)\n if (hasUserData) {\n const { email: _e, name: _n, ...customData } = this._userData;\n // Filter out undefined values\n const filtered: Record<string, string> = {};\n for (const [key, value] of Object.entries(customData)) {\n if (value !== undefined) {\n filtered[key] = value;\n }\n }\n if (Object.keys(filtered).length > 0) {\n result.custom_data = filtered;\n }\n }\n\n return result;\n }\n\n /**\n * Validate feedback data before submission\n * @throws Error if validation fails\n */\n private validateFeedback(feedback: Partial<FeedbackData>): void {\n // Validate message is present and not empty\n if (!feedback.message?.trim()) {\n throw new Error('Feedback message is required');\n }\n\n // Validate message length\n if (feedback.message.length > MAX_MESSAGE_LENGTH) {\n throw new Error(`Feedback message exceeds maximum length of ${MAX_MESSAGE_LENGTH} characters`);\n }\n\n // Validate sentiment if provided\n if (feedback.sentiment !== undefined && !VALID_SENTIMENTS.includes(feedback.sentiment)) {\n throw new Error(`Invalid sentiment value. Must be one of: ${VALID_SENTIMENTS.join(', ')}`);\n }\n\n // Validate customFieldValues are string key-value pairs\n if (feedback.customFieldValues) {\n for (const [key, value] of Object.entries(feedback.customFieldValues)) {\n if (typeof key !== 'string' || typeof value !== 'string') {\n throw new Error('Custom field values must be strings');\n }\n }\n }\n\n // Validate metadata field lengths\n if (feedback.metadata) {\n for (const [key, value] of Object.entries(feedback.metadata)) {\n if (typeof value === 'string' && value.length > MAX_METADATA_VALUE_LENGTH) {\n throw new Error(`Metadata field \"${key}\" exceeds maximum length of ${MAX_METADATA_VALUE_LENGTH} characters`);\n }\n }\n }\n }\n\n // ===========================================================================\n // Events\n // ===========================================================================\n\n on<K extends keyof FeedValueEvents>(event: K, callback: EventHandler<K>): void {\n this.emitter.on(event, callback);\n }\n\n /**\n * Subscribe to an event for a single emission.\n * The handler will be automatically removed after the first call.\n */\n once<K extends keyof FeedValueEvents>(event: K, callback: EventHandler<K>): void {\n this.emitter.once(event, callback);\n }\n\n off<K extends keyof FeedValueEvents>(event: K, callback?: EventHandler<K>): void {\n this.emitter.off(event, callback);\n }\n\n /**\n * Returns a promise that resolves when the widget is ready.\n * Useful for programmatic initialization flows.\n *\n * @throws {Error} If initialization fails\n */\n async waitUntilReady(): Promise<void> {\n if (this.state.isReady) {\n return;\n }\n\n if (this.state.error) {\n throw this.state.error;\n }\n\n return new Promise((resolve, reject) => {\n this.once('ready', () => resolve());\n this.once('error', (error) => reject(error));\n });\n }\n\n // ===========================================================================\n // Configuration\n // ===========================================================================\n\n setConfig(config: Partial<FeedValueConfig>): void {\n this.config = { ...this.config, ...config };\n this.log('Config updated', config);\n }\n\n getConfig(): FeedValueConfig {\n return { ...this.config };\n }\n\n /**\n * Get widget configuration (from API)\n */\n getWidgetConfig(): WidgetConfig | null {\n return this.widgetConfig;\n }\n\n // ===========================================================================\n // Framework Integration\n // ===========================================================================\n\n /**\n * Subscribe to state changes\n * Used by React's useSyncExternalStore\n */\n subscribe(callback: () => void): () => void {\n this.stateSubscribers.add(callback);\n return () => {\n this.stateSubscribers.delete(callback);\n };\n }\n\n /**\n * Get current state snapshot\n * Used by React's useSyncExternalStore\n */\n getSnapshot(): FeedValueState {\n return this.stateSnapshot;\n }\n\n // ===========================================================================\n // Internal Methods\n // ===========================================================================\n\n /**\n * Update state and notify subscribers\n */\n private updateState(partial: Partial<FeedValueState>): void {\n this.state = { ...this.state, ...partial };\n // Create new snapshot (important for React)\n this.stateSnapshot = { ...this.state };\n this.emitter.emit('stateChange', this.stateSnapshot);\n // Notify subscribers\n for (const subscriber of this.stateSubscribers) {\n subscriber();\n }\n }\n\n /**\n * Render widget DOM elements (for vanilla usage)\n */\n private renderWidget(): void {\n if (!this.widgetConfig) return;\n\n // Inject styles once\n if (!this.stylesInjected) {\n this.injectStyles();\n this.stylesInjected = true;\n }\n\n // Create trigger button\n this.renderTrigger();\n\n // Create modal\n this.renderModal();\n }\n\n /**\n * Sanitize CSS to block potentially dangerous patterns\n * Prevents CSS injection attacks via url(), @import, and other vectors\n */\n private sanitizeCSS(css: string): string {\n // Block potentially dangerous CSS patterns\n const BLOCKED_PATTERNS = [\n /url\\s*\\(/gi, // External resources\n /@import/gi, // External stylesheets\n /expression\\s*\\(/gi, // IE expressions\n /javascript:/gi, // JavaScript URLs\n /behavior\\s*:/gi, // IE behaviors\n /-moz-binding/gi, // Firefox XBL\n ];\n\n for (const pattern of BLOCKED_PATTERNS) {\n if (pattern.test(css)) {\n console.warn('[FeedValue] Blocked potentially unsafe CSS pattern');\n return ''; // Block entire CSS if unsafe pattern found\n }\n }\n return css;\n }\n\n /**\n * Inject CSS styles\n */\n private injectStyles(): void {\n if (!this.widgetConfig) return;\n\n const { styling, config } = this.widgetConfig;\n\n const styleEl = document.createElement('style');\n styleEl.id = 'fv-widget-styles';\n styleEl.textContent = this.getBaseStyles(styling, config.position);\n document.head.appendChild(styleEl);\n\n // Custom CSS - sanitize to prevent CSS injection attacks\n if (styling.customCSS) {\n const sanitizedCSS = this.sanitizeCSS(styling.customCSS);\n if (sanitizedCSS) {\n const customStyleEl = document.createElement('style');\n customStyleEl.id = 'fv-widget-custom-styles';\n customStyleEl.textContent = sanitizedCSS;\n document.head.appendChild(customStyleEl);\n }\n }\n }\n\n /**\n * Get base CSS styles\n */\n private getBaseStyles(styling: WidgetConfig['styling'], position: string): string {\n const positionStyles = this.getPositionStyles(position);\n const modalPositionStyles = this.getModalPositionStyles(position);\n\n return `\n .fv-widget-trigger {\n position: fixed;\n ${positionStyles}\n background-color: ${styling.primaryColor};\n color: ${styling.buttonTextColor};\n padding: 12px 24px;\n border-radius: ${styling.borderRadius};\n cursor: pointer;\n z-index: 9998;\n font-family: system-ui, -apple-system, sans-serif;\n font-size: 14px;\n font-weight: 500;\n border: none;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n transition: transform 0.2s, box-shadow 0.2s;\n }\n .fv-widget-trigger:hover {\n transform: translateY(-2px);\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);\n }\n .fv-widget-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, 0.5);\n z-index: 9998;\n display: none;\n backdrop-filter: blur(4px);\n }\n .fv-widget-overlay.fv-widget-open {\n display: block;\n }\n .fv-widget-modal {\n position: fixed;\n ${modalPositionStyles}\n background-color: ${styling.backgroundColor};\n color: ${styling.textColor};\n border-radius: ${styling.borderRadius};\n padding: 24px;\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n overflow-y: auto;\n z-index: 9999;\n display: none;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);\n font-family: system-ui, -apple-system, sans-serif;\n }\n .fv-widget-modal.fv-widget-open {\n display: block;\n }\n .fv-widget-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n }\n .fv-widget-title {\n font-size: 20px;\n font-weight: 600;\n margin: 0;\n }\n .fv-widget-close {\n background: transparent;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: ${styling.textColor};\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .fv-widget-form {\n display: flex;\n flex-direction: column;\n gap: 16px;\n }\n .fv-widget-textarea {\n width: 100%;\n min-height: 120px;\n padding: 12px;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: ${styling.borderRadius};\n font-family: system-ui, -apple-system, sans-serif;\n font-size: 14px;\n resize: vertical;\n box-sizing: border-box;\n background-color: ${styling.backgroundColor};\n color: ${styling.textColor};\n }\n .fv-widget-textarea:focus {\n outline: none;\n border-color: ${styling.primaryColor};\n box-shadow: 0 0 0 2px ${styling.primaryColor}33;\n }\n .fv-widget-submit {\n background-color: ${styling.primaryColor};\n color: ${styling.buttonTextColor};\n padding: 12px 24px;\n border: none;\n border-radius: ${styling.borderRadius};\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: opacity 0.2s;\n }\n .fv-widget-submit:hover:not(:disabled) {\n opacity: 0.9;\n }\n .fv-widget-submit:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n .fv-widget-error {\n color: #ef4444;\n font-size: 14px;\n margin-top: 8px;\n display: none;\n }\n .fv-widget-branding {\n text-align: center;\n font-size: 12px;\n color: ${styling.textColor};\n margin-top: 16px;\n opacity: 0.7;\n }\n .fv-widget-branding a {\n color: ${styling.primaryColor};\n text-decoration: none;\n }\n `;\n }\n\n /**\n * Get trigger button position styles\n */\n private getPositionStyles(position: string): string {\n switch (position) {\n case 'bottom-left':\n return 'bottom: 20px; left: 20px;';\n case 'top-right':\n return 'top: 20px; right: 20px;';\n case 'top-left':\n return 'top: 20px; left: 20px;';\n case 'center':\n return 'top: 50%; left: 50%; transform: translate(-50%, -50%);';\n case 'bottom-right':\n default:\n return 'bottom: 20px; right: 20px;';\n }\n }\n\n /**\n * Get modal position styles\n */\n private getModalPositionStyles(position: string): string {\n switch (position) {\n case 'bottom-left':\n return 'bottom: 20px; left: 20px;';\n case 'bottom-right':\n return 'bottom: 20px; right: 20px;';\n case 'top-right':\n return 'top: 20px; right: 20px;';\n case 'top-left':\n return 'top: 20px; left: 20px;';\n case 'center':\n default:\n return 'top: 50%; left: 50%; transform: translate(-50%, -50%);';\n }\n }\n\n /**\n * Render trigger button using safe DOM methods\n */\n private renderTrigger(): void {\n if (!this.widgetConfig) return;\n\n this.triggerButton = document.createElement('button');\n this.triggerButton.className = 'fv-widget-trigger';\n // textContent is safe - no HTML parsing\n this.triggerButton.textContent = this.widgetConfig.config.triggerText;\n this.triggerButton.addEventListener('click', () => this.open());\n\n document.body.appendChild(this.triggerButton);\n }\n\n /**\n * Render modal using safe DOM methods (no innerHTML)\n */\n private renderModal(): void {\n if (!this.widgetConfig) return;\n\n const { config } = this.widgetConfig;\n\n // Overlay\n this.overlay = document.createElement('div');\n this.overlay.className = 'fv-widget-overlay';\n this.overlay.addEventListener('click', () => this.close());\n document.body.appendChild(this.overlay);\n\n // Modal container\n this.modal = document.createElement('div');\n this.modal.className = 'fv-widget-modal';\n\n // Header\n const header = document.createElement('div');\n header.className = 'fv-widget-header';\n\n const title = document.createElement('h2');\n title.className = 'fv-widget-title';\n title.textContent = config.formTitle; // Safe - textContent\n header.appendChild(title);\n\n const closeBtn = document.createElement('button');\n closeBtn.className = 'fv-widget-close';\n closeBtn.setAttribute('aria-label', 'Close');\n closeBtn.textContent = '×';\n closeBtn.addEventListener('click', () => this.close());\n header.appendChild(closeBtn);\n\n this.modal.appendChild(header);\n\n // Form\n const form = document.createElement('form');\n form.className = 'fv-widget-form';\n form.id = 'fv-feedback-form';\n\n const textarea = document.createElement('textarea');\n textarea.className = 'fv-widget-textarea';\n textarea.id = 'fv-feedback-content';\n textarea.placeholder = 'Tell us what you think...';\n textarea.required = true;\n form.appendChild(textarea);\n\n const submitBtn = document.createElement('button');\n submitBtn.type = 'submit';\n submitBtn.className = 'fv-widget-submit';\n submitBtn.textContent = config.submitButtonText; // Safe - textContent\n form.appendChild(submitBtn);\n\n const errorDiv = document.createElement('div');\n errorDiv.className = 'fv-widget-error';\n errorDiv.id = 'fv-error-message';\n form.appendChild(errorDiv);\n\n form.addEventListener('submit', (e) => this.handleFormSubmit(e));\n this.modal.appendChild(form);\n\n // Branding\n if (config.showBranding) {\n const branding = document.createElement('div');\n branding.className = 'fv-widget-branding';\n\n const brandText = document.createTextNode('Powered by ');\n branding.appendChild(brandText);\n\n const link = document.createElement('a');\n link.href = 'https://feedvalue.com';\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n link.textContent = 'FeedValue';\n branding.appendChild(link);\n\n this.modal.appendChild(branding);\n }\n\n document.body.appendChild(this.modal);\n }\n\n /**\n * Handle form submission\n */\n private async handleFormSubmit(event: Event): Promise<void> {\n event.preventDefault();\n\n const textarea = document.getElementById('fv-feedback-content') as HTMLTextAreaElement;\n const submitBtn = this.modal?.querySelector('.fv-widget-submit') as HTMLButtonElement;\n const errorEl = document.getElementById('fv-error-message');\n\n if (!textarea?.value.trim()) {\n this.showError('Please enter your feedback');\n return;\n }\n\n try {\n submitBtn.disabled = true;\n submitBtn.textContent = 'Submitting...';\n if (errorEl) errorEl.style.display = 'none';\n\n await this.submit({ message: textarea.value.trim() });\n\n // Show success\n this.showSuccess();\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to submit';\n this.showError(message);\n } finally {\n submitBtn.disabled = false;\n submitBtn.textContent = this.widgetConfig?.config.submitButtonText ?? 'Submit';\n }\n }\n\n /**\n * Show error message (safe - uses textContent)\n */\n private showError(message: string): void {\n const errorEl = document.getElementById('fv-error-message');\n if (errorEl) {\n errorEl.textContent = message;\n errorEl.style.display = 'block';\n }\n }\n\n /**\n * Show success message using safe DOM methods\n */\n private showSuccess(): void {\n if (!this.modal || !this.widgetConfig) return;\n\n // Clear any existing auto-close timeout to prevent race conditions\n if (this.autoCloseTimeout) {\n clearTimeout(this.autoCloseTimeout);\n this.autoCloseTimeout = null;\n }\n\n // Clear modal\n this.modal.textContent = '';\n\n // Success container\n const successDiv = document.createElement('div');\n successDiv.style.cssText = 'text-align: center; padding: 40px 20px;';\n\n // Checkmark icon\n const iconDiv = document.createElement('div');\n iconDiv.style.cssText = 'font-size: 48px; margin-bottom: 16px;';\n iconDiv.textContent = '✓';\n successDiv.appendChild(iconDiv);\n\n // Thank you message\n const messageDiv = document.createElement('div');\n messageDiv.style.cssText = 'font-size: 16px; margin-bottom: 24px;';\n messageDiv.textContent = this.widgetConfig.config.thankYouMessage; // Safe\n successDiv.appendChild(messageDiv);\n\n // Close button\n const closeBtn = document.createElement('button');\n closeBtn.className = 'fv-widget-submit';\n closeBtn.textContent = 'Close';\n closeBtn.addEventListener('click', () => {\n this.close();\n this.resetForm();\n });\n successDiv.appendChild(closeBtn);\n\n this.modal.appendChild(successDiv);\n\n // Auto-close after delay (store reference for cleanup)\n this.autoCloseTimeout = setTimeout(() => {\n if (this.state.isOpen) {\n this.close();\n this.resetForm();\n }\n this.autoCloseTimeout = null;\n }, SUCCESS_AUTO_CLOSE_DELAY_MS);\n }\n\n /**\n * Reset form to initial state\n */\n private resetForm(): void {\n if (!this.modal) return;\n\n // Clear and rebuild modal\n this.modal.textContent = '';\n this.modal.remove();\n this.modal = null;\n\n // Re-render\n this.renderModal();\n }\n\n /**\n * Debug logging\n */\n private log(message: string, data?: unknown): void {\n if (this.config.debug) {\n console.log(`[FeedValue] ${message}`, data ?? '');\n }\n }\n}\n"]}