@od-oneapp/analytics 2026.2.1701 → 2026.2.2301-canary

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/{ai-YMnynb-t.mjs → ai-Co8hBoEj.mjs} +2 -2
  3. package/{ai-YMnynb-t.mjs.map → ai-Co8hBoEj.mjs.map} +1 -1
  4. package/{client-D339NFJS.mjs → client-B8gfgflr.mjs} +1 -1
  5. package/{client-D339NFJS.mjs.map → client-B8gfgflr.mjs.map} +1 -1
  6. package/{client-CeOLjbac.mjs → client-C35AzV71.mjs} +21 -6
  7. package/client-C35AzV71.mjs.map +1 -0
  8. package/{client-CcFTauAh.mjs → client-DDehaDSz.mjs} +1 -1
  9. package/{client-CcFTauAh.mjs.map → client-DDehaDSz.mjs.map} +1 -1
  10. package/{client-CTzJVFU5.mjs → client-DK8twEdp.mjs} +2 -2
  11. package/{client-CTzJVFU5.mjs.map → client-DK8twEdp.mjs.map} +1 -1
  12. package/client-next.d.mts +7 -7
  13. package/client-next.d.mts.map +1 -1
  14. package/client-next.mjs +1615 -31
  15. package/client-next.mjs.map +1 -1
  16. package/client.d.mts +9 -9
  17. package/client.mjs +8 -116
  18. package/client.mjs.map +1 -1
  19. package/{config-P6P5adJg.mjs → config-6Mwe7b2O.mjs} +1 -1
  20. package/{config-P6P5adJg.mjs.map → config-6Mwe7b2O.mjs.map} +1 -1
  21. package/{config-DPS6bSYo.d.mts → config-Ciu7O6n1.d.mts} +2 -2
  22. package/{config-DPS6bSYo.d.mts.map → config-Ciu7O6n1.d.mts.map} +1 -1
  23. package/{console-8bND3mMU.mjs → console-BpU88FNF.mjs} +2 -2
  24. package/console-BpU88FNF.mjs.map +1 -0
  25. package/core-DBLE5iTF.mjs +95 -0
  26. package/core-DBLE5iTF.mjs.map +1 -0
  27. package/{ecommerce-Cgu4wlux.mjs → ecommerce-DGG1FbiH.mjs} +2 -2
  28. package/{ecommerce-Cgu4wlux.mjs.map → ecommerce-DGG1FbiH.mjs.map} +1 -1
  29. package/{emitters-DldkVSPp.d.mts → emitters-BDSsleo_.d.mts} +2 -2
  30. package/{emitters-DldkVSPp.d.mts.map → emitters-BDSsleo_.d.mts.map} +1 -1
  31. package/{emitters-6-nKo8i-.mjs → emitters-BvEelkxS.mjs} +1 -1
  32. package/{emitters-6-nKo8i-.mjs.map → emitters-BvEelkxS.mjs.map} +1 -1
  33. package/{index-jPzXRn52.d.mts → index-BWhDEs8u.d.mts} +3 -3
  34. package/{index-jPzXRn52.d.mts.map → index-BWhDEs8u.d.mts.map} +1 -1
  35. package/{index-BkIWe--N.d.mts → index-Cp-N57Zb.d.mts} +2 -2
  36. package/{index-BkIWe--N.d.mts.map → index-Cp-N57Zb.d.mts.map} +1 -1
  37. package/{index-BfNWgfa5.d.mts → index-DTvdqV7H.d.mts} +14 -2
  38. package/{index-BfNWgfa5.d.mts.map → index-DTvdqV7H.d.mts.map} +1 -1
  39. package/{manager-DvRRjza6.d.mts → manager-OJpSKwqb.d.mts} +3 -2
  40. package/manager-OJpSKwqb.d.mts.map +1 -0
  41. package/module-DVAU7zKb.mjs +5850 -0
  42. package/module-DVAU7zKb.mjs.map +1 -0
  43. package/package.json +42 -37
  44. package/{posthog-bootstrap-DWxFrxlt.d.mts → posthog-bootstrap-Bu1BfhVv.d.mts} +3 -3
  45. package/{posthog-bootstrap-DWxFrxlt.d.mts.map → posthog-bootstrap-Bu1BfhVv.d.mts.map} +1 -1
  46. package/{posthog-bootstrap-CYfIy_WS.mjs → posthog-bootstrap-DkPdn-hA.mjs} +81 -46
  47. package/posthog-bootstrap-DkPdn-hA.mjs.map +1 -0
  48. package/providers-http-client.d.mts +1 -1
  49. package/providers-http-client.d.mts.map +1 -1
  50. package/providers-http-client.mjs +35 -7
  51. package/providers-http-client.mjs.map +1 -1
  52. package/providers-http-server.d.mts +1 -1
  53. package/providers-http-server.d.mts.map +1 -1
  54. package/providers-http-server.mjs +19 -3
  55. package/providers-http-server.mjs.map +1 -1
  56. package/providers-http.d.mts +9 -1
  57. package/providers-http.d.mts.map +1 -1
  58. package/server-edge.d.mts +3 -3
  59. package/server-edge.mjs +4 -4
  60. package/server-edge.mjs.map +1 -1
  61. package/server-next.d.mts +9 -9
  62. package/server-next.mjs +5 -5
  63. package/server.d.mts +9 -9
  64. package/server.mjs +5 -5
  65. package/{service-Duqnlppl.mjs → service-NuHnv30x.mjs} +51 -119
  66. package/service-NuHnv30x.mjs.map +1 -0
  67. package/shared.d.mts +4 -4
  68. package/shared.mjs +3 -3
  69. package/{types-CBvxUEaF.d.mts → types-DEcTnnFe.d.mts} +1 -1
  70. package/{types-CBvxUEaF.d.mts.map → types-DEcTnnFe.d.mts.map} +1 -1
  71. package/{types-BxBnNQ0V.d.mts → types-cMMfHIpi.d.mts} +1 -1
  72. package/{types-BxBnNQ0V.d.mts.map → types-cMMfHIpi.d.mts.map} +1 -1
  73. package/types.d.mts +3 -3
  74. package/{vercel-types-lwakUfoI.d.mts → vercel-types-oM7Sn385.d.mts} +1 -1
  75. package/{vercel-types-lwakUfoI.d.mts.map → vercel-types-oM7Sn385.d.mts.map} +1 -1
  76. package/client-CeOLjbac.mjs.map +0 -1
  77. package/console-8bND3mMU.mjs.map +0 -1
  78. package/manager-DvRRjza6.d.mts.map +0 -1
  79. package/posthog-bootstrap-CYfIy_WS.mjs.map +0 -1
  80. package/service-Duqnlppl.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"providers-http-server.mjs","names":[],"sources":["../src/providers/http/server.ts"],"sourcesContent":["/**\n * @fileoverview HTTP provider for server/Node.js environments\n *\n * Provides HTTP-based analytics event sending for server-side applications.\n * Sends events to a remote ingestion endpoint (e.g., oneapp-api/ingest).\n *\n * Features:\n * - Event batching for efficiency\n * - Automatic flush on interval or batch size\n * - Retry with exponential backoff\n * - Graceful shutdown with final flush\n *\n * @module @od-oneapp/analytics/providers/http/server\n */\n\nimport { logDebug, logError, logWarn } from '@repo/shared/logs';\n\nimport type { HttpProviderConfig, IngestionResponse, QueuedEvent } from './types';\nimport type {\n AnalyticsContext,\n AnalyticsProvider,\n GroupTraits,\n PageProperties,\n Properties,\n ProviderConfig,\n UserTraits,\n} from '../../shared/types/types';\n\n/** Default configuration values */\nconst DEFAULTS = {\n batchSize: 10,\n flushInterval: 5000,\n timeout: 10000,\n retries: 3,\n} as const;\n\n/** Base delay for exponential backoff in ms */\nconst BACKOFF_BASE_MS = 1000;\n\n/**\n * HTTP Analytics Provider for server environments.\n *\n * Sends analytics events to a remote endpoint via HTTP POST requests.\n * Events are batched and flushed periodically for efficiency.\n *\n * @example\n * ```typescript\n * const provider = new HttpServerProvider({\n * options: {\n * endpoint: 'https://api.oneapp.dev/v1/ingest',\n * apiKey: process.env.ANALYTICS_API_KEY,\n * },\n * });\n * await provider.initialize();\n * await provider.track('Button Clicked', { button: 'signup' });\n * await provider.flush(); // Send queued events\n * ```\n */\nexport class HttpServerProvider implements AnalyticsProvider {\n readonly name = 'http';\n\n private config: Required<\n Pick<HttpProviderConfig, 'batchSize' | 'flushInterval' | 'timeout' | 'retries'>\n > &\n HttpProviderConfig;\n private isInitialized = false;\n private queue: QueuedEvent[] = [];\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n private userId?: string;\n private anonymousId: string;\n private isFlushing = false;\n\n constructor(providerConfig: ProviderConfig) {\n const options = (providerConfig.options ?? {}) as unknown as HttpProviderConfig;\n\n if (!options.endpoint) {\n throw new Error('HttpProvider requires an endpoint URL');\n }\n\n this.config = {\n ...options,\n batchSize: options.batchSize ?? DEFAULTS.batchSize,\n flushInterval: options.flushInterval ?? DEFAULTS.flushInterval,\n timeout: options.timeout ?? DEFAULTS.timeout,\n retries: options.retries ?? DEFAULTS.retries,\n };\n\n this.userId = options.userId;\n this.anonymousId = options.anonymousId ?? this.generateAnonymousId();\n }\n\n async initialize(): Promise<void> {\n if (this.isInitialized) return;\n\n // Start auto-flush timer if interval > 0\n if (this.config.flushInterval > 0) {\n this.flushTimer = setInterval(() => {\n void this.flush();\n }, this.config.flushInterval);\n\n // Unref the timer so it doesn't prevent Node.js from exiting\n if (typeof this.flushTimer.unref === 'function') {\n this.flushTimer.unref();\n }\n }\n\n if (this.config.debug) {\n logDebug('HTTP Analytics Provider initialized', {\n provider: 'http',\n endpoint: this.config.endpoint,\n batchSize: this.config.batchSize,\n flushInterval: this.config.flushInterval,\n });\n }\n\n this.isInitialized = true;\n }\n\n async track(\n event: string,\n properties: Properties = {},\n _context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.isInitialized) {\n logWarn('HTTP provider not initialized', { provider: 'http', operation: 'track', event });\n return;\n }\n\n this.enqueue({\n type: 'track',\n event,\n properties,\n timestamp: new Date().toISOString(),\n userId: this.userId,\n anonymousId: this.anonymousId,\n });\n }\n\n async identify(\n userId: string,\n traits: UserTraits = {},\n _context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.isInitialized) {\n logWarn('HTTP provider not initialized', { provider: 'http', operation: 'identify', userId });\n return;\n }\n\n // Update stored user ID\n this.userId = userId;\n\n this.enqueue({\n type: 'identify',\n userId,\n traits,\n timestamp: new Date().toISOString(),\n anonymousId: this.anonymousId,\n });\n }\n\n async page(\n name?: string,\n properties: PageProperties = {},\n _context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.isInitialized) {\n logWarn('HTTP provider not initialized', { provider: 'http', operation: 'page', name });\n return;\n }\n\n this.enqueue({\n type: 'page',\n name,\n properties,\n timestamp: new Date().toISOString(),\n userId: this.userId,\n anonymousId: this.anonymousId,\n });\n }\n\n async group(\n groupId: string,\n traits: GroupTraits = {},\n _context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.isInitialized) {\n logWarn('HTTP provider not initialized', { provider: 'http', operation: 'group', groupId });\n return;\n }\n\n this.enqueue({\n type: 'group',\n groupId,\n traits,\n timestamp: new Date().toISOString(),\n userId: this.userId,\n anonymousId: this.anonymousId,\n });\n }\n\n async alias(userId: string, previousId: string, _context?: AnalyticsContext): Promise<void> {\n if (!this.isInitialized) {\n logWarn('HTTP provider not initialized', {\n provider: 'http',\n operation: 'alias',\n userId,\n previousId,\n });\n return;\n }\n\n this.enqueue({\n type: 'alias',\n userId,\n previousId,\n timestamp: new Date().toISOString(),\n anonymousId: this.anonymousId,\n });\n }\n\n /**\n * Flush all queued events to the remote endpoint.\n * Called automatically on interval or when batch size is reached.\n */\n async flush(): Promise<void> {\n if (this.queue.length === 0 || this.isFlushing) return;\n\n this.isFlushing = true;\n\n // Take all events from queue\n const events = [...this.queue];\n this.queue = [];\n\n try {\n await this.sendBatch(events);\n } catch (error) {\n // Re-queue events on failure (they'll be retried on next flush)\n this.queue.unshift(...events);\n logError('Failed to flush events, re-queued for retry', {\n provider: 'http',\n eventCount: events.length,\n error: error instanceof Error ? error.message : String(error),\n });\n } finally {\n this.isFlushing = false;\n }\n }\n\n /**\n * Shutdown the provider gracefully.\n * Flushes remaining events and stops the flush timer.\n */\n async shutdown(): Promise<void> {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n\n // Final flush\n await this.flush();\n this.isInitialized = false;\n }\n\n /**\n * Get the current queue length (for testing/monitoring).\n */\n getQueueLength(): number {\n return this.queue.length;\n }\n\n // ============================================================================\n // Private Methods\n // ============================================================================\n\n private enqueue(event: QueuedEvent): void {\n this.queue.push(event);\n\n if (this.config.debug) {\n logDebug('Event queued', {\n provider: 'http',\n type: event.type,\n queueLength: this.queue.length,\n });\n }\n\n // Flush if batch size reached\n if (this.queue.length >= this.config.batchSize) {\n void this.flush();\n }\n }\n\n private async sendBatch(events: QueuedEvent[]): Promise<void> {\n const payload = { batch: events };\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= this.config.retries; attempt++) {\n try {\n const response = await this.sendRequest(payload);\n\n if (response.success) {\n if (this.config.debug) {\n logDebug('Batch sent successfully', {\n provider: 'http',\n accepted: response.accepted,\n rejected: response.rejected,\n });\n }\n return;\n }\n\n // Request succeeded but ingestion failed\n logWarn('Batch partially rejected', {\n provider: 'http',\n accepted: response.accepted,\n rejected: response.rejected,\n error: response.error,\n });\n return;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n if (attempt < this.config.retries) {\n // Exponential backoff: 1s, 2s, 4s, ...\n const delay = BACKOFF_BASE_MS * Math.pow(2, attempt);\n\n if (this.config.debug) {\n logDebug('Retrying batch send', {\n provider: 'http',\n attempt: attempt + 1,\n maxRetries: this.config.retries,\n delayMs: delay,\n });\n }\n\n await this.sleep(delay);\n }\n }\n }\n\n // All retries exhausted\n throw lastError ?? new Error('Failed to send batch after retries');\n }\n\n private async sendRequest(payload: { batch: QueuedEvent[] }): Promise<IngestionResponse> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...this.config.headers,\n };\n\n if (this.config.apiKey) {\n headers['X-API-Key'] = this.config.apiKey;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n try {\n const response = await fetch(this.config.endpoint, {\n method: 'POST',\n headers,\n body: JSON.stringify(payload),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n // Handle rate limiting\n if (response.status === 429) {\n const retryAfter = response.headers.get('Retry-After');\n throw new Error(`Rate limited. Retry after ${retryAfter ?? 'unknown'} seconds`);\n }\n\n const errorBody = await response.text();\n throw new Error(`HTTP ${response.status}: ${errorBody}`);\n }\n\n return (await response.json()) as IngestionResponse;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private generateAnonymousId(): string {\n // Use crypto.randomUUID if available (Node 19+), otherwise fallback\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n\n // Fallback for older Node versions\n return `anon_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 9)}`;\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"providers-http-server.mjs","names":[],"sources":["../src/providers/http/server.ts"],"sourcesContent":["/**\n * @fileoverview HTTP provider for server/Node.js environments\n *\n * Provides HTTP-based analytics event sending for server-side applications.\n * Sends events to a remote ingestion endpoint (e.g., oneapp-api/ingest).\n *\n * Features:\n * - Event batching for efficiency\n * - Automatic flush on interval or batch size\n * - Retry with exponential backoff\n * - Graceful shutdown with final flush\n *\n * @module @od-oneapp/analytics/providers/http/server\n */\n\nimport { logDebug, logError, logWarn } from '@od-oneapp/shared/logs';\n\nimport type { HttpProviderConfig, IngestionResponse, QueuedEvent } from './types';\nimport type {\n AnalyticsContext,\n AnalyticsProvider,\n GroupTraits,\n PageProperties,\n Properties,\n ProviderConfig,\n UserTraits,\n} from '../../shared/types/types';\n\n/** Default configuration values */\nconst DEFAULTS = {\n batchSize: 10,\n flushInterval: 5000,\n timeout: 10000,\n retries: 3,\n maxQueueSize: 10000,\n} as const;\n\n/** Base delay for exponential backoff in ms */\nconst BACKOFF_BASE_MS = 1000;\n\n/**\n * HTTP Analytics Provider for server environments.\n *\n * Sends analytics events to a remote endpoint via HTTP POST requests.\n * Events are batched and flushed periodically for efficiency.\n *\n * @example\n * ```typescript\n * const provider = new HttpServerProvider({\n * options: {\n * endpoint: 'https://api.oneapp.dev/v1/ingest',\n * apiKey: process.env.ANALYTICS_API_KEY,\n * },\n * });\n * await provider.initialize();\n * await provider.track('Button Clicked', { button: 'signup' });\n * await provider.flush(); // Send queued events\n * ```\n */\nexport class HttpServerProvider implements AnalyticsProvider {\n readonly name = 'http';\n\n private config: Required<\n Pick<\n HttpProviderConfig,\n 'batchSize' | 'flushInterval' | 'timeout' | 'retries' | 'maxQueueSize'\n >\n > &\n HttpProviderConfig;\n private isInitialized = false;\n private queue: QueuedEvent[] = [];\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n private userId?: string;\n private anonymousId: string;\n private isFlushing = false;\n\n constructor(providerConfig: ProviderConfig) {\n const options = (providerConfig.options ?? {}) as unknown as HttpProviderConfig;\n\n if (!options.endpoint) {\n throw new Error('HttpProvider requires an endpoint URL');\n }\n\n try {\n const parsed = new URL(options.endpoint);\n if (parsed.protocol !== 'https:') {\n throw new Error('HttpProvider endpoint must use HTTPS');\n }\n } catch {\n throw new Error('HttpProvider endpoint must be a valid HTTPS URL');\n }\n\n const resolvedQueueSize = options.maxQueueSize ?? DEFAULTS.maxQueueSize;\n if (!Number.isInteger(resolvedQueueSize) || resolvedQueueSize <= 0) {\n throw new Error('HttpProvider maxQueueSize must be a positive integer');\n }\n\n this.config = {\n ...options,\n batchSize: options.batchSize ?? DEFAULTS.batchSize,\n flushInterval: options.flushInterval ?? DEFAULTS.flushInterval,\n timeout: options.timeout ?? DEFAULTS.timeout,\n retries: options.retries ?? DEFAULTS.retries,\n maxQueueSize: resolvedQueueSize,\n };\n\n this.userId = options.userId;\n this.anonymousId = options.anonymousId ?? this.generateAnonymousId();\n }\n\n async initialize(): Promise<void> {\n if (this.isInitialized) return;\n\n // Start auto-flush timer if interval > 0\n if (this.config.flushInterval > 0) {\n this.flushTimer = setInterval(() => {\n void this.flush();\n }, this.config.flushInterval);\n\n // Unref the timer so it doesn't prevent Node.js from exiting\n if (typeof this.flushTimer.unref === 'function') {\n this.flushTimer.unref();\n }\n }\n\n if (this.config.debug) {\n logDebug('HTTP Analytics Provider initialized', {\n provider: 'http',\n endpoint: this.config.endpoint,\n batchSize: this.config.batchSize,\n flushInterval: this.config.flushInterval,\n });\n }\n\n this.isInitialized = true;\n }\n\n async track(\n event: string,\n properties: Properties = {},\n _context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.isInitialized) {\n logWarn('HTTP provider not initialized', { provider: 'http', operation: 'track', event });\n return;\n }\n\n this.enqueue({\n type: 'track',\n event,\n properties,\n timestamp: new Date().toISOString(),\n userId: this.userId,\n anonymousId: this.anonymousId,\n });\n }\n\n async identify(\n userId: string,\n traits: UserTraits = {},\n _context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.isInitialized) {\n logWarn('HTTP provider not initialized', { provider: 'http', operation: 'identify', userId });\n return;\n }\n\n // Update stored user ID\n this.userId = userId;\n\n this.enqueue({\n type: 'identify',\n userId,\n traits,\n timestamp: new Date().toISOString(),\n anonymousId: this.anonymousId,\n });\n }\n\n async page(\n name?: string,\n properties: PageProperties = {},\n _context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.isInitialized) {\n logWarn('HTTP provider not initialized', { provider: 'http', operation: 'page', name });\n return;\n }\n\n this.enqueue({\n type: 'page',\n name,\n properties,\n timestamp: new Date().toISOString(),\n userId: this.userId,\n anonymousId: this.anonymousId,\n });\n }\n\n async group(\n groupId: string,\n traits: GroupTraits = {},\n _context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.isInitialized) {\n logWarn('HTTP provider not initialized', { provider: 'http', operation: 'group', groupId });\n return;\n }\n\n this.enqueue({\n type: 'group',\n groupId,\n traits,\n timestamp: new Date().toISOString(),\n userId: this.userId,\n anonymousId: this.anonymousId,\n });\n }\n\n async alias(userId: string, previousId: string, _context?: AnalyticsContext): Promise<void> {\n if (!this.isInitialized) {\n logWarn('HTTP provider not initialized', {\n provider: 'http',\n operation: 'alias',\n userId,\n previousId,\n });\n return;\n }\n\n this.enqueue({\n type: 'alias',\n userId,\n previousId,\n timestamp: new Date().toISOString(),\n anonymousId: this.anonymousId,\n });\n }\n\n /**\n * Flush all queued events to the remote endpoint.\n * Called automatically on interval or when batch size is reached.\n */\n async flush(): Promise<void> {\n if (this.queue.length === 0 || this.isFlushing) return;\n\n this.isFlushing = true;\n\n // Take all events from queue\n const events = [...this.queue];\n this.queue = [];\n\n try {\n await this.sendBatch(events);\n } catch (error) {\n // Re-queue events on failure (they'll be retried on next flush)\n this.queue.unshift(...events);\n logError('Failed to flush events, re-queued for retry', {\n provider: 'http',\n eventCount: events.length,\n error: error instanceof Error ? error.message : String(error),\n });\n } finally {\n this.isFlushing = false;\n }\n }\n\n /**\n * Shutdown the provider gracefully.\n * Flushes remaining events and stops the flush timer.\n */\n async shutdown(): Promise<void> {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n\n // Final flush\n await this.flush();\n this.isInitialized = false;\n }\n\n /**\n * Get the current queue length (for testing/monitoring).\n */\n getQueueLength(): number {\n return this.queue.length;\n }\n\n // ============================================================================\n // Private Methods\n // ============================================================================\n\n private enqueue(event: QueuedEvent): void {\n if (this.queue.length >= this.config.maxQueueSize) {\n this.queue.shift();\n logWarn('Http provider queue full. Dropping oldest event to maintain bounded memory.', {\n provider: 'http',\n queueSize: this.config.maxQueueSize,\n });\n }\n\n this.queue.push(event);\n\n if (this.config.debug) {\n logDebug('Event queued', {\n provider: 'http',\n type: event.type,\n queueLength: this.queue.length,\n });\n }\n\n // Flush if batch size reached\n if (this.queue.length >= this.config.batchSize) {\n void this.flush();\n }\n }\n\n private async sendBatch(events: QueuedEvent[]): Promise<void> {\n const payload = { batch: events };\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= this.config.retries; attempt++) {\n try {\n const response = await this.sendRequest(payload);\n\n if (response.success) {\n if (this.config.debug) {\n logDebug('Batch sent successfully', {\n provider: 'http',\n accepted: response.accepted,\n rejected: response.rejected,\n });\n }\n return;\n }\n\n // Request succeeded but ingestion failed\n logWarn('Batch partially rejected', {\n provider: 'http',\n accepted: response.accepted,\n rejected: response.rejected,\n error: response.error,\n });\n return;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n if (attempt < this.config.retries) {\n // Exponential backoff: 1s, 2s, 4s, ...\n const delay = BACKOFF_BASE_MS * Math.pow(2, attempt);\n\n if (this.config.debug) {\n logDebug('Retrying batch send', {\n provider: 'http',\n attempt: attempt + 1,\n maxRetries: this.config.retries,\n delayMs: delay,\n });\n }\n\n await this.sleep(delay);\n }\n }\n }\n\n // All retries exhausted\n throw lastError ?? new Error('Failed to send batch after retries');\n }\n\n private async sendRequest(payload: { batch: QueuedEvent[] }): Promise<IngestionResponse> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...this.config.headers,\n };\n\n if (this.config.apiKey) {\n headers['X-API-Key'] = this.config.apiKey;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n try {\n const response = await fetch(this.config.endpoint, {\n method: 'POST',\n headers,\n body: JSON.stringify(payload),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n // Handle rate limiting\n if (response.status === 429) {\n const retryAfter = response.headers.get('Retry-After');\n throw new Error(`Rate limited. Retry after ${retryAfter ?? 'unknown'} seconds`);\n }\n\n const errorBody = await response.text();\n throw new Error(`HTTP ${response.status}: ${errorBody}`);\n }\n\n return (await response.json()) as IngestionResponse;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private generateAnonymousId(): string {\n // Use crypto.randomUUID if available (Node 19+), otherwise fallback\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n\n // Fallback for older Node versions\n return `anon_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 9)}`;\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n"],"mappings":"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"}
@@ -9,6 +9,7 @@ interface HttpProviderConfig {
9
9
  flushInterval?: number;
10
10
  timeout?: number;
11
11
  retries?: number;
12
+ maxQueueSize?: number;
12
13
  headers?: Record<string, string>;
13
14
  debug?: boolean;
14
15
  userId?: string;
@@ -27,6 +28,12 @@ interface QueuedEvent {
27
28
  groupId?: string;
28
29
  previousId?: string;
29
30
  }
31
+ interface IngestionDispatchResult {
32
+ scheduled: number;
33
+ attempted: number;
34
+ failed: number;
35
+ status: 'skipped' | 'pending' | 'completed' | 'completed_with_failures';
36
+ }
30
37
  interface IngestionResponse {
31
38
  success: boolean;
32
39
  accepted?: number;
@@ -37,10 +44,11 @@ interface IngestionResponse {
37
44
  status: 'accepted' | 'rejected';
38
45
  error?: string;
39
46
  }>;
47
+ dispatch?: IngestionDispatchResult;
40
48
  receivedAt?: string;
41
49
  error?: string;
42
50
  code?: string;
43
51
  }
44
52
  //#endregion
45
- export { HttpClientProvider, HttpServerProvider as HttpProvider, HttpServerProvider, type HttpProviderConfig, type IngestionResponse, type QueuedEvent };
53
+ export { HttpClientProvider, HttpServerProvider as HttpProvider, HttpServerProvider, type HttpProviderConfig, type IngestionDispatchResult, type IngestionResponse, type QueuedEvent };
46
54
  //# sourceMappingURL=providers-http.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"providers-http.d.mts","names":[],"sources":["../src/providers/http/types.ts"],"mappings":";;;;UAsBiB,kBAAA;EAOf,QAAA;EAOA,MAAA;EAQA,SAAA;EAQA,aAAA;EAOA,OAAA;EAQA,OAAA;EAMA,OAAA,GAAU,MAAA;EAOV,KAAA;EAMA,MAAA;EAMA,WAAA;AAAA;AAAA,UAOe,WAAA;EACf,IAAA;EACA,SAAA;EACA,MAAA;EACA,WAAA;EAEA,KAAA;EACA,UAAA,GAAa,MAAA;EAEb,MAAA,GAAS,MAAA;EAET,IAAA;EACA,QAAA;EAEA,OAAA;EAEA,UAAA;AAAA;AAAA,UAMe,iBAAA;EACf,OAAA;EACA,QAAA;EACA,QAAA;EACA,OAAA,GAAU,KAAA;IACR,EAAA;IACA,IAAA;IACA,MAAA;IACA,KAAA;EAAA;EAEF,UAAA;EACA,KAAA;EACA,IAAA;AAAA"}
1
+ {"version":3,"file":"providers-http.d.mts","names":[],"sources":["../src/providers/http/types.ts"],"mappings":";;;;UAsBiB,kBAAA;EAOf,QAAA;EAOA,MAAA;EAQA,SAAA;EAQA,aAAA;EAOA,OAAA;EAQA,OAAA;EAOA,YAAA;EAMA,OAAA,GAAU,MAAA;EAOV,KAAA;EAMA,MAAA;EAMA,WAAA;AAAA;AAAA,UAOe,WAAA;EACf,IAAA;EACA,SAAA;EACA,MAAA;EACA,WAAA;EAEA,KAAA;EACA,UAAA,GAAa,MAAA;EAEb,MAAA,GAAS,MAAA;EAET,IAAA;EACA,QAAA;EAEA,OAAA;EAEA,UAAA;AAAA;AAAA,UAMe,uBAAA;EAEf,SAAA;EAGA,SAAA;EAGA,MAAA;EAGA,MAAA;AAAA;AAAA,UAMe,iBAAA;EACf,OAAA;EACA,QAAA;EACA,QAAA;EACA,OAAA,GAAU,KAAA;IACR,EAAA;IACA,IAAA;IACA,MAAA;IACA,KAAA;EAAA;EAEF,QAAA,GAAW,uBAAA;EACX,UAAA;EACA,KAAA;EACA,IAAA;AAAA"}
package/server-edge.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import { A as GroupTraits, C as EmitterPagePayload, D as EmitterTrackPayload, E as EmitterScreenPayload, F as UserTraits, M as Properties, N as PropertyObject, O as EmitterUserTraits, P as PropertyValue, S as EmitterOptions, T as EmitterProduct, _ as EmitterEventProperties, a as EcommerceEventSpec, b as EmitterIdentifyPayload, c as ProviderConfig, d as TrackingOptions, f as AnalyticsEmitter, g as EmitterContext, h as EmitterConfig, i as AnalyticsProvider, j as PageProperties, k as IntegrationConfig, l as ProviderFactory, m as EmitterBasePayload, n as AnalyticsContext, o as ErrorContext, p as EmitterAliasPayload, r as AnalyticsManager, s as PostHogBootstrap, t as AnalyticsConfig, u as ProviderRegistry, v as EmitterGroupPayload, w as EmitterPayload, x as EmitterIntegrations, y as EmitterGroupTraits } from "./types-BxBnNQ0V.mjs";
2
- import { i as page, n as group, o as track, r as identify, t as alias } from "./emitters-DldkVSPp.mjs";
3
- import { a as createEmitterProcessor, r as getAnalyticsConfig } from "./config-DPS6bSYo.mjs";
1
+ import { A as GroupTraits, C as EmitterPagePayload, D as EmitterTrackPayload, E as EmitterScreenPayload, F as UserTraits, M as Properties, N as PropertyObject, O as EmitterUserTraits, P as PropertyValue, S as EmitterOptions, T as EmitterProduct, _ as EmitterEventProperties, a as EcommerceEventSpec, b as EmitterIdentifyPayload, c as ProviderConfig, d as TrackingOptions, f as AnalyticsEmitter, g as EmitterContext, h as EmitterConfig, i as AnalyticsProvider, j as PageProperties, k as IntegrationConfig, l as ProviderFactory, m as EmitterBasePayload, n as AnalyticsContext, o as ErrorContext, p as EmitterAliasPayload, r as AnalyticsManager, s as PostHogBootstrap, t as AnalyticsConfig, u as ProviderRegistry, v as EmitterGroupPayload, w as EmitterPayload, x as EmitterIntegrations, y as EmitterGroupTraits } from "./types-cMMfHIpi.mjs";
2
+ import { i as page, n as group, o as track, r as identify, t as alias } from "./emitters-BDSsleo_.mjs";
3
+ import { a as createEmitterProcessor, r as getAnalyticsConfig } from "./config-Ciu7O6n1.mjs";
4
4
 
5
5
  //#region src/server-edge.d.ts
6
6
  declare function createServerAnalytics(config?: AnalyticsConfig): Promise<AnalyticsManager>;
package/server-edge.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { i as page, n as group, o as track, r as identify, t as alias } from "./emitters-6-nKo8i-.mjs";
2
- import { a as createEmitterProcessor, r as getAnalyticsConfig } from "./config-P6P5adJg.mjs";
3
- import { logWarn } from "@od-oneapp/shared/logger";
1
+ import { i as logWarn } from "./core-DBLE5iTF.mjs";
2
+ import { i as page, n as group, o as track, r as identify, t as alias } from "./emitters-BvEelkxS.mjs";
3
+ import { a as createEmitterProcessor, r as getAnalyticsConfig } from "./config-6Mwe7b2O.mjs";
4
4
  import { createEnv } from "@t3-oss/env-core";
5
5
  import { z } from "zod/v4";
6
6
 
@@ -140,7 +140,7 @@ async function createServerAnalytics(config = defaultConfig) {
140
140
  const providers = [];
141
141
  let context = {};
142
142
  if (config.providers.console) {
143
- const { ConsoleProvider } = await import("./console-8bND3mMU.mjs").then((n) => n.n);
143
+ const { ConsoleProvider } = await import("./console-BpU88FNF.mjs").then((n) => n.n);
144
144
  const consoleProvider = new ConsoleProvider(config.providers.console);
145
145
  await consoleProvider.initialize();
146
146
  providers.push(consoleProvider);
@@ -1 +1 @@
1
- {"version":3,"file":"server-edge.mjs","names":[],"sources":["../env.ts","../src/server-edge.ts"],"sourcesContent":["/**\n * @fileoverview Environment variable configuration for analytics package\n * Environment variable configuration for analytics package\n */\n\nimport { logWarn } from '@repo/shared/logger';\nimport { createEnv } from '@t3-oss/env-core';\nimport { z } from 'zod/v4';\n\nexport const env = createEnv({\n server: {\n // PostHog server configuration for feature flags and analytics\n POSTHOG_HOST: z.string().url().default('https://app.posthog.com'),\n POSTHOG_KEY: z.string().optional(),\n POSTHOG_API_KEY: z.string().optional(), // Additional key used in source code\n POSTHOG_PERSONAL_API_KEY: z.string().optional(),\n POSTHOG_PROJECT_ID: z.string().optional(),\n\n // Segment server configuration\n SEGMENT_WRITE_KEY: z.string().optional(),\n\n // Analytics logging configuration\n ANALYTICS_LOG_PROVIDER: z.enum(['console', 'sentry']).default('console'),\n\n // Environment detection\n NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),\n APP_ENV: z.enum(['development', 'staging', 'production']).optional(),\n NEXT_RUNTIME: z.enum(['nodejs', 'edge']).optional(),\n },\n clientPrefix: 'NEXT_PUBLIC_',\n client: {\n // PostHog client configuration\n NEXT_PUBLIC_POSTHOG_HOST: z.string().url().default('https://app.posthog.com'),\n NEXT_PUBLIC_POSTHOG_KEY: z.string().optional(),\n\n // Segment client configuration\n NEXT_PUBLIC_SEGMENT_WRITE_KEY: z.string().optional(),\n\n // Vercel Analytics\n NEXT_PUBLIC_VERCEL_ANALYTICS_ID: z.string().optional(),\n\n // App environment for client\n NEXT_PUBLIC_APP_ENV: z.enum(['development', 'staging', 'production']).optional(),\n NEXT_PUBLIC_NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),\n },\n runtimeEnv: process.env,\n emptyStringAsUndefined: true,\n onInvalidAccess: (variable: string) => {\n throw new Error(\n `❌ Attempted to access a server-side environment variable on the client: ${variable}`,\n );\n },\n onValidationError: (error: unknown) => {\n logWarn('Analytics environment validation failed:', { error: String(error) });\n // Don't throw in packages - use fallbacks for resilience\n return undefined as never;\n },\n});\n\n/**\n * Returns a resilient env object for non-Next.js runtimes (CLI scripts, tests, workers).\n *\n * Codex/OpenAI models can rely on this helper when generating examples because it always\n * returns a fully populated object, using process.env fallbacks when the strongly typed\n * `createEnv` instance is unavailable.\n */\nexport function safeEnv() {\n // env is always defined, but may have validation errors\n // Return env directly, fallback only if access throws\n try {\n return env;\n } catch {\n // Return fallback if env access fails\n return {\n // Server variables\n POSTHOG_HOST: process.env.POSTHOG_HOST ?? 'https://app.posthog.com',\n POSTHOG_KEY: process.env.POSTHOG_KEY ?? '',\n POSTHOG_API_KEY: process.env.POSTHOG_API_KEY ?? '',\n POSTHOG_PERSONAL_API_KEY: process.env.POSTHOG_PERSONAL_API_KEY ?? '',\n POSTHOG_PROJECT_ID: process.env.POSTHOG_PROJECT_ID ?? '',\n SEGMENT_WRITE_KEY: process.env.SEGMENT_WRITE_KEY ?? '',\n ANALYTICS_LOG_PROVIDER:\n (process.env.ANALYTICS_LOG_PROVIDER as 'console' | 'sentry' | undefined) ?? 'console',\n NODE_ENV: (process.env.NODE_ENV as string | undefined) ?? 'development',\n APP_ENV: process.env.APP_ENV as 'development' | 'staging' | 'production' | undefined,\n NEXT_RUNTIME: process.env.NEXT_RUNTIME as 'nodejs' | 'edge' | undefined,\n\n // Client variables\n NEXT_PUBLIC_POSTHOG_HOST: process.env.NEXT_PUBLIC_POSTHOG_HOST ?? 'https://app.posthog.com',\n NEXT_PUBLIC_POSTHOG_KEY: process.env.NEXT_PUBLIC_POSTHOG_KEY ?? '',\n NEXT_PUBLIC_SEGMENT_WRITE_KEY: process.env.NEXT_PUBLIC_SEGMENT_WRITE_KEY ?? '',\n NEXT_PUBLIC_VERCEL_ANALYTICS_ID: process.env.NEXT_PUBLIC_VERCEL_ANALYTICS_ID ?? '',\n NEXT_PUBLIC_APP_ENV: process.env.NEXT_PUBLIC_APP_ENV as\n | 'development'\n | 'staging'\n | 'production'\n | undefined,\n NEXT_PUBLIC_NODE_ENV:\n (process.env.NEXT_PUBLIC_NODE_ENV as 'development' | 'test' | 'production' | undefined) ??\n 'development',\n };\n }\n}\n\n// Export type for better DX\nexport type Env = typeof env;\n","/**\n * @fileoverview Edge Runtime Analytics Module\n *\n * Provides edge-compatible analytics for Next.js middleware and edge API routes.\n * Uses Web APIs and HTTP-based implementations compatible with edge runtime.\n *\n * **Supported Features**:\n * - Basic event tracking (track, identify, page, group, alias)\n * - Console provider (uses console API)\n * - PostHog provider (HTTP-based, no SDK dependency)\n * - Emitter pattern support via `emit()`\n *\n * **Limitations (Edge Runtime Constraints)**:\n * - No Node.js APIs (fs, crypto, etc.)\n * - No native modules or SDK dependencies\n * - No event deduplication (no LRU cache)\n * - No rate limiting (100 req/s limit not enforced)\n * - No batch processing optimization\n * - No performance metrics tracking\n * - No feature flags (PostHog flags require server SDK)\n * - Context is per-request only (not persisted)\n *\n * **For full analytics features**, use `@od-oneapp/analytics/server` in Node.js environments.\n *\n * **Usage**: Import from `@od-oneapp/analytics/server/edge` for Next.js middleware and edge API routes.\n *\n * @example\n * ```typescript\n * // In Next.js middleware\n * import { createServerAnalytics, track } from '@od-oneapp/analytics/server/edge';\n *\n * export async function middleware(request: NextRequest) {\n * const analytics = await createServerAnalytics({\n * providers: {\n * posthog: { apiKey: process.env.POSTHOG_API_KEY }\n * }\n * });\n *\n * await analytics.emit(track('Middleware Hit', { path: request.nextUrl.pathname }));\n * return NextResponse.next();\n * }\n * ```\n *\n * @module @od-oneapp/analytics/server/edge\n */\n\nimport { env } from '../env';\n\nimport type {\n EmitterAliasPayload,\n EmitterGroupPayload,\n EmitterIdentifyPayload,\n EmitterPagePayload,\n EmitterPayload,\n EmitterTrackPayload,\n} from './shared/emitters/emitter-types';\nimport type {\n AnalyticsConfig,\n AnalyticsContext,\n AnalyticsManager,\n AnalyticsProvider,\n GroupTraits,\n PageProperties,\n Properties,\n UserTraits,\n} from './shared/types/types';\n\n// Type aliases for clarity\ntype IdentifyTraits = UserTraits;\ntype TrackProperties = Properties;\n\n// Re-export types for consumers\nexport type * from './shared/emitters/emitter-types';\nexport type * from './shared/types/types';\n\n// Re-export emitter utilities\nexport { createEmitterProcessor } from './shared/utils/emitter-adapter';\n\n// Re-export core emitters for edge usage\nexport { alias, group, identify, page, track } from './shared/emitters';\n\nconst defaultConfig: AnalyticsConfig = { providers: {} };\n\n/**\n * Creates an edge-compatible analytics manager.\n *\n * This is a simplified implementation optimized for edge runtime constraints.\n * It provides basic analytics functionality without Node.js-specific features.\n *\n * **Supported Providers**:\n * - Console (always available)\n * - PostHog (HTTP-based, requires API key)\n *\n * **Not Supported in Edge**:\n * - Segment SDK (requires Node.js)\n * - Vercel Analytics SDK (requires Node.js)\n * - Rate limiting\n * - Event deduplication\n * - Batch processing optimization\n *\n * @param {AnalyticsConfig} [config] - Analytics configuration with provider settings\n * @returns {Promise<AnalyticsManager>} Promise resolving to AnalyticsManager instance\n *\n * @example\n * ```typescript\n * const analytics = await createServerAnalytics({\n * providers: {\n * posthog: { apiKey: process.env.POSTHOG_API_KEY }\n * }\n * });\n *\n * await analytics.track('Event Name', { property: 'value' });\n * ```\n */\nexport async function createServerAnalytics(\n config: AnalyticsConfig = defaultConfig,\n): Promise<AnalyticsManager> {\n const providers: AnalyticsProvider[] = [];\n let context: AnalyticsContext = {};\n\n // Initialize Console provider (edge-compatible)\n if (config.providers.console) {\n const { ConsoleProvider } = await import('./providers/console');\n const consoleProvider = new ConsoleProvider(config.providers.console);\n await consoleProvider.initialize();\n providers.push(consoleProvider);\n }\n\n // Initialize PostHog HTTP provider (edge-compatible)\n if (config.providers.posthog?.apiKey) {\n const posthogProvider = createPostHogEdgeProvider(config);\n providers.push(posthogProvider);\n }\n\n // Process emitter payload by type\n const processPayload = async (payload: EmitterPayload): Promise<void> => {\n switch (payload.type) {\n case 'track': {\n const p = payload;\n await Promise.allSettled(\n providers.map(provider =>\n provider.track(p.event, p.properties ?? {}, { ...context, ...p.context }),\n ),\n );\n break;\n }\n case 'identify': {\n const p = payload;\n await Promise.allSettled(\n providers.map(provider =>\n provider.identify?.(p.userId, p.traits ?? {}, { ...context, ...p.context }),\n ),\n );\n break;\n }\n case 'page': {\n const p = payload;\n await Promise.allSettled(\n providers.map(provider =>\n provider.page?.(p.name ?? '', p.properties ?? {}, { ...context, ...p.context }),\n ),\n );\n break;\n }\n case 'screen': {\n const p = payload;\n await Promise.allSettled(\n providers.map(provider =>\n provider.screen?.(p.name ?? '', p.properties ?? {}, { ...context, ...p.context }),\n ),\n );\n break;\n }\n case 'group': {\n const p = payload;\n await Promise.allSettled(\n providers.map(provider =>\n provider.group?.(p.groupId, p.traits ?? {}, { ...context, ...p.context }),\n ),\n );\n break;\n }\n case 'alias': {\n const p = payload;\n await Promise.allSettled(\n providers.map(provider =>\n provider.alias?.(p.userId, p.previousId, { ...context, ...p.context }),\n ),\n );\n break;\n }\n }\n };\n\n // Create emitter function at outer scope (within createServerAnalytics)\n function createEmitterFunction(payload: EmitterPayload): Promise<void> {\n return processPayload(payload);\n }\n\n // Return edge-compatible analytics manager\n const manager: AnalyticsManager = {\n getContext: () => ({ ...context }),\n\n initialize: async () => {\n // Providers already initialized above\n },\n\n setContext: (newContext: AnalyticsContext) => {\n context = { ...context, ...newContext };\n },\n\n createEmitter: () => createEmitterFunction,\n\n emit: async (payload: EmitterPayload) => {\n await processPayload(payload);\n },\n\n emitBatch: async (payloads: EmitterPayload[]) => {\n // Process sequentially in edge (no concurrency optimization)\n for (const payload of payloads) {\n await processPayload(payload);\n }\n },\n\n // Overloaded track method\n track: async (eventOrPayload: string | EmitterTrackPayload, properties?: Properties) => {\n if (typeof eventOrPayload === 'object') {\n await processPayload(eventOrPayload);\n } else if (typeof eventOrPayload === 'string') {\n await Promise.allSettled(\n providers.map(p => p.track(eventOrPayload, properties ?? {}, context)),\n );\n }\n },\n\n // Overloaded identify method\n identify: async (userIdOrPayload: string | EmitterIdentifyPayload, traits?: IdentifyTraits) => {\n if (typeof userIdOrPayload === 'object') {\n await processPayload(userIdOrPayload);\n } else if (typeof userIdOrPayload === 'string') {\n await Promise.allSettled(\n providers.map(p => p.identify?.(userIdOrPayload, traits ?? {}, context)),\n );\n }\n },\n\n // Overloaded page method\n page: async (nameOrPayload?: string | EmitterPagePayload, properties?: PageProperties) => {\n if (typeof nameOrPayload === 'object') {\n await processPayload(nameOrPayload);\n } else {\n const pageName = typeof nameOrPayload === 'string' ? nameOrPayload : '';\n await Promise.allSettled(providers.map(p => p.page?.(pageName, properties ?? {}, context)));\n }\n },\n\n // Overloaded group method\n group: async (groupIdOrPayload: string | EmitterGroupPayload, traits?: GroupTraits) => {\n if (typeof groupIdOrPayload === 'object') {\n await processPayload(groupIdOrPayload);\n } else if (typeof groupIdOrPayload === 'string') {\n await Promise.allSettled(\n providers.map(p => p.group?.(groupIdOrPayload, traits ?? {}, context)),\n );\n }\n },\n\n // Overloaded alias method\n alias: async (userIdOrPayload: string | EmitterAliasPayload, previousId?: string) => {\n if (typeof userIdOrPayload === 'object') {\n await processPayload(userIdOrPayload);\n } else if (typeof userIdOrPayload === 'string' && previousId) {\n await Promise.allSettled(\n providers.map(p => p.alias?.(userIdOrPayload, previousId, context)),\n );\n }\n },\n\n getActiveProviders: () => providers.map(p => p.name),\n getProvider: (name: string) => providers.find(p => p.name === name),\n\n reset: () => {\n context = {};\n },\n\n shutdown: async () => {\n // In edge, we don't have complex shutdown logic usually\n providers.length = 0;\n },\n\n // Deprecated methods (no-ops with warning)\n processEmitterPayload: async (payload: EmitterPayload) => {\n await processPayload(payload);\n },\n trackEcommerce: async () => {\n if (config.debug && config.onInfo) {\n config.onInfo('trackEcommerce is deprecated, use emit(ecommerce.EVENT_NAME(...))');\n }\n },\n };\n\n return manager;\n}\n\n/**\n * Creates a PostHog provider that uses HTTP API (edge-compatible).\n *\n * This provider uses PostHog's HTTP capture API instead of the Node.js SDK,\n * making it compatible with edge runtime constraints.\n *\n * **Features**:\n * - HTTP-based event tracking\n * - 5-second timeout per request\n * - Error handling via config callbacks\n * - Supports all standard analytics methods (track, identify, page, group, alias)\n *\n * @param {AnalyticsConfig} config - Analytics configuration\n * @returns {AnalyticsProvider} PostHog provider instance\n *\n * @throws {Error} If PostHog API key is not provided\n *\n * @internal\n */\nfunction createPostHogEdgeProvider(config: AnalyticsConfig): AnalyticsProvider {\n const posthogConfig = config.providers?.posthog;\n if (!posthogConfig?.apiKey) {\n throw new Error('PostHog apiKey is required');\n }\n\n const posthogHost =\n (posthogConfig.options as { api_host?: string } | undefined)?.api_host ??\n env.POSTHOG_HOST ??\n 'https://app.posthog.com';\n const posthogUrl = `${posthogHost}/capture/`;\n const { apiKey } = posthogConfig;\n const timeout = 5000;\n\n // Safe fetch with timeout and error handling\n const safeFetch = async (body: Record<string, unknown>, method: string): Promise<void> => {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(posthogUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n if (!response.ok && config.onError) {\n config.onError(\n new Error(`PostHog ${method} failed: ${response.status} ${response.statusText}`),\n { provider: 'posthog-edge', method, status: response.status },\n );\n }\n } catch (error) {\n if (config.onError) {\n config.onError(error instanceof Error ? error : new Error('Unknown error'), {\n provider: 'posthog-edge',\n method,\n });\n }\n } finally {\n clearTimeout(timeoutId);\n }\n };\n\n return {\n name: 'posthog-edge',\n\n async initialize() {\n // No initialization needed for HTTP-based PostHog\n },\n\n async track(event: string, properties?: TrackProperties, context?: AnalyticsContext) {\n const distinctId = context?.userId ?? properties?.distinctId ?? 'anonymous';\n await safeFetch(\n {\n api_key: apiKey,\n event,\n distinct_id: distinctId,\n properties: { ...properties, ...context },\n timestamp: new Date().toISOString(),\n },\n 'track',\n );\n },\n\n async identify(userId: string, traits?: IdentifyTraits) {\n await safeFetch(\n {\n api_key: apiKey,\n event: '$identify',\n distinct_id: userId,\n properties: { $set: traits },\n },\n 'identify',\n );\n },\n\n async page(name?: string, properties?: PageProperties, context?: AnalyticsContext) {\n const distinctId = context?.userId ?? 'anonymous';\n await safeFetch(\n {\n api_key: apiKey,\n event: '$pageview',\n distinct_id: distinctId,\n properties: { $current_url: properties?.url, $title: name, ...properties },\n },\n 'page',\n );\n },\n\n async group(groupId: string, traits?: GroupTraits, context?: AnalyticsContext) {\n const distinctId = context?.userId ?? 'anonymous';\n await safeFetch(\n {\n api_key: apiKey,\n event: '$groupidentify',\n distinct_id: distinctId,\n properties: { $group_type: 'company', $group_key: groupId, $group_set: traits },\n },\n 'group',\n );\n },\n\n async alias(userId: string, previousId: string) {\n await safeFetch(\n {\n api_key: apiKey,\n event: '$create_alias',\n properties: { distinct_id: userId, alias: previousId },\n },\n 'alias',\n );\n },\n };\n}\n\n// Export edge-compatible configuration utilities\nexport { getAnalyticsConfig } from './shared/utils/config';\n"],"mappings":";;;;;;;;;;;AASA,MAAa,MAAM,UAAU;CAC3B,QAAQ;EAEN,cAAc,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,0BAA0B;EACjE,aAAa,EAAE,QAAQ,CAAC,UAAU;EAClC,iBAAiB,EAAE,QAAQ,CAAC,UAAU;EACtC,0BAA0B,EAAE,QAAQ,CAAC,UAAU;EAC/C,oBAAoB,EAAE,QAAQ,CAAC,UAAU;EAGzC,mBAAmB,EAAE,QAAQ,CAAC,UAAU;EAGxC,wBAAwB,EAAE,KAAK,CAAC,WAAW,SAAS,CAAC,CAAC,QAAQ,UAAU;EAGxE,UAAU,EAAE,KAAK;GAAC;GAAe;GAAQ;GAAa,CAAC,CAAC,QAAQ,cAAc;EAC9E,SAAS,EAAE,KAAK;GAAC;GAAe;GAAW;GAAa,CAAC,CAAC,UAAU;EACpE,cAAc,EAAE,KAAK,CAAC,UAAU,OAAO,CAAC,CAAC,UAAU;EACpD;CACD,cAAc;CACd,QAAQ;EAEN,0BAA0B,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,0BAA0B;EAC7E,yBAAyB,EAAE,QAAQ,CAAC,UAAU;EAG9C,+BAA+B,EAAE,QAAQ,CAAC,UAAU;EAGpD,iCAAiC,EAAE,QAAQ,CAAC,UAAU;EAGtD,qBAAqB,EAAE,KAAK;GAAC;GAAe;GAAW;GAAa,CAAC,CAAC,UAAU;EAChF,sBAAsB,EAAE,KAAK;GAAC;GAAe;GAAQ;GAAa,CAAC,CAAC,QAAQ,cAAc;EAC3F;CACD,YAAY,QAAQ;CACpB,wBAAwB;CACxB,kBAAkB,aAAqB;AACrC,QAAM,IAAI,MACR,2EAA2E,WAC5E;;CAEH,oBAAoB,UAAmB;AACrC,UAAQ,4CAA4C,EAAE,OAAO,OAAO,MAAM,EAAE,CAAC;;CAIhF,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACwBF,MAAM,gBAAiC,EAAE,WAAW,EAAE,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCxD,eAAsB,sBACpB,SAA0B,eACC;CAC3B,MAAM,YAAiC,EAAE;CACzC,IAAI,UAA4B,EAAE;AAGlC,KAAI,OAAO,UAAU,SAAS;EAC5B,MAAM,EAAE,oBAAoB,MAAM,OAAO;EACzC,MAAM,kBAAkB,IAAI,gBAAgB,OAAO,UAAU,QAAQ;AACrE,QAAM,gBAAgB,YAAY;AAClC,YAAU,KAAK,gBAAgB;;AAIjC,KAAI,OAAO,UAAU,SAAS,QAAQ;EACpC,MAAM,kBAAkB,0BAA0B,OAAO;AACzD,YAAU,KAAK,gBAAgB;;CAIjC,MAAM,iBAAiB,OAAO,YAA2C;AACvE,UAAQ,QAAQ,MAAhB;GACE,KAAK,SAAS;IACZ,MAAM,IAAI;AACV,UAAM,QAAQ,WACZ,UAAU,KAAI,aACZ,SAAS,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE;KAAE,GAAG;KAAS,GAAG,EAAE;KAAS,CAAC,CAC1E,CACF;AACD;;GAEF,KAAK,YAAY;IACf,MAAM,IAAI;AACV,UAAM,QAAQ,WACZ,UAAU,KAAI,aACZ,SAAS,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE;KAAE,GAAG;KAAS,GAAG,EAAE;KAAS,CAAC,CAC5E,CACF;AACD;;GAEF,KAAK,QAAQ;IACX,MAAM,IAAI;AACV,UAAM,QAAQ,WACZ,UAAU,KAAI,aACZ,SAAS,OAAO,EAAE,QAAQ,IAAI,EAAE,cAAc,EAAE,EAAE;KAAE,GAAG;KAAS,GAAG,EAAE;KAAS,CAAC,CAChF,CACF;AACD;;GAEF,KAAK,UAAU;IACb,MAAM,IAAI;AACV,UAAM,QAAQ,WACZ,UAAU,KAAI,aACZ,SAAS,SAAS,EAAE,QAAQ,IAAI,EAAE,cAAc,EAAE,EAAE;KAAE,GAAG;KAAS,GAAG,EAAE;KAAS,CAAC,CAClF,CACF;AACD;;GAEF,KAAK,SAAS;IACZ,MAAM,IAAI;AACV,UAAM,QAAQ,WACZ,UAAU,KAAI,aACZ,SAAS,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE;KAAE,GAAG;KAAS,GAAG,EAAE;KAAS,CAAC,CAC1E,CACF;AACD;;GAEF,KAAK,SAAS;IACZ,MAAM,IAAI;AACV,UAAM,QAAQ,WACZ,UAAU,KAAI,aACZ,SAAS,QAAQ,EAAE,QAAQ,EAAE,YAAY;KAAE,GAAG;KAAS,GAAG,EAAE;KAAS,CAAC,CACvE,CACF;AACD;;;;CAMN,SAAS,sBAAsB,SAAwC;AACrE,SAAO,eAAe,QAAQ;;AAyGhC,QArGkC;EAChC,mBAAmB,EAAE,GAAG,SAAS;EAEjC,YAAY,YAAY;EAIxB,aAAa,eAAiC;AAC5C,aAAU;IAAE,GAAG;IAAS,GAAG;IAAY;;EAGzC,qBAAqB;EAErB,MAAM,OAAO,YAA4B;AACvC,SAAM,eAAe,QAAQ;;EAG/B,WAAW,OAAO,aAA+B;AAE/C,QAAK,MAAM,WAAW,SACpB,OAAM,eAAe,QAAQ;;EAKjC,OAAO,OAAO,gBAA8C,eAA4B;AACtF,OAAI,OAAO,mBAAmB,SAC5B,OAAM,eAAe,eAAe;YAC3B,OAAO,mBAAmB,SACnC,OAAM,QAAQ,WACZ,UAAU,KAAI,MAAK,EAAE,MAAM,gBAAgB,cAAc,EAAE,EAAE,QAAQ,CAAC,CACvE;;EAKL,UAAU,OAAO,iBAAkD,WAA4B;AAC7F,OAAI,OAAO,oBAAoB,SAC7B,OAAM,eAAe,gBAAgB;YAC5B,OAAO,oBAAoB,SACpC,OAAM,QAAQ,WACZ,UAAU,KAAI,MAAK,EAAE,WAAW,iBAAiB,UAAU,EAAE,EAAE,QAAQ,CAAC,CACzE;;EAKL,MAAM,OAAO,eAA6C,eAAgC;AACxF,OAAI,OAAO,kBAAkB,SAC3B,OAAM,eAAe,cAAc;QAC9B;IACL,MAAM,WAAW,OAAO,kBAAkB,WAAW,gBAAgB;AACrE,UAAM,QAAQ,WAAW,UAAU,KAAI,MAAK,EAAE,OAAO,UAAU,cAAc,EAAE,EAAE,QAAQ,CAAC,CAAC;;;EAK/F,OAAO,OAAO,kBAAgD,WAAyB;AACrF,OAAI,OAAO,qBAAqB,SAC9B,OAAM,eAAe,iBAAiB;YAC7B,OAAO,qBAAqB,SACrC,OAAM,QAAQ,WACZ,UAAU,KAAI,MAAK,EAAE,QAAQ,kBAAkB,UAAU,EAAE,EAAE,QAAQ,CAAC,CACvE;;EAKL,OAAO,OAAO,iBAA+C,eAAwB;AACnF,OAAI,OAAO,oBAAoB,SAC7B,OAAM,eAAe,gBAAgB;YAC5B,OAAO,oBAAoB,YAAY,WAChD,OAAM,QAAQ,WACZ,UAAU,KAAI,MAAK,EAAE,QAAQ,iBAAiB,YAAY,QAAQ,CAAC,CACpE;;EAIL,0BAA0B,UAAU,KAAI,MAAK,EAAE,KAAK;EACpD,cAAc,SAAiB,UAAU,MAAK,MAAK,EAAE,SAAS,KAAK;EAEnE,aAAa;AACX,aAAU,EAAE;;EAGd,UAAU,YAAY;AAEpB,aAAU,SAAS;;EAIrB,uBAAuB,OAAO,YAA4B;AACxD,SAAM,eAAe,QAAQ;;EAE/B,gBAAgB,YAAY;AAC1B,OAAI,OAAO,SAAS,OAAO,OACzB,QAAO,OAAO,oEAAoE;;EAGvF;;;;;;;;;;;;;;;;;;;;;AAwBH,SAAS,0BAA0B,QAA4C;CAC7E,MAAM,gBAAgB,OAAO,WAAW;AACxC,KAAI,CAAC,eAAe,OAClB,OAAM,IAAI,MAAM,6BAA6B;CAO/C,MAAM,aAAa,GAHhB,cAAc,SAA+C,YAC9D,IAAI,gBACJ,0BACgC;CAClC,MAAM,EAAE,WAAW;CACnB,MAAM,UAAU;CAGhB,MAAM,YAAY,OAAO,MAA+B,WAAkC;EACxF,MAAM,aAAa,IAAI,iBAAiB;EACxC,MAAM,YAAY,iBAAiB,WAAW,OAAO,EAAE,QAAQ;AAE/D,MAAI;GACF,MAAM,WAAW,MAAM,MAAM,YAAY;IACvC,QAAQ;IACR,SAAS,EAAE,gBAAgB,oBAAoB;IAC/C,MAAM,KAAK,UAAU,KAAK;IAC1B,QAAQ,WAAW;IACpB,CAAC;AAEF,OAAI,CAAC,SAAS,MAAM,OAAO,QACzB,QAAO,wBACL,IAAI,MAAM,WAAW,OAAO,WAAW,SAAS,OAAO,GAAG,SAAS,aAAa,EAChF;IAAE,UAAU;IAAgB;IAAQ,QAAQ,SAAS;IAAQ,CAC9D;WAEI,OAAO;AACd,OAAI,OAAO,QACT,QAAO,QAAQ,iBAAiB,QAAQ,wBAAQ,IAAI,MAAM,gBAAgB,EAAE;IAC1E,UAAU;IACV;IACD,CAAC;YAEI;AACR,gBAAa,UAAU;;;AAI3B,QAAO;EACL,MAAM;EAEN,MAAM,aAAa;EAInB,MAAM,MAAM,OAAe,YAA8B,SAA4B;AAEnF,SAAM,UACJ;IACE,SAAS;IACT;IACA,aALe,SAAS,UAAU,YAAY,cAAc;IAM5D,YAAY;KAAE,GAAG;KAAY,GAAG;KAAS;IACzC,4BAAW,IAAI,MAAM,EAAC,aAAa;IACpC,EACD,QACD;;EAGH,MAAM,SAAS,QAAgB,QAAyB;AACtD,SAAM,UACJ;IACE,SAAS;IACT,OAAO;IACP,aAAa;IACb,YAAY,EAAE,MAAM,QAAQ;IAC7B,EACD,WACD;;EAGH,MAAM,KAAK,MAAe,YAA6B,SAA4B;AAEjF,SAAM,UACJ;IACE,SAAS;IACT,OAAO;IACP,aALe,SAAS,UAAU;IAMlC,YAAY;KAAE,cAAc,YAAY;KAAK,QAAQ;KAAM,GAAG;KAAY;IAC3E,EACD,OACD;;EAGH,MAAM,MAAM,SAAiB,QAAsB,SAA4B;AAE7E,SAAM,UACJ;IACE,SAAS;IACT,OAAO;IACP,aALe,SAAS,UAAU;IAMlC,YAAY;KAAE,aAAa;KAAW,YAAY;KAAS,YAAY;KAAQ;IAChF,EACD,QACD;;EAGH,MAAM,MAAM,QAAgB,YAAoB;AAC9C,SAAM,UACJ;IACE,SAAS;IACT,OAAO;IACP,YAAY;KAAE,aAAa;KAAQ,OAAO;KAAY;IACvD,EACD,QACD;;EAEJ"}
1
+ {"version":3,"file":"server-edge.mjs","names":[],"sources":["../env.ts","../src/server-edge.ts"],"sourcesContent":["/**\n * @fileoverview Environment variable configuration for analytics package\n * Environment variable configuration for analytics package\n */\n\nimport { logWarn } from '@od-oneapp/shared/logger';\nimport { createEnv } from '@t3-oss/env-core';\nimport { z } from 'zod/v4';\n\nexport const env = createEnv({\n server: {\n // PostHog server configuration for feature flags and analytics\n POSTHOG_HOST: z.string().url().default('https://app.posthog.com'),\n POSTHOG_KEY: z.string().optional(),\n POSTHOG_API_KEY: z.string().optional(), // Additional key used in source code\n POSTHOG_PERSONAL_API_KEY: z.string().optional(),\n POSTHOG_PROJECT_ID: z.string().optional(),\n\n // Segment server configuration\n SEGMENT_WRITE_KEY: z.string().optional(),\n\n // Analytics logging configuration\n ANALYTICS_LOG_PROVIDER: z.enum(['console', 'sentry']).default('console'),\n\n // Environment detection\n NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),\n APP_ENV: z.enum(['development', 'staging', 'production']).optional(),\n NEXT_RUNTIME: z.enum(['nodejs', 'edge']).optional(),\n },\n clientPrefix: 'NEXT_PUBLIC_',\n client: {\n // PostHog client configuration\n NEXT_PUBLIC_POSTHOG_HOST: z.string().url().default('https://app.posthog.com'),\n NEXT_PUBLIC_POSTHOG_KEY: z.string().optional(),\n\n // Segment client configuration\n NEXT_PUBLIC_SEGMENT_WRITE_KEY: z.string().optional(),\n\n // Vercel Analytics\n NEXT_PUBLIC_VERCEL_ANALYTICS_ID: z.string().optional(),\n\n // App environment for client\n NEXT_PUBLIC_APP_ENV: z.enum(['development', 'staging', 'production']).optional(),\n NEXT_PUBLIC_NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),\n },\n runtimeEnv: process.env,\n emptyStringAsUndefined: true,\n onInvalidAccess: (variable: string) => {\n throw new Error(\n `❌ Attempted to access a server-side environment variable on the client: ${variable}`,\n );\n },\n onValidationError: (error: unknown) => {\n logWarn('Analytics environment validation failed:', { error: String(error) });\n // Don't throw in packages - use fallbacks for resilience\n return undefined as never;\n },\n});\n\n/**\n * Returns a resilient env object for non-Next.js runtimes (CLI scripts, tests, workers).\n *\n * Codex/OpenAI models can rely on this helper when generating examples because it always\n * returns a fully populated object, using process.env fallbacks when the strongly typed\n * `createEnv` instance is unavailable.\n */\nexport function safeEnv() {\n // env is always defined, but may have validation errors\n // Return env directly, fallback only if access throws\n try {\n return env;\n } catch {\n // Return fallback if env access fails\n return {\n // Server variables\n POSTHOG_HOST: process.env.POSTHOG_HOST ?? 'https://app.posthog.com',\n POSTHOG_KEY: process.env.POSTHOG_KEY ?? '',\n POSTHOG_API_KEY: process.env.POSTHOG_API_KEY ?? '',\n POSTHOG_PERSONAL_API_KEY: process.env.POSTHOG_PERSONAL_API_KEY ?? '',\n POSTHOG_PROJECT_ID: process.env.POSTHOG_PROJECT_ID ?? '',\n SEGMENT_WRITE_KEY: process.env.SEGMENT_WRITE_KEY ?? '',\n ANALYTICS_LOG_PROVIDER:\n (process.env.ANALYTICS_LOG_PROVIDER as 'console' | 'sentry' | undefined) ?? 'console',\n NODE_ENV: (process.env.NODE_ENV as string | undefined) ?? 'development',\n APP_ENV: process.env.APP_ENV as 'development' | 'staging' | 'production' | undefined,\n NEXT_RUNTIME: process.env.NEXT_RUNTIME as 'nodejs' | 'edge' | undefined,\n\n // Client variables\n NEXT_PUBLIC_POSTHOG_HOST: process.env.NEXT_PUBLIC_POSTHOG_HOST ?? 'https://app.posthog.com',\n NEXT_PUBLIC_POSTHOG_KEY: process.env.NEXT_PUBLIC_POSTHOG_KEY ?? '',\n NEXT_PUBLIC_SEGMENT_WRITE_KEY: process.env.NEXT_PUBLIC_SEGMENT_WRITE_KEY ?? '',\n NEXT_PUBLIC_VERCEL_ANALYTICS_ID: process.env.NEXT_PUBLIC_VERCEL_ANALYTICS_ID ?? '',\n NEXT_PUBLIC_APP_ENV: process.env.NEXT_PUBLIC_APP_ENV as\n | 'development'\n | 'staging'\n | 'production'\n | undefined,\n NEXT_PUBLIC_NODE_ENV:\n (process.env.NEXT_PUBLIC_NODE_ENV as 'development' | 'test' | 'production' | undefined) ??\n 'development',\n };\n }\n}\n\n// Export type for better DX\nexport type Env = typeof env;\n","/**\n * @fileoverview Edge Runtime Analytics Module\n *\n * Provides edge-compatible analytics for Next.js middleware and edge API routes.\n * Uses Web APIs and HTTP-based implementations compatible with edge runtime.\n *\n * **Supported Features**:\n * - Basic event tracking (track, identify, page, group, alias)\n * - Console provider (uses console API)\n * - PostHog provider (HTTP-based, no SDK dependency)\n * - Emitter pattern support via `emit()`\n *\n * **Limitations (Edge Runtime Constraints)**:\n * - No Node.js APIs (fs, crypto, etc.)\n * - No native modules or SDK dependencies\n * - No event deduplication (no LRU cache)\n * - No rate limiting (100 req/s limit not enforced)\n * - No batch processing optimization\n * - No performance metrics tracking\n * - No feature flags (PostHog flags require server SDK)\n * - Context is per-request only (not persisted)\n *\n * **For full analytics features**, use `@od-oneapp/analytics/server` in Node.js environments.\n *\n * **Usage**: Import from `@od-oneapp/analytics/server/edge` for Next.js middleware and edge API routes.\n *\n * @example\n * ```typescript\n * // In Next.js middleware\n * import { createServerAnalytics, track } from '@od-oneapp/analytics/server/edge';\n *\n * export async function middleware(request: NextRequest) {\n * const analytics = await createServerAnalytics({\n * providers: {\n * posthog: { apiKey: process.env.POSTHOG_API_KEY }\n * }\n * });\n *\n * await analytics.emit(track('Middleware Hit', { path: request.nextUrl.pathname }));\n * return NextResponse.next();\n * }\n * ```\n *\n * @module @od-oneapp/analytics/server/edge\n */\n\nimport { env } from '../env';\n\nimport type {\n EmitterAliasPayload,\n EmitterGroupPayload,\n EmitterIdentifyPayload,\n EmitterPagePayload,\n EmitterPayload,\n EmitterTrackPayload,\n} from './shared/emitters/emitter-types';\nimport type {\n AnalyticsConfig,\n AnalyticsContext,\n AnalyticsManager,\n AnalyticsProvider,\n GroupTraits,\n PageProperties,\n Properties,\n UserTraits,\n} from './shared/types/types';\n\n// Type aliases for clarity\ntype IdentifyTraits = UserTraits;\ntype TrackProperties = Properties;\n\n// Re-export types for consumers\nexport type * from './shared/emitters/emitter-types';\nexport type * from './shared/types/types';\n\n// Re-export emitter utilities\nexport { createEmitterProcessor } from './shared/utils/emitter-adapter';\n\n// Re-export core emitters for edge usage\nexport { alias, group, identify, page, track } from './shared/emitters';\n\nconst defaultConfig: AnalyticsConfig = { providers: {} };\n\n/**\n * Creates an edge-compatible analytics manager.\n *\n * This is a simplified implementation optimized for edge runtime constraints.\n * It provides basic analytics functionality without Node.js-specific features.\n *\n * **Supported Providers**:\n * - Console (always available)\n * - PostHog (HTTP-based, requires API key)\n *\n * **Not Supported in Edge**:\n * - Segment SDK (requires Node.js)\n * - Vercel Analytics SDK (requires Node.js)\n * - Rate limiting\n * - Event deduplication\n * - Batch processing optimization\n *\n * @param {AnalyticsConfig} [config] - Analytics configuration with provider settings\n * @returns {Promise<AnalyticsManager>} Promise resolving to AnalyticsManager instance\n *\n * @example\n * ```typescript\n * const analytics = await createServerAnalytics({\n * providers: {\n * posthog: { apiKey: process.env.POSTHOG_API_KEY }\n * }\n * });\n *\n * await analytics.track('Event Name', { property: 'value' });\n * ```\n */\nexport async function createServerAnalytics(\n config: AnalyticsConfig = defaultConfig,\n): Promise<AnalyticsManager> {\n const providers: AnalyticsProvider[] = [];\n let context: AnalyticsContext = {};\n\n // Initialize Console provider (edge-compatible)\n if (config.providers.console) {\n const { ConsoleProvider } = await import('./providers/console');\n const consoleProvider = new ConsoleProvider(config.providers.console);\n await consoleProvider.initialize();\n providers.push(consoleProvider);\n }\n\n // Initialize PostHog HTTP provider (edge-compatible)\n if (config.providers.posthog?.apiKey) {\n const posthogProvider = createPostHogEdgeProvider(config);\n providers.push(posthogProvider);\n }\n\n // Process emitter payload by type\n const processPayload = async (payload: EmitterPayload): Promise<void> => {\n switch (payload.type) {\n case 'track': {\n const p = payload;\n await Promise.allSettled(\n providers.map(provider =>\n provider.track(p.event, p.properties ?? {}, { ...context, ...p.context }),\n ),\n );\n break;\n }\n case 'identify': {\n const p = payload;\n await Promise.allSettled(\n providers.map(provider =>\n provider.identify?.(p.userId, p.traits ?? {}, { ...context, ...p.context }),\n ),\n );\n break;\n }\n case 'page': {\n const p = payload;\n await Promise.allSettled(\n providers.map(provider =>\n provider.page?.(p.name ?? '', p.properties ?? {}, { ...context, ...p.context }),\n ),\n );\n break;\n }\n case 'screen': {\n const p = payload;\n await Promise.allSettled(\n providers.map(provider =>\n provider.screen?.(p.name ?? '', p.properties ?? {}, { ...context, ...p.context }),\n ),\n );\n break;\n }\n case 'group': {\n const p = payload;\n await Promise.allSettled(\n providers.map(provider =>\n provider.group?.(p.groupId, p.traits ?? {}, { ...context, ...p.context }),\n ),\n );\n break;\n }\n case 'alias': {\n const p = payload;\n await Promise.allSettled(\n providers.map(provider =>\n provider.alias?.(p.userId, p.previousId, { ...context, ...p.context }),\n ),\n );\n break;\n }\n }\n };\n\n // Create emitter function at outer scope (within createServerAnalytics)\n function createEmitterFunction(payload: EmitterPayload): Promise<void> {\n return processPayload(payload);\n }\n\n // Return edge-compatible analytics manager\n const manager: AnalyticsManager = {\n getContext: () => ({ ...context }),\n\n initialize: async () => {\n // Providers already initialized above\n },\n\n setContext: (newContext: AnalyticsContext) => {\n context = { ...context, ...newContext };\n },\n\n createEmitter: () => createEmitterFunction,\n\n emit: async (payload: EmitterPayload) => {\n await processPayload(payload);\n },\n\n emitBatch: async (payloads: EmitterPayload[]) => {\n // Process sequentially in edge (no concurrency optimization)\n for (const payload of payloads) {\n await processPayload(payload);\n }\n },\n\n // Overloaded track method\n track: async (eventOrPayload: string | EmitterTrackPayload, properties?: Properties) => {\n if (typeof eventOrPayload === 'object') {\n await processPayload(eventOrPayload);\n } else if (typeof eventOrPayload === 'string') {\n await Promise.allSettled(\n providers.map(p => p.track(eventOrPayload, properties ?? {}, context)),\n );\n }\n },\n\n // Overloaded identify method\n identify: async (userIdOrPayload: string | EmitterIdentifyPayload, traits?: IdentifyTraits) => {\n if (typeof userIdOrPayload === 'object') {\n await processPayload(userIdOrPayload);\n } else if (typeof userIdOrPayload === 'string') {\n await Promise.allSettled(\n providers.map(p => p.identify?.(userIdOrPayload, traits ?? {}, context)),\n );\n }\n },\n\n // Overloaded page method\n page: async (nameOrPayload?: string | EmitterPagePayload, properties?: PageProperties) => {\n if (typeof nameOrPayload === 'object') {\n await processPayload(nameOrPayload);\n } else {\n const pageName = typeof nameOrPayload === 'string' ? nameOrPayload : '';\n await Promise.allSettled(providers.map(p => p.page?.(pageName, properties ?? {}, context)));\n }\n },\n\n // Overloaded group method\n group: async (groupIdOrPayload: string | EmitterGroupPayload, traits?: GroupTraits) => {\n if (typeof groupIdOrPayload === 'object') {\n await processPayload(groupIdOrPayload);\n } else if (typeof groupIdOrPayload === 'string') {\n await Promise.allSettled(\n providers.map(p => p.group?.(groupIdOrPayload, traits ?? {}, context)),\n );\n }\n },\n\n // Overloaded alias method\n alias: async (userIdOrPayload: string | EmitterAliasPayload, previousId?: string) => {\n if (typeof userIdOrPayload === 'object') {\n await processPayload(userIdOrPayload);\n } else if (typeof userIdOrPayload === 'string' && previousId) {\n await Promise.allSettled(\n providers.map(p => p.alias?.(userIdOrPayload, previousId, context)),\n );\n }\n },\n\n getActiveProviders: () => providers.map(p => p.name),\n getProvider: (name: string) => providers.find(p => p.name === name),\n\n reset: () => {\n context = {};\n },\n\n shutdown: async () => {\n // In edge, we don't have complex shutdown logic usually\n providers.length = 0;\n },\n\n // Deprecated methods (no-ops with warning)\n processEmitterPayload: async (payload: EmitterPayload) => {\n await processPayload(payload);\n },\n trackEcommerce: async () => {\n if (config.debug && config.onInfo) {\n config.onInfo('trackEcommerce is deprecated, use emit(ecommerce.EVENT_NAME(...))');\n }\n },\n };\n\n return manager;\n}\n\n/**\n * Creates a PostHog provider that uses HTTP API (edge-compatible).\n *\n * This provider uses PostHog's HTTP capture API instead of the Node.js SDK,\n * making it compatible with edge runtime constraints.\n *\n * **Features**:\n * - HTTP-based event tracking\n * - 5-second timeout per request\n * - Error handling via config callbacks\n * - Supports all standard analytics methods (track, identify, page, group, alias)\n *\n * @param {AnalyticsConfig} config - Analytics configuration\n * @returns {AnalyticsProvider} PostHog provider instance\n *\n * @throws {Error} If PostHog API key is not provided\n *\n * @internal\n */\nfunction createPostHogEdgeProvider(config: AnalyticsConfig): AnalyticsProvider {\n const posthogConfig = config.providers?.posthog;\n if (!posthogConfig?.apiKey) {\n throw new Error('PostHog apiKey is required');\n }\n\n const posthogHost =\n (posthogConfig.options as { api_host?: string } | undefined)?.api_host ??\n env.POSTHOG_HOST ??\n 'https://app.posthog.com';\n const posthogUrl = `${posthogHost}/capture/`;\n const { apiKey } = posthogConfig;\n const timeout = 5000;\n\n // Safe fetch with timeout and error handling\n const safeFetch = async (body: Record<string, unknown>, method: string): Promise<void> => {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(posthogUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n if (!response.ok && config.onError) {\n config.onError(\n new Error(`PostHog ${method} failed: ${response.status} ${response.statusText}`),\n { provider: 'posthog-edge', method, status: response.status },\n );\n }\n } catch (error) {\n if (config.onError) {\n config.onError(error instanceof Error ? error : new Error('Unknown error'), {\n provider: 'posthog-edge',\n method,\n });\n }\n } finally {\n clearTimeout(timeoutId);\n }\n };\n\n return {\n name: 'posthog-edge',\n\n async initialize() {\n // No initialization needed for HTTP-based PostHog\n },\n\n async track(event: string, properties?: TrackProperties, context?: AnalyticsContext) {\n const distinctId = context?.userId ?? properties?.distinctId ?? 'anonymous';\n await safeFetch(\n {\n api_key: apiKey,\n event,\n distinct_id: distinctId,\n properties: { ...properties, ...context },\n timestamp: new Date().toISOString(),\n },\n 'track',\n );\n },\n\n async identify(userId: string, traits?: IdentifyTraits) {\n await safeFetch(\n {\n api_key: apiKey,\n event: '$identify',\n distinct_id: userId,\n properties: { $set: traits },\n },\n 'identify',\n );\n },\n\n async page(name?: string, properties?: PageProperties, context?: AnalyticsContext) {\n const distinctId = context?.userId ?? 'anonymous';\n await safeFetch(\n {\n api_key: apiKey,\n event: '$pageview',\n distinct_id: distinctId,\n properties: { $current_url: properties?.url, $title: name, ...properties },\n },\n 'page',\n );\n },\n\n async group(groupId: string, traits?: GroupTraits, context?: AnalyticsContext) {\n const distinctId = context?.userId ?? 'anonymous';\n await safeFetch(\n {\n api_key: apiKey,\n event: '$groupidentify',\n distinct_id: distinctId,\n properties: { $group_type: 'company', $group_key: groupId, $group_set: traits },\n },\n 'group',\n );\n },\n\n async alias(userId: string, previousId: string) {\n await safeFetch(\n {\n api_key: apiKey,\n event: '$create_alias',\n properties: { distinct_id: userId, alias: previousId },\n },\n 'alias',\n );\n },\n };\n}\n\n// Export edge-compatible configuration utilities\nexport { getAnalyticsConfig } from './shared/utils/config';\n"],"mappings":";;;;;;;;;;;AASA,MAAa,MAAM,UAAU;CAC3B,QAAQ;EAEN,cAAc,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,0BAA0B;EACjE,aAAa,EAAE,QAAQ,CAAC,UAAU;EAClC,iBAAiB,EAAE,QAAQ,CAAC,UAAU;EACtC,0BAA0B,EAAE,QAAQ,CAAC,UAAU;EAC/C,oBAAoB,EAAE,QAAQ,CAAC,UAAU;EAGzC,mBAAmB,EAAE,QAAQ,CAAC,UAAU;EAGxC,wBAAwB,EAAE,KAAK,CAAC,WAAW,SAAS,CAAC,CAAC,QAAQ,UAAU;EAGxE,UAAU,EAAE,KAAK;GAAC;GAAe;GAAQ;GAAa,CAAC,CAAC,QAAQ,cAAc;EAC9E,SAAS,EAAE,KAAK;GAAC;GAAe;GAAW;GAAa,CAAC,CAAC,UAAU;EACpE,cAAc,EAAE,KAAK,CAAC,UAAU,OAAO,CAAC,CAAC,UAAU;EACpD;CACD,cAAc;CACd,QAAQ;EAEN,0BAA0B,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,0BAA0B;EAC7E,yBAAyB,EAAE,QAAQ,CAAC,UAAU;EAG9C,+BAA+B,EAAE,QAAQ,CAAC,UAAU;EAGpD,iCAAiC,EAAE,QAAQ,CAAC,UAAU;EAGtD,qBAAqB,EAAE,KAAK;GAAC;GAAe;GAAW;GAAa,CAAC,CAAC,UAAU;EAChF,sBAAsB,EAAE,KAAK;GAAC;GAAe;GAAQ;GAAa,CAAC,CAAC,QAAQ,cAAc;EAC3F;CACD,YAAY,QAAQ;CACpB,wBAAwB;CACxB,kBAAkB,aAAqB;AACrC,QAAM,IAAI,MACR,2EAA2E,WAC5E;;CAEH,oBAAoB,UAAmB;AACrC,UAAQ,4CAA4C,EAAE,OAAO,OAAO,MAAM,EAAE,CAAC;;CAIhF,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACwBF,MAAM,gBAAiC,EAAE,WAAW,EAAE,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCxD,eAAsB,sBACpB,SAA0B,eACC;CAC3B,MAAM,YAAiC,EAAE;CACzC,IAAI,UAA4B,EAAE;AAGlC,KAAI,OAAO,UAAU,SAAS;EAC5B,MAAM,EAAE,oBAAoB,MAAM,OAAO;EACzC,MAAM,kBAAkB,IAAI,gBAAgB,OAAO,UAAU,QAAQ;AACrE,QAAM,gBAAgB,YAAY;AAClC,YAAU,KAAK,gBAAgB;;AAIjC,KAAI,OAAO,UAAU,SAAS,QAAQ;EACpC,MAAM,kBAAkB,0BAA0B,OAAO;AACzD,YAAU,KAAK,gBAAgB;;CAIjC,MAAM,iBAAiB,OAAO,YAA2C;AACvE,UAAQ,QAAQ,MAAhB;GACE,KAAK,SAAS;IACZ,MAAM,IAAI;AACV,UAAM,QAAQ,WACZ,UAAU,KAAI,aACZ,SAAS,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE;KAAE,GAAG;KAAS,GAAG,EAAE;KAAS,CAAC,CAC1E,CACF;AACD;;GAEF,KAAK,YAAY;IACf,MAAM,IAAI;AACV,UAAM,QAAQ,WACZ,UAAU,KAAI,aACZ,SAAS,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE;KAAE,GAAG;KAAS,GAAG,EAAE;KAAS,CAAC,CAC5E,CACF;AACD;;GAEF,KAAK,QAAQ;IACX,MAAM,IAAI;AACV,UAAM,QAAQ,WACZ,UAAU,KAAI,aACZ,SAAS,OAAO,EAAE,QAAQ,IAAI,EAAE,cAAc,EAAE,EAAE;KAAE,GAAG;KAAS,GAAG,EAAE;KAAS,CAAC,CAChF,CACF;AACD;;GAEF,KAAK,UAAU;IACb,MAAM,IAAI;AACV,UAAM,QAAQ,WACZ,UAAU,KAAI,aACZ,SAAS,SAAS,EAAE,QAAQ,IAAI,EAAE,cAAc,EAAE,EAAE;KAAE,GAAG;KAAS,GAAG,EAAE;KAAS,CAAC,CAClF,CACF;AACD;;GAEF,KAAK,SAAS;IACZ,MAAM,IAAI;AACV,UAAM,QAAQ,WACZ,UAAU,KAAI,aACZ,SAAS,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE;KAAE,GAAG;KAAS,GAAG,EAAE;KAAS,CAAC,CAC1E,CACF;AACD;;GAEF,KAAK,SAAS;IACZ,MAAM,IAAI;AACV,UAAM,QAAQ,WACZ,UAAU,KAAI,aACZ,SAAS,QAAQ,EAAE,QAAQ,EAAE,YAAY;KAAE,GAAG;KAAS,GAAG,EAAE;KAAS,CAAC,CACvE,CACF;AACD;;;;CAMN,SAAS,sBAAsB,SAAwC;AACrE,SAAO,eAAe,QAAQ;;AAyGhC,QArGkC;EAChC,mBAAmB,EAAE,GAAG,SAAS;EAEjC,YAAY,YAAY;EAIxB,aAAa,eAAiC;AAC5C,aAAU;IAAE,GAAG;IAAS,GAAG;IAAY;;EAGzC,qBAAqB;EAErB,MAAM,OAAO,YAA4B;AACvC,SAAM,eAAe,QAAQ;;EAG/B,WAAW,OAAO,aAA+B;AAE/C,QAAK,MAAM,WAAW,SACpB,OAAM,eAAe,QAAQ;;EAKjC,OAAO,OAAO,gBAA8C,eAA4B;AACtF,OAAI,OAAO,mBAAmB,SAC5B,OAAM,eAAe,eAAe;YAC3B,OAAO,mBAAmB,SACnC,OAAM,QAAQ,WACZ,UAAU,KAAI,MAAK,EAAE,MAAM,gBAAgB,cAAc,EAAE,EAAE,QAAQ,CAAC,CACvE;;EAKL,UAAU,OAAO,iBAAkD,WAA4B;AAC7F,OAAI,OAAO,oBAAoB,SAC7B,OAAM,eAAe,gBAAgB;YAC5B,OAAO,oBAAoB,SACpC,OAAM,QAAQ,WACZ,UAAU,KAAI,MAAK,EAAE,WAAW,iBAAiB,UAAU,EAAE,EAAE,QAAQ,CAAC,CACzE;;EAKL,MAAM,OAAO,eAA6C,eAAgC;AACxF,OAAI,OAAO,kBAAkB,SAC3B,OAAM,eAAe,cAAc;QAC9B;IACL,MAAM,WAAW,OAAO,kBAAkB,WAAW,gBAAgB;AACrE,UAAM,QAAQ,WAAW,UAAU,KAAI,MAAK,EAAE,OAAO,UAAU,cAAc,EAAE,EAAE,QAAQ,CAAC,CAAC;;;EAK/F,OAAO,OAAO,kBAAgD,WAAyB;AACrF,OAAI,OAAO,qBAAqB,SAC9B,OAAM,eAAe,iBAAiB;YAC7B,OAAO,qBAAqB,SACrC,OAAM,QAAQ,WACZ,UAAU,KAAI,MAAK,EAAE,QAAQ,kBAAkB,UAAU,EAAE,EAAE,QAAQ,CAAC,CACvE;;EAKL,OAAO,OAAO,iBAA+C,eAAwB;AACnF,OAAI,OAAO,oBAAoB,SAC7B,OAAM,eAAe,gBAAgB;YAC5B,OAAO,oBAAoB,YAAY,WAChD,OAAM,QAAQ,WACZ,UAAU,KAAI,MAAK,EAAE,QAAQ,iBAAiB,YAAY,QAAQ,CAAC,CACpE;;EAIL,0BAA0B,UAAU,KAAI,MAAK,EAAE,KAAK;EACpD,cAAc,SAAiB,UAAU,MAAK,MAAK,EAAE,SAAS,KAAK;EAEnE,aAAa;AACX,aAAU,EAAE;;EAGd,UAAU,YAAY;AAEpB,aAAU,SAAS;;EAIrB,uBAAuB,OAAO,YAA4B;AACxD,SAAM,eAAe,QAAQ;;EAE/B,gBAAgB,YAAY;AAC1B,OAAI,OAAO,SAAS,OAAO,OACzB,QAAO,OAAO,oEAAoE;;EAGvF;;;;;;;;;;;;;;;;;;;;;AAwBH,SAAS,0BAA0B,QAA4C;CAC7E,MAAM,gBAAgB,OAAO,WAAW;AACxC,KAAI,CAAC,eAAe,OAClB,OAAM,IAAI,MAAM,6BAA6B;CAO/C,MAAM,aAAa,GAHhB,cAAc,SAA+C,YAC9D,IAAI,gBACJ,0BACgC;CAClC,MAAM,EAAE,WAAW;CACnB,MAAM,UAAU;CAGhB,MAAM,YAAY,OAAO,MAA+B,WAAkC;EACxF,MAAM,aAAa,IAAI,iBAAiB;EACxC,MAAM,YAAY,iBAAiB,WAAW,OAAO,EAAE,QAAQ;AAE/D,MAAI;GACF,MAAM,WAAW,MAAM,MAAM,YAAY;IACvC,QAAQ;IACR,SAAS,EAAE,gBAAgB,oBAAoB;IAC/C,MAAM,KAAK,UAAU,KAAK;IAC1B,QAAQ,WAAW;IACpB,CAAC;AAEF,OAAI,CAAC,SAAS,MAAM,OAAO,QACzB,QAAO,wBACL,IAAI,MAAM,WAAW,OAAO,WAAW,SAAS,OAAO,GAAG,SAAS,aAAa,EAChF;IAAE,UAAU;IAAgB;IAAQ,QAAQ,SAAS;IAAQ,CAC9D;WAEI,OAAO;AACd,OAAI,OAAO,QACT,QAAO,QAAQ,iBAAiB,QAAQ,wBAAQ,IAAI,MAAM,gBAAgB,EAAE;IAC1E,UAAU;IACV;IACD,CAAC;YAEI;AACR,gBAAa,UAAU;;;AAI3B,QAAO;EACL,MAAM;EAEN,MAAM,aAAa;EAInB,MAAM,MAAM,OAAe,YAA8B,SAA4B;AAEnF,SAAM,UACJ;IACE,SAAS;IACT;IACA,aALe,SAAS,UAAU,YAAY,cAAc;IAM5D,YAAY;KAAE,GAAG;KAAY,GAAG;KAAS;IACzC,4BAAW,IAAI,MAAM,EAAC,aAAa;IACpC,EACD,QACD;;EAGH,MAAM,SAAS,QAAgB,QAAyB;AACtD,SAAM,UACJ;IACE,SAAS;IACT,OAAO;IACP,aAAa;IACb,YAAY,EAAE,MAAM,QAAQ;IAC7B,EACD,WACD;;EAGH,MAAM,KAAK,MAAe,YAA6B,SAA4B;AAEjF,SAAM,UACJ;IACE,SAAS;IACT,OAAO;IACP,aALe,SAAS,UAAU;IAMlC,YAAY;KAAE,cAAc,YAAY;KAAK,QAAQ;KAAM,GAAG;KAAY;IAC3E,EACD,OACD;;EAGH,MAAM,MAAM,SAAiB,QAAsB,SAA4B;AAE7E,SAAM,UACJ;IACE,SAAS;IACT,OAAO;IACP,aALe,SAAS,UAAU;IAMlC,YAAY;KAAE,aAAa;KAAW,YAAY;KAAS,YAAY;KAAQ;IAChF,EACD,QACD;;EAGH,MAAM,MAAM,QAAgB,YAAoB;AAC9C,SAAM,UACJ;IACE,SAAS;IACT,OAAO;IACP,YAAY;KAAE,aAAa;KAAQ,OAAO;KAAY;IACvD,EACD,QACD;;EAEJ"}
package/server-next.d.mts CHANGED
@@ -1,12 +1,12 @@
1
- import { C as EmitterPagePayload, D as EmitterTrackPayload, S as EmitterOptions, b as EmitterIdentifyPayload, c as ProviderConfig, d as TrackingOptions, g as EmitterContext, i as AnalyticsProvider, n as AnalyticsContext, p as EmitterAliasPayload, r as AnalyticsManager, t as AnalyticsConfig, u as ProviderRegistry, v as EmitterGroupPayload, w as EmitterPayload } from "./types-BxBnNQ0V.mjs";
2
- import { a as screen, i as page, n as group, o as track, r as identify, t as alias } from "./emitters-DldkVSPp.mjs";
3
- import { a as ContextBuilder, c as createAnonymousSession, d as isGroupPayload, f as isIdentifyPayload, g as withUTM, h as withMetadata, l as createUserSession, m as isTrackPayload, n as createMinimalBootstrapData, o as EventBatch, p as isPagePayload, r as generateDistinctId, s as PayloadBuilder, t as createBootstrapData, u as isAliasPayload } from "./posthog-bootstrap-DWxFrxlt.mjs";
4
- import { d as EcommerceEventSpec, m as OrderProperties, p as ExtendedProductProperties, r as CartProperties, t as BaseProductProperties } from "./types-CBvxUEaF.mjs";
5
- import { t as index_d_exports } from "./index-jPzXRn52.mjs";
6
- import { a as createEmitterProcessor, i as validateConfig, n as createConfigBuilder, o as processEmitterPayload, r as getAnalyticsConfig, s as trackEcommerceEvent, t as PROVIDER_REQUIREMENTS } from "./config-DPS6bSYo.mjs";
7
- import { a as ConsoleConfig, c as PostHogConfig, i as SegmentOptions, l as PostHogOptions, n as VercelOptions, o as ConsoleOptions, r as SegmentConfig, s as BootstrapData, t as VercelConfig } from "./vercel-types-lwakUfoI.mjs";
8
- import { n as createAnalyticsManager, t as AnalyticsManager$1 } from "./manager-DvRRjza6.mjs";
9
- import { a as createIngestionService, c as IngestionErrorResponse, d as validateAnalyticsConfig, f as validateConfigOrThrow, h as createServerAnalyticsUninitialized, i as IngestionServiceConfig, l as IngestionSuccessResponse, m as createServerAnalytics, n as IngestionMetrics, o as validateBatchPayload, p as validateProvider, r as IngestionService, s as validateEventPayload, t as IngestionContext, u as debugConfig } from "./index-BfNWgfa5.mjs";
1
+ import { C as EmitterPagePayload, D as EmitterTrackPayload, S as EmitterOptions, b as EmitterIdentifyPayload, c as ProviderConfig, d as TrackingOptions, g as EmitterContext, i as AnalyticsProvider, n as AnalyticsContext, p as EmitterAliasPayload, r as AnalyticsManager, t as AnalyticsConfig, u as ProviderRegistry, v as EmitterGroupPayload, w as EmitterPayload } from "./types-cMMfHIpi.mjs";
2
+ import { a as screen, i as page, n as group, o as track, r as identify, t as alias } from "./emitters-BDSsleo_.mjs";
3
+ import { a as ContextBuilder, c as createAnonymousSession, d as isGroupPayload, f as isIdentifyPayload, g as withUTM, h as withMetadata, l as createUserSession, m as isTrackPayload, n as createMinimalBootstrapData, o as EventBatch, p as isPagePayload, r as generateDistinctId, s as PayloadBuilder, t as createBootstrapData, u as isAliasPayload } from "./posthog-bootstrap-Bu1BfhVv.mjs";
4
+ import { d as EcommerceEventSpec, m as OrderProperties, p as ExtendedProductProperties, r as CartProperties, t as BaseProductProperties } from "./types-DEcTnnFe.mjs";
5
+ import { t as index_d_exports } from "./index-BWhDEs8u.mjs";
6
+ import { a as createEmitterProcessor, i as validateConfig, n as createConfigBuilder, o as processEmitterPayload, r as getAnalyticsConfig, s as trackEcommerceEvent, t as PROVIDER_REQUIREMENTS } from "./config-Ciu7O6n1.mjs";
7
+ import { a as ConsoleConfig, c as PostHogConfig, i as SegmentOptions, l as PostHogOptions, n as VercelOptions, o as ConsoleOptions, r as SegmentConfig, s as BootstrapData, t as VercelConfig } from "./vercel-types-oM7Sn385.mjs";
8
+ import { n as createAnalyticsManager, t as AnalyticsManager$1 } from "./manager-OJpSKwqb.mjs";
9
+ import { a as createIngestionService, c as IngestionErrorResponse, d as validateAnalyticsConfig, f as validateConfigOrThrow, h as createServerAnalyticsUninitialized, i as IngestionServiceConfig, l as IngestionSuccessResponse, m as createServerAnalytics, n as IngestionMetrics, o as validateBatchPayload, p as validateProvider, r as IngestionService, s as validateEventPayload, t as IngestionContext, u as debugConfig } from "./index-DTvdqV7H.mjs";
10
10
  import "./server.mjs";
11
11
 
12
12
  //#region src/next/middleware.d.ts
package/server-next.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import { _ as AnalyticsManager, a as ContextBuilder, c as createAnonymousSession, d as isGroupPayload, f as isIdentifyPayload, g as withUTM, h as withMetadata, i as getDistinctIdFromCookies, l as createUserSession, m as isTrackPayload, n as createMinimalBootstrapData, o as EventBatch, p as isPagePayload, r as generateDistinctId, s as PayloadBuilder, t as createBootstrapData, u as isAliasPayload, v as createAnalyticsManager } from "./posthog-bootstrap-CYfIy_WS.mjs";
2
- import { a as screen, i as page, n as group, o as track, r as identify, t as alias } from "./emitters-6-nKo8i-.mjs";
3
- import { t as ecommerce_exports } from "./ecommerce-Cgu4wlux.mjs";
4
- import { a as createEmitterProcessor, i as validateConfig, n as createConfigBuilder, o as processEmitterPayload, r as getAnalyticsConfig, s as trackEcommerceEvent, t as PROVIDER_REQUIREMENTS } from "./config-P6P5adJg.mjs";
5
- import { a as debugConfig, c as validateProvider, i as validateEventPayload, l as createServerAnalytics, n as createIngestionService, o as validateAnalyticsConfig, r as validateBatchPayload, s as validateConfigOrThrow, t as IngestionService, u as createServerAnalyticsUninitialized } from "./service-Duqnlppl.mjs";
1
+ import { _ as AnalyticsManager, a as ContextBuilder, c as createAnonymousSession, d as isGroupPayload, f as isIdentifyPayload, g as withUTM, h as withMetadata, i as getDistinctIdFromCookies, l as createUserSession, m as isTrackPayload, n as createMinimalBootstrapData, o as EventBatch, p as isPagePayload, r as generateDistinctId, s as PayloadBuilder, t as createBootstrapData, u as isAliasPayload, v as createAnalyticsManager } from "./posthog-bootstrap-DkPdn-hA.mjs";
2
+ import { a as screen, i as page, n as group, o as track, r as identify, t as alias } from "./emitters-BvEelkxS.mjs";
3
+ import { t as ecommerce_exports } from "./ecommerce-DGG1FbiH.mjs";
4
+ import { a as createEmitterProcessor, i as validateConfig, n as createConfigBuilder, o as processEmitterPayload, r as getAnalyticsConfig, s as trackEcommerceEvent, t as PROVIDER_REQUIREMENTS } from "./config-6Mwe7b2O.mjs";
5
+ import { a as debugConfig, c as validateProvider, i as validateEventPayload, l as createServerAnalytics, n as createIngestionService, o as validateAnalyticsConfig, r as validateBatchPayload, s as validateConfigOrThrow, t as IngestionService, u as createServerAnalyticsUninitialized } from "./service-NuHnv30x.mjs";
6
6
 
7
7
  //#region src/next/middleware.ts
8
8
  /**
package/server.d.mts CHANGED
@@ -1,10 +1,10 @@
1
- import { C as EmitterPagePayload, D as EmitterTrackPayload, S as EmitterOptions, b as EmitterIdentifyPayload, c as ProviderConfig, d as TrackingOptions, g as EmitterContext, i as AnalyticsProvider, n as AnalyticsContext, p as EmitterAliasPayload, r as AnalyticsManager, t as AnalyticsConfig, u as ProviderRegistry, v as EmitterGroupPayload, w as EmitterPayload } from "./types-BxBnNQ0V.mjs";
2
- import { a as screen, i as page, n as group, o as track, r as identify, t as alias } from "./emitters-DldkVSPp.mjs";
3
- import { a as ContextBuilder, c as createAnonymousSession, d as isGroupPayload, f as isIdentifyPayload, g as withUTM, h as withMetadata, l as createUserSession, m as isTrackPayload, n as createMinimalBootstrapData, o as EventBatch, p as isPagePayload, r as generateDistinctId, s as PayloadBuilder, t as createBootstrapData, u as isAliasPayload } from "./posthog-bootstrap-DWxFrxlt.mjs";
4
- import { d as EcommerceEventSpec, m as OrderProperties, p as ExtendedProductProperties, r as CartProperties, t as BaseProductProperties } from "./types-CBvxUEaF.mjs";
5
- import { t as index_d_exports } from "./index-jPzXRn52.mjs";
6
- import { a as createEmitterProcessor, i as validateConfig, n as createConfigBuilder, o as processEmitterPayload, r as getAnalyticsConfig, s as trackEcommerceEvent, t as PROVIDER_REQUIREMENTS } from "./config-DPS6bSYo.mjs";
7
- import { a as ConsoleConfig, c as PostHogConfig, i as SegmentOptions, l as PostHogOptions, n as VercelOptions, o as ConsoleOptions, r as SegmentConfig, s as BootstrapData, t as VercelConfig } from "./vercel-types-lwakUfoI.mjs";
8
- import { n as createAnalyticsManager, t as AnalyticsManager$1 } from "./manager-DvRRjza6.mjs";
9
- import { a as createIngestionService, c as IngestionErrorResponse, d as validateAnalyticsConfig, f as validateConfigOrThrow, h as createServerAnalyticsUninitialized, i as IngestionServiceConfig, l as IngestionSuccessResponse, m as createServerAnalytics, n as IngestionMetrics, o as validateBatchPayload, p as validateProvider, r as IngestionService, s as validateEventPayload, t as IngestionContext, u as debugConfig } from "./index-BfNWgfa5.mjs";
1
+ import { C as EmitterPagePayload, D as EmitterTrackPayload, S as EmitterOptions, b as EmitterIdentifyPayload, c as ProviderConfig, d as TrackingOptions, g as EmitterContext, i as AnalyticsProvider, n as AnalyticsContext, p as EmitterAliasPayload, r as AnalyticsManager, t as AnalyticsConfig, u as ProviderRegistry, v as EmitterGroupPayload, w as EmitterPayload } from "./types-cMMfHIpi.mjs";
2
+ import { a as screen, i as page, n as group, o as track, r as identify, t as alias } from "./emitters-BDSsleo_.mjs";
3
+ import { a as ContextBuilder, c as createAnonymousSession, d as isGroupPayload, f as isIdentifyPayload, g as withUTM, h as withMetadata, l as createUserSession, m as isTrackPayload, n as createMinimalBootstrapData, o as EventBatch, p as isPagePayload, r as generateDistinctId, s as PayloadBuilder, t as createBootstrapData, u as isAliasPayload } from "./posthog-bootstrap-Bu1BfhVv.mjs";
4
+ import { d as EcommerceEventSpec, m as OrderProperties, p as ExtendedProductProperties, r as CartProperties, t as BaseProductProperties } from "./types-DEcTnnFe.mjs";
5
+ import { t as index_d_exports } from "./index-BWhDEs8u.mjs";
6
+ import { a as createEmitterProcessor, i as validateConfig, n as createConfigBuilder, o as processEmitterPayload, r as getAnalyticsConfig, s as trackEcommerceEvent, t as PROVIDER_REQUIREMENTS } from "./config-Ciu7O6n1.mjs";
7
+ import { a as ConsoleConfig, c as PostHogConfig, i as SegmentOptions, l as PostHogOptions, n as VercelOptions, o as ConsoleOptions, r as SegmentConfig, s as BootstrapData, t as VercelConfig } from "./vercel-types-oM7Sn385.mjs";
8
+ import { n as createAnalyticsManager, t as AnalyticsManager$1 } from "./manager-OJpSKwqb.mjs";
9
+ import { a as createIngestionService, c as IngestionErrorResponse, d as validateAnalyticsConfig, f as validateConfigOrThrow, h as createServerAnalyticsUninitialized, i as IngestionServiceConfig, l as IngestionSuccessResponse, m as createServerAnalytics, n as IngestionMetrics, o as validateBatchPayload, p as validateProvider, r as IngestionService, s as validateEventPayload, t as IngestionContext, u as debugConfig } from "./index-DTvdqV7H.mjs";
10
10
  export { AnalyticsConfig, AnalyticsContext, AnalyticsManager, AnalyticsManager$1 as AnalyticsManagerClass, AnalyticsProvider, BaseProductProperties, BootstrapData, CartProperties, ConsoleConfig, ConsoleOptions, ContextBuilder, EcommerceEventSpec, EmitterAliasPayload, EmitterContext, EmitterGroupPayload, EmitterIdentifyPayload, EmitterOptions, EmitterPagePayload, EmitterPayload, EmitterTrackPayload, EventBatch, ExtendedProductProperties, type IngestionContext, type IngestionErrorResponse, type IngestionMetrics, IngestionService, type IngestionServiceConfig, type IngestionSuccessResponse, OrderProperties, PROVIDER_REQUIREMENTS, PayloadBuilder, PostHogConfig, PostHogOptions, ProviderConfig, ProviderRegistry, SegmentConfig, SegmentOptions, TrackingOptions, VercelConfig, VercelOptions, alias, createAnalyticsManager, createAnonymousSession, createBootstrapData, createConfigBuilder, createEmitterProcessor, createIngestionService, createMinimalBootstrapData, createServerAnalytics, createServerAnalyticsUninitialized, createUserSession, debugConfig, index_d_exports as ecommerce, generateDistinctId, getAnalyticsConfig, group, identify, isAliasPayload, isGroupPayload, isIdentifyPayload, isPagePayload, isTrackPayload, page, processEmitterPayload, screen, track, trackEcommerceEvent, validateAnalyticsConfig, validateBatchPayload, validateConfig, validateConfigOrThrow, validateEventPayload, validateProvider, withMetadata, withUTM };
package/server.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { _ as AnalyticsManager, a as ContextBuilder, c as createAnonymousSession, d as isGroupPayload, f as isIdentifyPayload, g as withUTM, h as withMetadata, l as createUserSession, m as isTrackPayload, n as createMinimalBootstrapData, o as EventBatch, p as isPagePayload, r as generateDistinctId, s as PayloadBuilder, t as createBootstrapData, u as isAliasPayload, v as createAnalyticsManager } from "./posthog-bootstrap-CYfIy_WS.mjs";
2
- import { a as screen, i as page, n as group, o as track, r as identify, t as alias } from "./emitters-6-nKo8i-.mjs";
3
- import { t as ecommerce_exports } from "./ecommerce-Cgu4wlux.mjs";
4
- import { a as createEmitterProcessor, i as validateConfig, n as createConfigBuilder, o as processEmitterPayload, r as getAnalyticsConfig, s as trackEcommerceEvent, t as PROVIDER_REQUIREMENTS } from "./config-P6P5adJg.mjs";
5
- import { a as debugConfig, c as validateProvider, i as validateEventPayload, l as createServerAnalytics, n as createIngestionService, o as validateAnalyticsConfig, r as validateBatchPayload, s as validateConfigOrThrow, t as IngestionService, u as createServerAnalyticsUninitialized } from "./service-Duqnlppl.mjs";
1
+ import { _ as AnalyticsManager, a as ContextBuilder, c as createAnonymousSession, d as isGroupPayload, f as isIdentifyPayload, g as withUTM, h as withMetadata, l as createUserSession, m as isTrackPayload, n as createMinimalBootstrapData, o as EventBatch, p as isPagePayload, r as generateDistinctId, s as PayloadBuilder, t as createBootstrapData, u as isAliasPayload, v as createAnalyticsManager } from "./posthog-bootstrap-DkPdn-hA.mjs";
2
+ import { a as screen, i as page, n as group, o as track, r as identify, t as alias } from "./emitters-BvEelkxS.mjs";
3
+ import { t as ecommerce_exports } from "./ecommerce-DGG1FbiH.mjs";
4
+ import { a as createEmitterProcessor, i as validateConfig, n as createConfigBuilder, o as processEmitterPayload, r as getAnalyticsConfig, s as trackEcommerceEvent, t as PROVIDER_REQUIREMENTS } from "./config-6Mwe7b2O.mjs";
5
+ import { a as debugConfig, c as validateProvider, i as validateEventPayload, l as createServerAnalytics, n as createIngestionService, o as validateAnalyticsConfig, r as validateBatchPayload, s as validateConfigOrThrow, t as IngestionService, u as createServerAnalyticsUninitialized } from "./service-NuHnv30x.mjs";
6
6
 
7
7
  export { AnalyticsManager as AnalyticsManagerClass, ContextBuilder, EventBatch, IngestionService, PROVIDER_REQUIREMENTS, PayloadBuilder, alias, createAnalyticsManager, createAnonymousSession, createBootstrapData, createConfigBuilder, createEmitterProcessor, createIngestionService, createMinimalBootstrapData, createServerAnalytics, createServerAnalyticsUninitialized, createUserSession, debugConfig, ecommerce_exports as ecommerce, generateDistinctId, getAnalyticsConfig, group, identify, isAliasPayload, isGroupPayload, isIdentifyPayload, isPagePayload, isTrackPayload, page, processEmitterPayload, screen, track, trackEcommerceEvent, validateAnalyticsConfig, validateBatchPayload, validateConfig, validateConfigOrThrow, validateEventPayload, validateProvider, withMetadata, withUTM };
@@ -1,117 +1,12 @@
1
- import { t as ConsoleProvider } from "./console-8bND3mMU.mjs";
2
- import { b as validateEventName, v as createAnalyticsManager, y as sanitizeProperties } from "./posthog-bootstrap-CYfIy_WS.mjs";
3
- import { t as PROVIDER_REQUIREMENTS } from "./config-P6P5adJg.mjs";
1
+ import { i as logWarn, n as logError, r as logInfo, t as logDebug } from "./core-DBLE5iTF.mjs";
2
+ import { t as ConsoleProvider } from "./console-BpU88FNF.mjs";
3
+ import { b as validateEventName, v as createAnalyticsManager, y as sanitizeProperties } from "./posthog-bootstrap-DkPdn-hA.mjs";
4
+ import { t as PROVIDER_REQUIREMENTS } from "./config-6Mwe7b2O.mjs";
4
5
  import { HttpServerProvider } from "./providers-http-server.mjs";
5
- import { logError, logInfo, logWarn } from "@od-oneapp/shared/logger";
6
- import { logDebug as logDebug$1, logError as logError$1, logInfo as logInfo$1, logWarn as logWarn$1 } from "@od-oneapp/shared/logs";
6
+ import { SegmentServerProvider } from "@od-oneapp/integration-segment/analytics-provider/server";
7
+ import { VercelServerProvider } from "@od-oneapp/integration-vercel/analytics-provider/server";
7
8
  import { z } from "zod";
8
9
 
9
- //#region ../../integrations/segment/src/analytics-provider/server.ts
10
- var SegmentServerProvider = class {
11
- name = "segment";
12
- analytics = null;
13
- config;
14
- isInitialized = false;
15
- constructor(config) {
16
- if (!config.writeKey) throw new Error("Segment writeKey is required");
17
- this.config = {
18
- options: config.options,
19
- writeKey: config.writeKey
20
- };
21
- }
22
- async initialize() {
23
- if (this.isInitialized) return;
24
- const { Analytics } = await import(
25
- /* webpackChunkName: "segment-analytics" */
26
- "@segment/analytics-next"
27
- );
28
- this.analytics = new Analytics({
29
- writeKey: this.config.writeKey,
30
- ...this.config.options
31
- });
32
- this.isInitialized = true;
33
- }
34
- async track(event, properties = {}, _context) {
35
- if (!this.analytics) return;
36
- await this.analytics.track({
37
- event,
38
- properties
39
- });
40
- }
41
- async identify(userId, traits = {}, _context) {
42
- if (!this.analytics) return;
43
- await this.analytics.identify({
44
- userId,
45
- traits
46
- });
47
- }
48
- async page(name, properties = {}, _context) {
49
- if (!this.analytics) return;
50
- await this.analytics.page({
51
- ...name && { name },
52
- properties
53
- });
54
- }
55
- async group(groupId, traits = {}, _context) {
56
- if (!this.analytics) return;
57
- await this.analytics.group({
58
- groupId,
59
- traits
60
- });
61
- }
62
- async alias(userId, previousId, _context) {
63
- if (!this.analytics) return;
64
- await this.analytics.alias({
65
- userId,
66
- previousId
67
- });
68
- }
69
- };
70
-
71
- //#endregion
72
- //#region ../../integrations/vercel/src/analytics-provider/server.ts
73
- var VercelServerProvider = class {
74
- name = "vercel";
75
- isInitialized = false;
76
- config;
77
- constructor(config) {
78
- this.config = config;
79
- }
80
- async initialize() {
81
- if (this.isInitialized) return;
82
- this.isInitialized = true;
83
- }
84
- async track(event, properties = {}) {
85
- if (!this.isInitialized) return;
86
- this.config;
87
- }
88
- async identify(userId, traits = {}) {
89
- await this.track("User Identified", {
90
- userId,
91
- ...traits
92
- });
93
- }
94
- async page(name, properties = {}) {
95
- await this.track("Page View (Server)", {
96
- page: name,
97
- ...properties
98
- });
99
- }
100
- async group(groupId, traits = {}) {
101
- await this.track("Group Identified", {
102
- groupId,
103
- ...traits
104
- });
105
- }
106
- async alias(userId, previousId) {
107
- await this.track("User Aliased", {
108
- previousId,
109
- userId
110
- });
111
- }
112
- };
113
-
114
- //#endregion
115
10
  //#region src/server/manager.ts
116
11
  /**
117
12
  * @fileoverview Server analytics manager with static provider registry
@@ -631,6 +526,20 @@ const EventResultSchema = z.object({
631
526
  error: z.string().optional()
632
527
  });
633
528
  /**
529
+ * Dispatch outcome for analytics forwarding.
530
+ */
531
+ const IngestionDispatchResultSchema = z.object({
532
+ scheduled: z.number().int().nonnegative(),
533
+ attempted: z.number().int().nonnegative(),
534
+ failed: z.number().int().nonnegative(),
535
+ status: z.enum([
536
+ "skipped",
537
+ "pending",
538
+ "completed",
539
+ "completed_with_failures"
540
+ ])
541
+ });
542
+ /**
634
543
  * Successful ingestion response schema.
635
544
  */
636
545
  const IngestionSuccessResponseSchema = z.object({
@@ -638,6 +547,7 @@ const IngestionSuccessResponseSchema = z.object({
638
547
  accepted: z.number().int().nonnegative(),
639
548
  rejected: z.number().int().nonnegative(),
640
549
  results: z.array(EventResultSchema),
550
+ dispatch: IngestionDispatchResultSchema.optional(),
641
551
  receivedAt: z.string().datetime()
642
552
  });
643
553
  /**
@@ -680,7 +590,8 @@ const DEFAULT_CONFIG = {
680
590
  stripPII: true,
681
591
  stripHTML: true,
682
592
  eventTimeout: 5e3,
683
- batchConcurrency: 10
593
+ batchConcurrency: 10,
594
+ awaitDispatch: false
684
595
  };
685
596
  /**
686
597
  * Generate a UUID v4.
@@ -901,7 +812,7 @@ var IngestionService = class {
901
812
  allowDangerousKeys: false
902
813
  });
903
814
  normalized.properties = sanitized.data;
904
- if (sanitized.warnings.length > 0) logDebug$1("Event properties sanitized", {
815
+ if (sanitized.warnings.length > 0) logDebug("Event properties sanitized", {
905
816
  eventId,
906
817
  warnings: sanitized.warnings
907
818
  });
@@ -931,31 +842,51 @@ var IngestionService = class {
931
842
  error: errorMessage
932
843
  });
933
844
  metrics.rejected++;
934
- logWarn$1("Event processing failed", {
845
+ logWarn("Event processing failed", {
935
846
  eventId,
936
847
  type: event.type,
937
848
  error: errorMessage
938
849
  });
939
850
  }
940
851
  }
941
- if (processedEvents.length > 0) (async () => {
852
+ const dispatch = {
853
+ scheduled: 0,
854
+ attempted: 0,
855
+ failed: 0,
856
+ status: processedEvents.length > 0 ? "pending" : "skipped"
857
+ };
858
+ const forwardEvents = async () => {
942
859
  try {
943
860
  await this.analyticsManager.emitBatch(processedEvents, {
944
861
  timeout: this.config.eventTimeout,
945
862
  concurrency: this.config.batchConcurrency,
946
863
  failFast: false
947
864
  });
865
+ if (this.config.awaitDispatch) {
866
+ dispatch.status = "completed";
867
+ dispatch.attempted = processedEvents.length;
868
+ }
948
869
  } catch (error) {
949
- logError$1("Failed to emit events to analytics manager", {
870
+ if (this.config.awaitDispatch) {
871
+ dispatch.status = "completed_with_failures";
872
+ dispatch.attempted = processedEvents.length;
873
+ dispatch.failed = processedEvents.length;
874
+ }
875
+ logError("Failed to emit events to analytics manager", {
950
876
  error: error instanceof Error ? error.message : "Unknown error",
951
877
  eventCount: processedEvents.length,
952
878
  traceId: context.traceId
953
879
  });
954
880
  }
955
- })();
881
+ };
882
+ if (processedEvents.length > 0) {
883
+ dispatch.scheduled = processedEvents.length;
884
+ if (this.config.awaitDispatch) await forwardEvents();
885
+ else forwardEvents();
886
+ }
956
887
  const endTime = process.hrtime.bigint();
957
888
  metrics.processingTimeMs = Number(endTime - startTime) / 1e6;
958
- logInfo$1("Event ingestion completed", {
889
+ logInfo("Event ingestion completed", {
959
890
  traceId: context.traceId,
960
891
  source: context.source,
961
892
  tenantId: context.tenantId,
@@ -970,6 +901,7 @@ var IngestionService = class {
970
901
  accepted: metrics.accepted,
971
902
  rejected: metrics.rejected,
972
903
  results,
904
+ dispatch,
973
905
  receivedAt
974
906
  };
975
907
  }
@@ -1046,4 +978,4 @@ function validateBatchPayload(payloads) {
1046
978
 
1047
979
  //#endregion
1048
980
  export { debugConfig as a, validateProvider as c, validateEventPayload as i, createServerAnalytics as l, createIngestionService as n, validateAnalyticsConfig as o, validateBatchPayload as r, validateConfigOrThrow as s, IngestionService as t, createServerAnalyticsUninitialized as u };
1049
- //# sourceMappingURL=service-Duqnlppl.mjs.map
981
+ //# sourceMappingURL=service-NuHnv30x.mjs.map