@od-oneapp/analytics 2026.1.1301
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +509 -0
- package/dist/ai-YMnynb-t.mjs +3347 -0
- package/dist/ai-YMnynb-t.mjs.map +1 -0
- package/dist/chunk-DQk6qfdC.mjs +18 -0
- package/dist/client-CTzJVFU5.mjs +9 -0
- package/dist/client-CTzJVFU5.mjs.map +1 -0
- package/dist/client-CcFTauAh.mjs +54 -0
- package/dist/client-CcFTauAh.mjs.map +1 -0
- package/dist/client-CeOLjbac.mjs +281 -0
- package/dist/client-CeOLjbac.mjs.map +1 -0
- package/dist/client-D339NFJS.mjs +267 -0
- package/dist/client-D339NFJS.mjs.map +1 -0
- package/dist/client-next.d.mts +62 -0
- package/dist/client-next.d.mts.map +1 -0
- package/dist/client-next.mjs +525 -0
- package/dist/client-next.mjs.map +1 -0
- package/dist/client.d.mts +30 -0
- package/dist/client.d.mts.map +1 -0
- package/dist/client.mjs +186 -0
- package/dist/client.mjs.map +1 -0
- package/dist/config-DPS6bSYo.d.mts +34 -0
- package/dist/config-DPS6bSYo.d.mts.map +1 -0
- package/dist/config-P6P5adJg.mjs +287 -0
- package/dist/config-P6P5adJg.mjs.map +1 -0
- package/dist/console-8bND3mMU.mjs +128 -0
- package/dist/console-8bND3mMU.mjs.map +1 -0
- package/dist/ecommerce-Cgu4wlux.mjs +993 -0
- package/dist/ecommerce-Cgu4wlux.mjs.map +1 -0
- package/dist/emitters-6-nKo8i-.mjs +208 -0
- package/dist/emitters-6-nKo8i-.mjs.map +1 -0
- package/dist/emitters-DldkVSPp.d.mts +12 -0
- package/dist/emitters-DldkVSPp.d.mts.map +1 -0
- package/dist/index-BfNWgfa5.d.mts +1494 -0
- package/dist/index-BfNWgfa5.d.mts.map +1 -0
- package/dist/index-BkIWe--N.d.mts +953 -0
- package/dist/index-BkIWe--N.d.mts.map +1 -0
- package/dist/index-jPzXRn52.d.mts +184 -0
- package/dist/index-jPzXRn52.d.mts.map +1 -0
- package/dist/manager-DvRRjza6.d.mts +76 -0
- package/dist/manager-DvRRjza6.d.mts.map +1 -0
- package/dist/posthog-bootstrap-CYfIy_WS.mjs +1769 -0
- package/dist/posthog-bootstrap-CYfIy_WS.mjs.map +1 -0
- package/dist/posthog-bootstrap-DWxFrxlt.d.mts +81 -0
- package/dist/posthog-bootstrap-DWxFrxlt.d.mts.map +1 -0
- package/dist/providers-http-client.d.mts +37 -0
- package/dist/providers-http-client.d.mts.map +1 -0
- package/dist/providers-http-client.mjs +320 -0
- package/dist/providers-http-client.mjs.map +1 -0
- package/dist/providers-http-server.d.mts +31 -0
- package/dist/providers-http-server.d.mts.map +1 -0
- package/dist/providers-http-server.mjs +297 -0
- package/dist/providers-http-server.mjs.map +1 -0
- package/dist/providers-http.d.mts +46 -0
- package/dist/providers-http.d.mts.map +1 -0
- package/dist/providers-http.mjs +4 -0
- package/dist/server-edge.d.mts +9 -0
- package/dist/server-edge.d.mts.map +1 -0
- package/dist/server-edge.mjs +373 -0
- package/dist/server-edge.mjs.map +1 -0
- package/dist/server-next.d.mts +67 -0
- package/dist/server-next.d.mts.map +1 -0
- package/dist/server-next.mjs +193 -0
- package/dist/server-next.mjs.map +1 -0
- package/dist/server.d.mts +10 -0
- package/dist/server.mjs +7 -0
- package/dist/service-cYtBBL8x.mjs +945 -0
- package/dist/service-cYtBBL8x.mjs.map +1 -0
- package/dist/shared.d.mts +16 -0
- package/dist/shared.d.mts.map +1 -0
- package/dist/shared.mjs +93 -0
- package/dist/shared.mjs.map +1 -0
- package/dist/types-BxBnNQ0V.d.mts +354 -0
- package/dist/types-BxBnNQ0V.d.mts.map +1 -0
- package/dist/types-CBvxUEaF.d.mts +216 -0
- package/dist/types-CBvxUEaF.d.mts.map +1 -0
- package/dist/types.d.mts +4 -0
- package/dist/types.mjs +0 -0
- package/dist/vercel-types-lwakUfoI.d.mts +102 -0
- package/dist/vercel-types-lwakUfoI.d.mts.map +1 -0
- package/package.json +129 -0
- package/src/client/index.ts +164 -0
- package/src/client/manager.ts +71 -0
- package/src/client/next/components.tsx +270 -0
- package/src/client/next/hooks.ts +217 -0
- package/src/client/next/manager.ts +141 -0
- package/src/client/next.ts +144 -0
- package/src/client-next.ts +101 -0
- package/src/client.ts +89 -0
- package/src/examples/ai-sdk-patterns.ts +583 -0
- package/src/examples/emitter-patterns.ts +476 -0
- package/src/examples/nextjs-emitter-patterns.tsx +403 -0
- package/src/next/app-router.tsx +564 -0
- package/src/next/client.ts +419 -0
- package/src/next/index.ts +84 -0
- package/src/next/middleware.ts +429 -0
- package/src/next/rsc.tsx +300 -0
- package/src/next/server.ts +253 -0
- package/src/next/types.d.ts +220 -0
- package/src/providers/base-provider.ts +419 -0
- package/src/providers/console/client.ts +10 -0
- package/src/providers/console/index.ts +152 -0
- package/src/providers/console/server.ts +6 -0
- package/src/providers/console/types.ts +15 -0
- package/src/providers/http/client.ts +464 -0
- package/src/providers/http/index.ts +30 -0
- package/src/providers/http/server.ts +396 -0
- package/src/providers/http/types.ts +135 -0
- package/src/providers/posthog/client.ts +518 -0
- package/src/providers/posthog/index.ts +11 -0
- package/src/providers/posthog/server.ts +329 -0
- package/src/providers/posthog/types.ts +104 -0
- package/src/providers/segment/client.ts +113 -0
- package/src/providers/segment/index.ts +11 -0
- package/src/providers/segment/server.ts +115 -0
- package/src/providers/segment/types.ts +51 -0
- package/src/providers/vercel/client.ts +102 -0
- package/src/providers/vercel/index.ts +11 -0
- package/src/providers/vercel/server.ts +89 -0
- package/src/providers/vercel/types.ts +27 -0
- package/src/server/index.ts +103 -0
- package/src/server/manager.ts +62 -0
- package/src/server/next.ts +210 -0
- package/src/server-edge.ts +442 -0
- package/src/server-next.ts +39 -0
- package/src/server.ts +106 -0
- package/src/shared/emitters/ai/README.md +981 -0
- package/src/shared/emitters/ai/events/agent.ts +130 -0
- package/src/shared/emitters/ai/events/artifacts.ts +167 -0
- package/src/shared/emitters/ai/events/chat.ts +126 -0
- package/src/shared/emitters/ai/events/chatbot-ecommerce.ts +133 -0
- package/src/shared/emitters/ai/events/completion.ts +103 -0
- package/src/shared/emitters/ai/events/content-generation.ts +347 -0
- package/src/shared/emitters/ai/events/conversation.ts +332 -0
- package/src/shared/emitters/ai/events/product-features.ts +1402 -0
- package/src/shared/emitters/ai/events/streaming.ts +114 -0
- package/src/shared/emitters/ai/events/tool.ts +93 -0
- package/src/shared/emitters/ai/index.ts +69 -0
- package/src/shared/emitters/ai/track-ai-sdk.ts +74 -0
- package/src/shared/emitters/ai/track-ai.ts +50 -0
- package/src/shared/emitters/ai/types.ts +1041 -0
- package/src/shared/emitters/ai/utils.ts +468 -0
- package/src/shared/emitters/ecommerce/events/cart-checkout.ts +106 -0
- package/src/shared/emitters/ecommerce/events/coupon.ts +49 -0
- package/src/shared/emitters/ecommerce/events/engagement.ts +61 -0
- package/src/shared/emitters/ecommerce/events/marketplace.ts +119 -0
- package/src/shared/emitters/ecommerce/events/order.ts +199 -0
- package/src/shared/emitters/ecommerce/events/product.ts +205 -0
- package/src/shared/emitters/ecommerce/events/registry.ts +123 -0
- package/src/shared/emitters/ecommerce/events/wishlist-sharing.ts +140 -0
- package/src/shared/emitters/ecommerce/index.ts +46 -0
- package/src/shared/emitters/ecommerce/track-ecommerce.ts +53 -0
- package/src/shared/emitters/ecommerce/types.ts +314 -0
- package/src/shared/emitters/ecommerce/utils.ts +216 -0
- package/src/shared/emitters/emitter-types.ts +974 -0
- package/src/shared/emitters/emitters.ts +292 -0
- package/src/shared/emitters/helpers.ts +419 -0
- package/src/shared/emitters/index.ts +66 -0
- package/src/shared/index.ts +142 -0
- package/src/shared/ingestion/index.ts +66 -0
- package/src/shared/ingestion/schemas.ts +386 -0
- package/src/shared/ingestion/service.ts +628 -0
- package/src/shared/node22-features.ts +848 -0
- package/src/shared/providers/console-provider.ts +160 -0
- package/src/shared/types/base-types.ts +54 -0
- package/src/shared/types/console-types.ts +19 -0
- package/src/shared/types/posthog-types.ts +131 -0
- package/src/shared/types/segment-types.ts +15 -0
- package/src/shared/types/types.ts +397 -0
- package/src/shared/types/vercel-types.ts +19 -0
- package/src/shared/utils/config-client.ts +19 -0
- package/src/shared/utils/config.ts +250 -0
- package/src/shared/utils/emitter-adapter.ts +212 -0
- package/src/shared/utils/manager.test.ts +36 -0
- package/src/shared/utils/manager.ts +1322 -0
- package/src/shared/utils/posthog-bootstrap.ts +136 -0
- package/src/shared/utils/posthog-client-utils.ts +48 -0
- package/src/shared/utils/posthog-next-utils.ts +282 -0
- package/src/shared/utils/posthog-server-utils.ts +210 -0
- package/src/shared/utils/rate-limit.ts +289 -0
- package/src/shared/utils/security.ts +545 -0
- package/src/shared/utils/validation-client.ts +161 -0
- package/src/shared/utils/validation.ts +399 -0
- package/src/shared.ts +155 -0
- package/src/types/index.ts +62 -0
|
@@ -0,0 +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":";;;;;;;;;;;;;;;;;;AA6BA,MAAM,WAAW;CACf,WAAW;CACX,eAAe;CACf,SAAS;CACT,SAAS;CACV;;AAGD,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;AAqBxB,IAAa,qBAAb,MAA6D;CAC3D,AAAS,OAAO;CAEhB,AAAQ;CAIR,AAAQ,gBAAgB;CACxB,AAAQ,QAAuB,EAAE;CACjC,AAAQ,aAAoD;CAC5D,AAAQ;CACR,AAAQ;CACR,AAAQ,aAAa;CAErB,YAAY,gBAAgC;EAC1C,MAAM,UAAW,eAAe,WAAW,EAAE;AAE7C,MAAI,CAAC,QAAQ,SACX,OAAM,IAAI,MAAM,wCAAwC;AAG1D,OAAK,SAAS;GACZ,GAAG;GACH,WAAW,QAAQ,aAAa,SAAS;GACzC,eAAe,QAAQ,iBAAiB,SAAS;GACjD,SAAS,QAAQ,WAAW,SAAS;GACrC,SAAS,QAAQ,WAAW,SAAS;GACtC;AAED,OAAK,SAAS,QAAQ;AACtB,OAAK,cAAc,QAAQ,eAAe,KAAK,qBAAqB;;CAGtE,MAAM,aAA4B;AAChC,MAAI,KAAK,cAAe;AAGxB,MAAI,KAAK,OAAO,gBAAgB,GAAG;AACjC,QAAK,aAAa,kBAAkB;AAClC,IAAK,KAAK,OAAO;MAChB,KAAK,OAAO,cAAc;AAG7B,OAAI,OAAO,KAAK,WAAW,UAAU,WACnC,MAAK,WAAW,OAAO;;AAI3B,MAAI,KAAK,OAAO,MACd,UAAS,uCAAuC;GAC9C,UAAU;GACV,UAAU,KAAK,OAAO;GACtB,WAAW,KAAK,OAAO;GACvB,eAAe,KAAK,OAAO;GAC5B,CAAC;AAGJ,OAAK,gBAAgB;;CAGvB,MAAM,MACJ,OACA,aAAyB,EAAE,EAC3B,UACe;AACf,MAAI,CAAC,KAAK,eAAe;AACvB,WAAQ,iCAAiC;IAAE,UAAU;IAAQ,WAAW;IAAS;IAAO,CAAC;AACzF;;AAGF,OAAK,QAAQ;GACX,MAAM;GACN;GACA;GACA,4BAAW,IAAI,MAAM,EAAC,aAAa;GACnC,QAAQ,KAAK;GACb,aAAa,KAAK;GACnB,CAAC;;CAGJ,MAAM,SACJ,QACA,SAAqB,EAAE,EACvB,UACe;AACf,MAAI,CAAC,KAAK,eAAe;AACvB,WAAQ,iCAAiC;IAAE,UAAU;IAAQ,WAAW;IAAY;IAAQ,CAAC;AAC7F;;AAIF,OAAK,SAAS;AAEd,OAAK,QAAQ;GACX,MAAM;GACN;GACA;GACA,4BAAW,IAAI,MAAM,EAAC,aAAa;GACnC,aAAa,KAAK;GACnB,CAAC;;CAGJ,MAAM,KACJ,MACA,aAA6B,EAAE,EAC/B,UACe;AACf,MAAI,CAAC,KAAK,eAAe;AACvB,WAAQ,iCAAiC;IAAE,UAAU;IAAQ,WAAW;IAAQ;IAAM,CAAC;AACvF;;AAGF,OAAK,QAAQ;GACX,MAAM;GACN;GACA;GACA,4BAAW,IAAI,MAAM,EAAC,aAAa;GACnC,QAAQ,KAAK;GACb,aAAa,KAAK;GACnB,CAAC;;CAGJ,MAAM,MACJ,SACA,SAAsB,EAAE,EACxB,UACe;AACf,MAAI,CAAC,KAAK,eAAe;AACvB,WAAQ,iCAAiC;IAAE,UAAU;IAAQ,WAAW;IAAS;IAAS,CAAC;AAC3F;;AAGF,OAAK,QAAQ;GACX,MAAM;GACN;GACA;GACA,4BAAW,IAAI,MAAM,EAAC,aAAa;GACnC,QAAQ,KAAK;GACb,aAAa,KAAK;GACnB,CAAC;;CAGJ,MAAM,MAAM,QAAgB,YAAoB,UAA4C;AAC1F,MAAI,CAAC,KAAK,eAAe;AACvB,WAAQ,iCAAiC;IACvC,UAAU;IACV,WAAW;IACX;IACA;IACD,CAAC;AACF;;AAGF,OAAK,QAAQ;GACX,MAAM;GACN;GACA;GACA,4BAAW,IAAI,MAAM,EAAC,aAAa;GACnC,aAAa,KAAK;GACnB,CAAC;;;;;;CAOJ,MAAM,QAAuB;AAC3B,MAAI,KAAK,MAAM,WAAW,KAAK,KAAK,WAAY;AAEhD,OAAK,aAAa;EAGlB,MAAM,SAAS,CAAC,GAAG,KAAK,MAAM;AAC9B,OAAK,QAAQ,EAAE;AAEf,MAAI;AACF,SAAM,KAAK,UAAU,OAAO;WACrB,OAAO;AAEd,QAAK,MAAM,QAAQ,GAAG,OAAO;AAC7B,YAAS,+CAA+C;IACtD,UAAU;IACV,YAAY,OAAO;IACnB,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC9D,CAAC;YACM;AACR,QAAK,aAAa;;;;;;;CAQtB,MAAM,WAA0B;AAC9B,MAAI,KAAK,YAAY;AACnB,iBAAc,KAAK,WAAW;AAC9B,QAAK,aAAa;;AAIpB,QAAM,KAAK,OAAO;AAClB,OAAK,gBAAgB;;;;;CAMvB,iBAAyB;AACvB,SAAO,KAAK,MAAM;;CAOpB,AAAQ,QAAQ,OAA0B;AACxC,OAAK,MAAM,KAAK,MAAM;AAEtB,MAAI,KAAK,OAAO,MACd,UAAS,gBAAgB;GACvB,UAAU;GACV,MAAM,MAAM;GACZ,aAAa,KAAK,MAAM;GACzB,CAAC;AAIJ,MAAI,KAAK,MAAM,UAAU,KAAK,OAAO,UACnC,CAAK,KAAK,OAAO;;CAIrB,MAAc,UAAU,QAAsC;EAC5D,MAAM,UAAU,EAAE,OAAO,QAAQ;EAEjC,IAAI,YAA0B;AAE9B,OAAK,IAAI,UAAU,GAAG,WAAW,KAAK,OAAO,SAAS,UACpD,KAAI;GACF,MAAM,WAAW,MAAM,KAAK,YAAY,QAAQ;AAEhD,OAAI,SAAS,SAAS;AACpB,QAAI,KAAK,OAAO,MACd,UAAS,2BAA2B;KAClC,UAAU;KACV,UAAU,SAAS;KACnB,UAAU,SAAS;KACpB,CAAC;AAEJ;;AAIF,WAAQ,4BAA4B;IAClC,UAAU;IACV,UAAU,SAAS;IACnB,UAAU,SAAS;IACnB,OAAO,SAAS;IACjB,CAAC;AACF;WACO,OAAO;AACd,eAAY,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC;AAErE,OAAI,UAAU,KAAK,OAAO,SAAS;IAEjC,MAAM,QAAQ,kBAAkB,KAAK,IAAI,GAAG,QAAQ;AAEpD,QAAI,KAAK,OAAO,MACd,UAAS,uBAAuB;KAC9B,UAAU;KACV,SAAS,UAAU;KACnB,YAAY,KAAK,OAAO;KACxB,SAAS;KACV,CAAC;AAGJ,UAAM,KAAK,MAAM,MAAM;;;AAM7B,QAAM,6BAAa,IAAI,MAAM,qCAAqC;;CAGpE,MAAc,YAAY,SAA+D;EACvF,MAAM,UAAkC;GACtC,gBAAgB;GAChB,GAAG,KAAK,OAAO;GAChB;AAED,MAAI,KAAK,OAAO,OACd,SAAQ,eAAe,KAAK,OAAO;EAGrC,MAAM,aAAa,IAAI,iBAAiB;EACxC,MAAM,YAAY,iBAAiB,WAAW,OAAO,EAAE,KAAK,OAAO,QAAQ;AAE3E,MAAI;GACF,MAAM,WAAW,MAAM,MAAM,KAAK,OAAO,UAAU;IACjD,QAAQ;IACR;IACA,MAAM,KAAK,UAAU,QAAQ;IAC7B,QAAQ,WAAW;IACpB,CAAC;AAEF,OAAI,CAAC,SAAS,IAAI;AAEhB,QAAI,SAAS,WAAW,KAAK;KAC3B,MAAM,aAAa,SAAS,QAAQ,IAAI,cAAc;AACtD,WAAM,IAAI,MAAM,6BAA6B,cAAc,UAAU,UAAU;;IAGjF,MAAM,YAAY,MAAM,SAAS,MAAM;AACvC,UAAM,IAAI,MAAM,QAAQ,SAAS,OAAO,IAAI,YAAY;;AAG1D,UAAQ,MAAM,SAAS,MAAM;YACrB;AACR,gBAAa,UAAU;;;CAI3B,AAAQ,sBAA8B;AAEpC,MAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,WAChE,QAAO,OAAO,YAAY;AAI5B,SAAO,QAAQ,KAAK,KAAK,CAAC,SAAS,GAAG,GAAG,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,MAAM,GAAG,EAAE;;CAGjF,AAAQ,MAAM,IAA2B;AACvC,SAAO,IAAI,SAAQ,YAAW,WAAW,SAAS,GAAG,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { HttpClientProvider } from "./providers-http-client.mjs";
|
|
2
|
+
import { HttpServerProvider } from "./providers-http-server.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/providers/http/types.d.ts
|
|
5
|
+
interface HttpProviderConfig {
|
|
6
|
+
endpoint: string;
|
|
7
|
+
apiKey?: string;
|
|
8
|
+
batchSize?: number;
|
|
9
|
+
flushInterval?: number;
|
|
10
|
+
timeout?: number;
|
|
11
|
+
retries?: number;
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
debug?: boolean;
|
|
14
|
+
userId?: string;
|
|
15
|
+
anonymousId?: string;
|
|
16
|
+
}
|
|
17
|
+
interface QueuedEvent {
|
|
18
|
+
type: 'track' | 'identify' | 'page' | 'screen' | 'group' | 'alias';
|
|
19
|
+
timestamp: string;
|
|
20
|
+
userId?: string;
|
|
21
|
+
anonymousId?: string;
|
|
22
|
+
event?: string;
|
|
23
|
+
properties?: Record<string, unknown>;
|
|
24
|
+
traits?: Record<string, unknown>;
|
|
25
|
+
name?: string;
|
|
26
|
+
category?: string;
|
|
27
|
+
groupId?: string;
|
|
28
|
+
previousId?: string;
|
|
29
|
+
}
|
|
30
|
+
interface IngestionResponse {
|
|
31
|
+
success: boolean;
|
|
32
|
+
accepted?: number;
|
|
33
|
+
rejected?: number;
|
|
34
|
+
results?: Array<{
|
|
35
|
+
id: string;
|
|
36
|
+
type: string;
|
|
37
|
+
status: 'accepted' | 'rejected';
|
|
38
|
+
error?: string;
|
|
39
|
+
}>;
|
|
40
|
+
receivedAt?: string;
|
|
41
|
+
error?: string;
|
|
42
|
+
code?: string;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { HttpClientProvider, HttpServerProvider as HttpProvider, HttpServerProvider, type HttpProviderConfig, type IngestionResponse, type QueuedEvent };
|
|
46
|
+
//# sourceMappingURL=providers-http.d.mts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
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";
|
|
4
|
+
|
|
5
|
+
//#region src/server-edge.d.ts
|
|
6
|
+
declare function createServerAnalytics(config?: AnalyticsConfig): Promise<AnalyticsManager>;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { AnalyticsConfig, AnalyticsContext, AnalyticsEmitter, AnalyticsManager, AnalyticsProvider, EcommerceEventSpec, EmitterAliasPayload, EmitterBasePayload, EmitterConfig, EmitterContext, EmitterEventProperties, EmitterGroupPayload, EmitterGroupTraits, EmitterIdentifyPayload, EmitterIntegrations, EmitterOptions, EmitterPagePayload, EmitterPayload, EmitterProduct, EmitterScreenPayload, EmitterTrackPayload, EmitterUserTraits, ErrorContext, GroupTraits, IntegrationConfig, PageProperties, PostHogBootstrap, Properties, PropertyObject, PropertyValue, ProviderConfig, ProviderFactory, ProviderRegistry, TrackingOptions, UserTraits, alias, createEmitterProcessor, createServerAnalytics, getAnalyticsConfig, group, identify, page, track };
|
|
9
|
+
//# sourceMappingURL=server-edge.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-edge.d.mts","names":[],"sources":["../src/server-edge.ts"],"mappings":";;;;;iBAkHsB,qBAAA,CACpB,MAAA,GAAQ,eAAA,GACP,OAAA,CAAQ,gBAAA"}
|
|
@@ -0,0 +1,373 @@
|
|
|
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";
|
|
4
|
+
import { createEnv } from "@t3-oss/env-core";
|
|
5
|
+
import { z } from "zod/v4";
|
|
6
|
+
|
|
7
|
+
//#region env.ts
|
|
8
|
+
/**
|
|
9
|
+
* @fileoverview Environment variable configuration for analytics package
|
|
10
|
+
* Environment variable configuration for analytics package
|
|
11
|
+
*/
|
|
12
|
+
const env = createEnv({
|
|
13
|
+
server: {
|
|
14
|
+
POSTHOG_HOST: z.string().url().default("https://app.posthog.com"),
|
|
15
|
+
POSTHOG_KEY: z.string().optional(),
|
|
16
|
+
POSTHOG_API_KEY: z.string().optional(),
|
|
17
|
+
POSTHOG_PERSONAL_API_KEY: z.string().optional(),
|
|
18
|
+
POSTHOG_PROJECT_ID: z.string().optional(),
|
|
19
|
+
SEGMENT_WRITE_KEY: z.string().optional(),
|
|
20
|
+
ANALYTICS_LOG_PROVIDER: z.enum(["console", "sentry"]).default("console"),
|
|
21
|
+
NODE_ENV: z.enum([
|
|
22
|
+
"development",
|
|
23
|
+
"test",
|
|
24
|
+
"production"
|
|
25
|
+
]).default("development"),
|
|
26
|
+
APP_ENV: z.enum([
|
|
27
|
+
"development",
|
|
28
|
+
"staging",
|
|
29
|
+
"production"
|
|
30
|
+
]).optional(),
|
|
31
|
+
NEXT_RUNTIME: z.enum(["nodejs", "edge"]).optional()
|
|
32
|
+
},
|
|
33
|
+
clientPrefix: "NEXT_PUBLIC_",
|
|
34
|
+
client: {
|
|
35
|
+
NEXT_PUBLIC_POSTHOG_HOST: z.string().url().default("https://app.posthog.com"),
|
|
36
|
+
NEXT_PUBLIC_POSTHOG_KEY: z.string().optional(),
|
|
37
|
+
NEXT_PUBLIC_SEGMENT_WRITE_KEY: z.string().optional(),
|
|
38
|
+
NEXT_PUBLIC_VERCEL_ANALYTICS_ID: z.string().optional(),
|
|
39
|
+
NEXT_PUBLIC_APP_ENV: z.enum([
|
|
40
|
+
"development",
|
|
41
|
+
"staging",
|
|
42
|
+
"production"
|
|
43
|
+
]).optional(),
|
|
44
|
+
NEXT_PUBLIC_NODE_ENV: z.enum([
|
|
45
|
+
"development",
|
|
46
|
+
"test",
|
|
47
|
+
"production"
|
|
48
|
+
]).default("development")
|
|
49
|
+
},
|
|
50
|
+
runtimeEnv: process.env,
|
|
51
|
+
emptyStringAsUndefined: true,
|
|
52
|
+
onInvalidAccess: (variable) => {
|
|
53
|
+
throw new Error(`❌ Attempted to access a server-side environment variable on the client: ${variable}`);
|
|
54
|
+
},
|
|
55
|
+
onValidationError: (error) => {
|
|
56
|
+
logWarn("Analytics environment validation failed:", { error: String(error) });
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/server-edge.ts
|
|
62
|
+
/**
|
|
63
|
+
* @fileoverview Edge Runtime Analytics Module
|
|
64
|
+
*
|
|
65
|
+
* Provides edge-compatible analytics for Next.js middleware and edge API routes.
|
|
66
|
+
* Uses Web APIs and HTTP-based implementations compatible with edge runtime.
|
|
67
|
+
*
|
|
68
|
+
* **Supported Features**:
|
|
69
|
+
* - Basic event tracking (track, identify, page, group, alias)
|
|
70
|
+
* - Console provider (uses console API)
|
|
71
|
+
* - PostHog provider (HTTP-based, no SDK dependency)
|
|
72
|
+
* - Emitter pattern support via `emit()`
|
|
73
|
+
*
|
|
74
|
+
* **Limitations (Edge Runtime Constraints)**:
|
|
75
|
+
* - No Node.js APIs (fs, crypto, etc.)
|
|
76
|
+
* - No native modules or SDK dependencies
|
|
77
|
+
* - No event deduplication (no LRU cache)
|
|
78
|
+
* - No rate limiting (100 req/s limit not enforced)
|
|
79
|
+
* - No batch processing optimization
|
|
80
|
+
* - No performance metrics tracking
|
|
81
|
+
* - No feature flags (PostHog flags require server SDK)
|
|
82
|
+
* - Context is per-request only (not persisted)
|
|
83
|
+
*
|
|
84
|
+
* **For full analytics features**, use `@od-oneapp/analytics/server` in Node.js environments.
|
|
85
|
+
*
|
|
86
|
+
* **Usage**: Import from `@od-oneapp/analytics/server/edge` for Next.js middleware and edge API routes.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* // In Next.js middleware
|
|
91
|
+
* import { createServerAnalytics, track } from '@od-oneapp/analytics/server/edge';
|
|
92
|
+
*
|
|
93
|
+
* export async function middleware(request: NextRequest) {
|
|
94
|
+
* const analytics = await createServerAnalytics({
|
|
95
|
+
* providers: {
|
|
96
|
+
* posthog: { apiKey: process.env.POSTHOG_API_KEY }
|
|
97
|
+
* }
|
|
98
|
+
* });
|
|
99
|
+
*
|
|
100
|
+
* await analytics.emit(track('Middleware Hit', { path: request.nextUrl.pathname }));
|
|
101
|
+
* return NextResponse.next();
|
|
102
|
+
* }
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* @module @od-oneapp/analytics/server/edge
|
|
106
|
+
*/
|
|
107
|
+
const defaultConfig = { providers: {} };
|
|
108
|
+
/**
|
|
109
|
+
* Creates an edge-compatible analytics manager.
|
|
110
|
+
*
|
|
111
|
+
* This is a simplified implementation optimized for edge runtime constraints.
|
|
112
|
+
* It provides basic analytics functionality without Node.js-specific features.
|
|
113
|
+
*
|
|
114
|
+
* **Supported Providers**:
|
|
115
|
+
* - Console (always available)
|
|
116
|
+
* - PostHog (HTTP-based, requires API key)
|
|
117
|
+
*
|
|
118
|
+
* **Not Supported in Edge**:
|
|
119
|
+
* - Segment SDK (requires Node.js)
|
|
120
|
+
* - Vercel Analytics SDK (requires Node.js)
|
|
121
|
+
* - Rate limiting
|
|
122
|
+
* - Event deduplication
|
|
123
|
+
* - Batch processing optimization
|
|
124
|
+
*
|
|
125
|
+
* @param {AnalyticsConfig} [config] - Analytics configuration with provider settings
|
|
126
|
+
* @returns {Promise<AnalyticsManager>} Promise resolving to AnalyticsManager instance
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* const analytics = await createServerAnalytics({
|
|
131
|
+
* providers: {
|
|
132
|
+
* posthog: { apiKey: process.env.POSTHOG_API_KEY }
|
|
133
|
+
* }
|
|
134
|
+
* });
|
|
135
|
+
*
|
|
136
|
+
* await analytics.track('Event Name', { property: 'value' });
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
async function createServerAnalytics(config = defaultConfig) {
|
|
140
|
+
const providers = [];
|
|
141
|
+
let context = {};
|
|
142
|
+
if (config.providers.console) {
|
|
143
|
+
const { ConsoleProvider } = await import("./console-8bND3mMU.mjs").then((n) => n.n);
|
|
144
|
+
const consoleProvider = new ConsoleProvider(config.providers.console);
|
|
145
|
+
await consoleProvider.initialize();
|
|
146
|
+
providers.push(consoleProvider);
|
|
147
|
+
}
|
|
148
|
+
if (config.providers.posthog?.apiKey) {
|
|
149
|
+
const posthogProvider = createPostHogEdgeProvider(config);
|
|
150
|
+
providers.push(posthogProvider);
|
|
151
|
+
}
|
|
152
|
+
const processPayload = async (payload) => {
|
|
153
|
+
switch (payload.type) {
|
|
154
|
+
case "track": {
|
|
155
|
+
const p = payload;
|
|
156
|
+
await Promise.allSettled(providers.map((provider) => provider.track(p.event, p.properties ?? {}, {
|
|
157
|
+
...context,
|
|
158
|
+
...p.context
|
|
159
|
+
})));
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
case "identify": {
|
|
163
|
+
const p = payload;
|
|
164
|
+
await Promise.allSettled(providers.map((provider) => provider.identify?.(p.userId, p.traits ?? {}, {
|
|
165
|
+
...context,
|
|
166
|
+
...p.context
|
|
167
|
+
})));
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
case "page": {
|
|
171
|
+
const p = payload;
|
|
172
|
+
await Promise.allSettled(providers.map((provider) => provider.page?.(p.name ?? "", p.properties ?? {}, {
|
|
173
|
+
...context,
|
|
174
|
+
...p.context
|
|
175
|
+
})));
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
case "screen": {
|
|
179
|
+
const p = payload;
|
|
180
|
+
await Promise.allSettled(providers.map((provider) => provider.screen?.(p.name ?? "", p.properties ?? {}, {
|
|
181
|
+
...context,
|
|
182
|
+
...p.context
|
|
183
|
+
})));
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
case "group": {
|
|
187
|
+
const p = payload;
|
|
188
|
+
await Promise.allSettled(providers.map((provider) => provider.group?.(p.groupId, p.traits ?? {}, {
|
|
189
|
+
...context,
|
|
190
|
+
...p.context
|
|
191
|
+
})));
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
case "alias": {
|
|
195
|
+
const p = payload;
|
|
196
|
+
await Promise.allSettled(providers.map((provider) => provider.alias?.(p.userId, p.previousId, {
|
|
197
|
+
...context,
|
|
198
|
+
...p.context
|
|
199
|
+
})));
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
function createEmitterFunction(payload) {
|
|
205
|
+
return processPayload(payload);
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
getContext: () => ({ ...context }),
|
|
209
|
+
initialize: async () => {},
|
|
210
|
+
setContext: (newContext) => {
|
|
211
|
+
context = {
|
|
212
|
+
...context,
|
|
213
|
+
...newContext
|
|
214
|
+
};
|
|
215
|
+
},
|
|
216
|
+
createEmitter: () => createEmitterFunction,
|
|
217
|
+
emit: async (payload) => {
|
|
218
|
+
await processPayload(payload);
|
|
219
|
+
},
|
|
220
|
+
emitBatch: async (payloads) => {
|
|
221
|
+
for (const payload of payloads) await processPayload(payload);
|
|
222
|
+
},
|
|
223
|
+
track: async (eventOrPayload, properties) => {
|
|
224
|
+
if (typeof eventOrPayload === "object") await processPayload(eventOrPayload);
|
|
225
|
+
else if (typeof eventOrPayload === "string") await Promise.allSettled(providers.map((p) => p.track(eventOrPayload, properties ?? {}, context)));
|
|
226
|
+
},
|
|
227
|
+
identify: async (userIdOrPayload, traits) => {
|
|
228
|
+
if (typeof userIdOrPayload === "object") await processPayload(userIdOrPayload);
|
|
229
|
+
else if (typeof userIdOrPayload === "string") await Promise.allSettled(providers.map((p) => p.identify?.(userIdOrPayload, traits ?? {}, context)));
|
|
230
|
+
},
|
|
231
|
+
page: async (nameOrPayload, properties) => {
|
|
232
|
+
if (typeof nameOrPayload === "object") await processPayload(nameOrPayload);
|
|
233
|
+
else {
|
|
234
|
+
const pageName = typeof nameOrPayload === "string" ? nameOrPayload : "";
|
|
235
|
+
await Promise.allSettled(providers.map((p) => p.page?.(pageName, properties ?? {}, context)));
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
group: async (groupIdOrPayload, traits) => {
|
|
239
|
+
if (typeof groupIdOrPayload === "object") await processPayload(groupIdOrPayload);
|
|
240
|
+
else if (typeof groupIdOrPayload === "string") await Promise.allSettled(providers.map((p) => p.group?.(groupIdOrPayload, traits ?? {}, context)));
|
|
241
|
+
},
|
|
242
|
+
alias: async (userIdOrPayload, previousId) => {
|
|
243
|
+
if (typeof userIdOrPayload === "object") await processPayload(userIdOrPayload);
|
|
244
|
+
else if (typeof userIdOrPayload === "string" && previousId) await Promise.allSettled(providers.map((p) => p.alias?.(userIdOrPayload, previousId, context)));
|
|
245
|
+
},
|
|
246
|
+
getActiveProviders: () => providers.map((p) => p.name),
|
|
247
|
+
getProvider: (name) => providers.find((p) => p.name === name),
|
|
248
|
+
reset: () => {
|
|
249
|
+
context = {};
|
|
250
|
+
},
|
|
251
|
+
shutdown: async () => {
|
|
252
|
+
providers.length = 0;
|
|
253
|
+
},
|
|
254
|
+
processEmitterPayload: async (payload) => {
|
|
255
|
+
await processPayload(payload);
|
|
256
|
+
},
|
|
257
|
+
trackEcommerce: async () => {
|
|
258
|
+
if (config.debug && config.onInfo) config.onInfo("trackEcommerce is deprecated, use emit(ecommerce.EVENT_NAME(...))");
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Creates a PostHog provider that uses HTTP API (edge-compatible).
|
|
264
|
+
*
|
|
265
|
+
* This provider uses PostHog's HTTP capture API instead of the Node.js SDK,
|
|
266
|
+
* making it compatible with edge runtime constraints.
|
|
267
|
+
*
|
|
268
|
+
* **Features**:
|
|
269
|
+
* - HTTP-based event tracking
|
|
270
|
+
* - 5-second timeout per request
|
|
271
|
+
* - Error handling via config callbacks
|
|
272
|
+
* - Supports all standard analytics methods (track, identify, page, group, alias)
|
|
273
|
+
*
|
|
274
|
+
* @param {AnalyticsConfig} config - Analytics configuration
|
|
275
|
+
* @returns {AnalyticsProvider} PostHog provider instance
|
|
276
|
+
*
|
|
277
|
+
* @throws {Error} If PostHog API key is not provided
|
|
278
|
+
*
|
|
279
|
+
* @internal
|
|
280
|
+
*/
|
|
281
|
+
function createPostHogEdgeProvider(config) {
|
|
282
|
+
const posthogConfig = config.providers?.posthog;
|
|
283
|
+
if (!posthogConfig?.apiKey) throw new Error("PostHog apiKey is required");
|
|
284
|
+
const posthogUrl = `${posthogConfig.options?.api_host ?? env.POSTHOG_HOST ?? "https://app.posthog.com"}/capture/`;
|
|
285
|
+
const { apiKey } = posthogConfig;
|
|
286
|
+
const timeout = 5e3;
|
|
287
|
+
const safeFetch = async (body, method) => {
|
|
288
|
+
const controller = new AbortController();
|
|
289
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
290
|
+
try {
|
|
291
|
+
const response = await fetch(posthogUrl, {
|
|
292
|
+
method: "POST",
|
|
293
|
+
headers: { "Content-Type": "application/json" },
|
|
294
|
+
body: JSON.stringify(body),
|
|
295
|
+
signal: controller.signal
|
|
296
|
+
});
|
|
297
|
+
if (!response.ok && config.onError) config.onError(/* @__PURE__ */ new Error(`PostHog ${method} failed: ${response.status} ${response.statusText}`), {
|
|
298
|
+
provider: "posthog-edge",
|
|
299
|
+
method,
|
|
300
|
+
status: response.status
|
|
301
|
+
});
|
|
302
|
+
} catch (error) {
|
|
303
|
+
if (config.onError) config.onError(error instanceof Error ? error : /* @__PURE__ */ new Error("Unknown error"), {
|
|
304
|
+
provider: "posthog-edge",
|
|
305
|
+
method
|
|
306
|
+
});
|
|
307
|
+
} finally {
|
|
308
|
+
clearTimeout(timeoutId);
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
return {
|
|
312
|
+
name: "posthog-edge",
|
|
313
|
+
async initialize() {},
|
|
314
|
+
async track(event, properties, context) {
|
|
315
|
+
await safeFetch({
|
|
316
|
+
api_key: apiKey,
|
|
317
|
+
event,
|
|
318
|
+
distinct_id: context?.userId ?? properties?.distinctId ?? "anonymous",
|
|
319
|
+
properties: {
|
|
320
|
+
...properties,
|
|
321
|
+
...context
|
|
322
|
+
},
|
|
323
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
324
|
+
}, "track");
|
|
325
|
+
},
|
|
326
|
+
async identify(userId, traits) {
|
|
327
|
+
await safeFetch({
|
|
328
|
+
api_key: apiKey,
|
|
329
|
+
event: "$identify",
|
|
330
|
+
distinct_id: userId,
|
|
331
|
+
properties: { $set: traits }
|
|
332
|
+
}, "identify");
|
|
333
|
+
},
|
|
334
|
+
async page(name, properties, context) {
|
|
335
|
+
await safeFetch({
|
|
336
|
+
api_key: apiKey,
|
|
337
|
+
event: "$pageview",
|
|
338
|
+
distinct_id: context?.userId ?? "anonymous",
|
|
339
|
+
properties: {
|
|
340
|
+
$current_url: properties?.url,
|
|
341
|
+
$title: name,
|
|
342
|
+
...properties
|
|
343
|
+
}
|
|
344
|
+
}, "page");
|
|
345
|
+
},
|
|
346
|
+
async group(groupId, traits, context) {
|
|
347
|
+
await safeFetch({
|
|
348
|
+
api_key: apiKey,
|
|
349
|
+
event: "$groupidentify",
|
|
350
|
+
distinct_id: context?.userId ?? "anonymous",
|
|
351
|
+
properties: {
|
|
352
|
+
$group_type: "company",
|
|
353
|
+
$group_key: groupId,
|
|
354
|
+
$group_set: traits
|
|
355
|
+
}
|
|
356
|
+
}, "group");
|
|
357
|
+
},
|
|
358
|
+
async alias(userId, previousId) {
|
|
359
|
+
await safeFetch({
|
|
360
|
+
api_key: apiKey,
|
|
361
|
+
event: "$create_alias",
|
|
362
|
+
properties: {
|
|
363
|
+
distinct_id: userId,
|
|
364
|
+
alias: previousId
|
|
365
|
+
}
|
|
366
|
+
}, "alias");
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
//#endregion
|
|
372
|
+
export { alias, createEmitterProcessor, createServerAnalytics, getAnalyticsConfig, group, identify, page, track };
|
|
373
|
+
//# sourceMappingURL=server-edge.mjs.map
|
|
@@ -0,0 +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":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
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";
|
|
10
|
+
import "./server.mjs";
|
|
11
|
+
|
|
12
|
+
//#region src/next/middleware.d.ts
|
|
13
|
+
interface MiddlewareRequest {
|
|
14
|
+
cookies: {
|
|
15
|
+
get: (name: string) => {
|
|
16
|
+
value: string;
|
|
17
|
+
} | undefined;
|
|
18
|
+
set: (name: string, value: string, options?: any) => void;
|
|
19
|
+
};
|
|
20
|
+
headers: Headers;
|
|
21
|
+
method: string;
|
|
22
|
+
nextUrl: {
|
|
23
|
+
pathname: string;
|
|
24
|
+
searchParams: URLSearchParams;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
interface MiddlewareResponse {
|
|
28
|
+
headers: Headers;
|
|
29
|
+
status: number;
|
|
30
|
+
cookies: {
|
|
31
|
+
set: (name: string, value: string, options?: any) => void;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
interface AnalyticsMiddlewareConfig {
|
|
35
|
+
analytics: AnalyticsConfig;
|
|
36
|
+
posthogApiKey?: string;
|
|
37
|
+
excludeRoutes?: string[] | RegExp[];
|
|
38
|
+
shouldTrack?: (pathname: string) => boolean;
|
|
39
|
+
debug?: boolean;
|
|
40
|
+
getEventName?: (pathname: string, method: string) => string;
|
|
41
|
+
getProperties?: (request: MiddlewareRequest) => Record<string, any>;
|
|
42
|
+
trackPageViews?: boolean;
|
|
43
|
+
trackApiRoutes?: boolean;
|
|
44
|
+
createResponse: () => MiddlewareResponse;
|
|
45
|
+
}
|
|
46
|
+
declare function createAnalyticsMiddleware(config: AnalyticsMiddlewareConfig): (request: MiddlewareRequest) => Promise<MiddlewareResponse>;
|
|
47
|
+
declare function createAnalyticsMiddlewareConfig(options: {
|
|
48
|
+
createResponse: () => MiddlewareResponse;
|
|
49
|
+
posthogApiKey?: string;
|
|
50
|
+
segmentWriteKey?: string;
|
|
51
|
+
excludeRoutes?: string[] | RegExp[];
|
|
52
|
+
debug?: boolean;
|
|
53
|
+
}): AnalyticsMiddlewareConfig;
|
|
54
|
+
declare function getAnalyticsContextFromHeaders(headers: Headers): Record<string, any>;
|
|
55
|
+
declare function getDistinctIdFromHeaders(headers: Headers): string | null;
|
|
56
|
+
declare function conditionalAnalyticsMiddleware(config: AnalyticsMiddlewareConfig, condition: (request: MiddlewareRequest) => boolean): (request: MiddlewareRequest) => Promise<MiddlewareResponse>;
|
|
57
|
+
declare function composeMiddleware(...middlewares: ((request: MiddlewareRequest, createResponse?: () => MiddlewareResponse) => Promise<MiddlewareResponse>)[]): (request: MiddlewareRequest, createResponse: () => MiddlewareResponse) => Promise<MiddlewareResponse>;
|
|
58
|
+
declare global {
|
|
59
|
+
var analytics: {
|
|
60
|
+
track: (event: string, properties?: any) => Promise<void>;
|
|
61
|
+
identify: (userId: string, traits?: any) => Promise<void>;
|
|
62
|
+
page: (name?: string, properties?: any) => Promise<void>;
|
|
63
|
+
} | undefined;
|
|
64
|
+
} //# sourceMappingURL=middleware.d.ts.map
|
|
65
|
+
//#endregion
|
|
66
|
+
export { AnalyticsConfig, AnalyticsContext, AnalyticsManager, AnalyticsManager$1 as AnalyticsManagerClass, type AnalyticsMiddlewareConfig, AnalyticsProvider, BaseProductProperties, BootstrapData, CartProperties, ConsoleConfig, ConsoleOptions, ContextBuilder, EcommerceEventSpec, EmitterAliasPayload, EmitterContext, EmitterGroupPayload, EmitterIdentifyPayload, EmitterOptions, EmitterPagePayload, EmitterPayload, EmitterTrackPayload, EventBatch, ExtendedProductProperties, IngestionContext, IngestionErrorResponse, IngestionMetrics, IngestionService, IngestionServiceConfig, IngestionSuccessResponse, type MiddlewareRequest, type MiddlewareResponse, OrderProperties, PROVIDER_REQUIREMENTS, PayloadBuilder, PostHogConfig, PostHogOptions, ProviderConfig, ProviderRegistry, SegmentConfig, SegmentOptions, TrackingOptions, VercelConfig, VercelOptions, alias, composeMiddleware, conditionalAnalyticsMiddleware, createAnalyticsManager, createAnalyticsMiddleware, createAnalyticsMiddlewareConfig, createAnonymousSession, createBootstrapData, createConfigBuilder, createEmitterProcessor, createIngestionService, createMinimalBootstrapData, createServerAnalytics, createServerAnalyticsUninitialized, createUserSession, debugConfig, index_d_exports as ecommerce, generateDistinctId, getAnalyticsConfig, getAnalyticsContextFromHeaders, getDistinctIdFromHeaders, group, identify, isAliasPayload, isGroupPayload, isIdentifyPayload, isPagePayload, isTrackPayload, page, processEmitterPayload, screen, track, trackEcommerceEvent, validateAnalyticsConfig, validateBatchPayload, validateConfig, validateConfigOrThrow, validateEventPayload, validateProvider, withMetadata, withUTM };
|
|
67
|
+
//# sourceMappingURL=server-next.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-next.d.mts","names":[],"sources":["../src/next/middleware.ts"],"mappings":";;;;;;;;;;;;UAwBiB,iBAAA;EACf,OAAA;IACE,GAAA,GAAM,IAAA;MAAmB,KAAA;IAAA;IACzB,GAAA,GAAM,IAAA,UAAc,KAAA,UAAe,OAAA;EAAA;EAErC,OAAA,EAAS,OAAA;EACT,MAAA;EACA,OAAA;IACE,QAAA;IACA,YAAA,EAAc,eAAA;EAAA;AAAA;AAAA,UAOD,kBAAA;EACf,OAAA,EAAS,OAAA;EACT,MAAA;EACA,OAAA;IACE,GAAA,GAAM,IAAA,UAAc,KAAA,UAAe,OAAA;EAAA;AAAA;AAAA,UAItB,yBAAA;EAIf,SAAA,EAAW,eAAA;EAKX,aAAA;EAKA,aAAA,cAA2B,MAAA;EAK3B,WAAA,IAAe,QAAA;EAKf,KAAA;EAKA,YAAA,IAAgB,QAAA,UAAkB,MAAA;EAKlC,aAAA,IAAiB,OAAA,EAAS,iBAAA,KAAsB,MAAA;EAKhD,cAAA;EAKA,cAAA;EAKA,cAAA,QAAsB,kBAAA;AAAA;AAAA,iBAQR,yBAAA,CAA0B,MAAA,EAAQ,yBAAA,IAE9C,OAAA,EAAS,iBAAA,KACR,OAAA,CAAQ,kBAAA;AAAA,iBA+MG,+BAAA,CAAgC,OAAA;EAC9C,cAAA,QAAsB,kBAAA;EACtB,aAAA;EACA,eAAA;EACA,aAAA,cAA2B,MAAA;EAC3B,KAAA;AAAA,IACE,yBAAA;AAAA,iBAgCY,8BAAA,CAA+B,OAAA,EAAS,OAAA,GAAU,MAAA;AAAA,iBAiBlD,wBAAA,CAAyB,OAAA,EAAS,OAAA;AAAA,iBAOlC,8BAAA,CACd,MAAA,EAAQ,yBAAA,EACR,SAAA,GAAY,OAAA,EAAS,iBAAA,gBAIE,OAAA,EAAS,iBAAA,KAAoB,OAAA,CAAQ,kBAAA;AAAA,iBAW9C,iBAAA,CAAA,GACX,WAAA,IACD,OAAA,EAAS,iBAAA,EACT,cAAA,SAAuB,kBAAA,KACpB,OAAA,CAAQ,kBAAA,QAGX,OAAA,EAAS,iBAAA,EACT,cAAA,QAAsB,kBAAA,KACrB,OAAA,CAAQ,kBAAA;AAAA,QAiBL,MAAA;EAAA,IACF,SAAA;IAEE,KAAA,GAAQ,KAAA,UAAe,UAAA,WAAqB,OAAA;IAC5C,QAAA,GAAW,MAAA,UAAgB,MAAA,WAAiB,OAAA;IAC5C,IAAA,GAAO,IAAA,WAAe,UAAA,WAAqB,OAAA;EAAA;AAAA"}
|