@drivemetadata-ai/sdk 0.1.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +21 -0
  3. package/README.md +107 -0
  4. package/dist/angular/index.cjs +954 -0
  5. package/dist/angular/index.cjs.map +1 -0
  6. package/dist/angular/index.d.cts +26 -0
  7. package/dist/angular/index.d.ts +26 -0
  8. package/dist/angular/index.js +928 -0
  9. package/dist/angular/index.js.map +1 -0
  10. package/dist/browser/index.cjs +914 -0
  11. package/dist/browser/index.cjs.map +1 -0
  12. package/dist/browser/index.d.cts +84 -0
  13. package/dist/browser/index.d.ts +84 -0
  14. package/dist/browser/index.js +874 -0
  15. package/dist/browser/index.js.map +1 -0
  16. package/dist/next/index.cjs +971 -0
  17. package/dist/next/index.cjs.map +1 -0
  18. package/dist/next/index.d.cts +18 -0
  19. package/dist/next/index.d.ts +18 -0
  20. package/dist/next/index.js +928 -0
  21. package/dist/next/index.js.map +1 -0
  22. package/dist/node/index.cjs +239 -0
  23. package/dist/node/index.cjs.map +1 -0
  24. package/dist/node/index.d.cts +85 -0
  25. package/dist/node/index.d.ts +85 -0
  26. package/dist/node/index.js +209 -0
  27. package/dist/node/index.js.map +1 -0
  28. package/dist/react/index.cjs +999 -0
  29. package/dist/react/index.cjs.map +1 -0
  30. package/dist/react/index.d.cts +26 -0
  31. package/dist/react/index.d.ts +26 -0
  32. package/dist/react/index.js +952 -0
  33. package/dist/react/index.js.map +1 -0
  34. package/dist/types-BwtS0ZDu.d.cts +106 -0
  35. package/dist/types-BwtS0ZDu.d.ts +106 -0
  36. package/docs/angular-integration.md +106 -0
  37. package/docs/index.md +19 -0
  38. package/docs/migration-cdn-to-npm.md +99 -0
  39. package/docs/node-server-integration.md +138 -0
  40. package/docs/npm-browser-sdk.md +143 -0
  41. package/docs/react-next-integration.md +168 -0
  42. package/docs/security-privacy.md +128 -0
  43. package/package.json +100 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/react/DmdProvider.tsx","../../src/core/config.ts","../../src/core/environment.ts","../../src/browser/core/consent.ts","../../src/browser/core/delivery.ts","../../src/browser/core/privacy.ts","../../src/browser/core/schema.ts","../../src/browser/core/DriveMetaDataSDK.ts","../../src/browser/legacy-loader.ts","../../src/browser/client.ts","../../src/react/hooks.ts"],"sourcesContent":["import React from 'react';\nimport { getDmdSDK, initDmdSDK } from '../browser/client';\nimport type { DmdBrowserClient, DmdBrowserConfig } from '../core/types';\n\nexport const DmdContext = React.createContext<DmdBrowserClient | undefined>(undefined);\n\nexport interface DmdProviderProps {\n config: DmdBrowserConfig;\n children: React.ReactNode;\n enabled?: boolean;\n onReady?: (client: DmdBrowserClient) => void;\n onError?: (error: Error) => void;\n}\n\nexport function DmdProvider({\n config,\n children,\n enabled = true,\n onReady,\n onError\n}: DmdProviderProps) {\n const [client, setClient] = React.useState<DmdBrowserClient | undefined>(() => getDmdSDK());\n\n React.useEffect(() => {\n if (!enabled) return;\n\n try {\n const initializedClient = initDmdSDK(config);\n const configuredConsent = config.gdprConsent ?? config.consent;\n if (configuredConsent !== undefined) {\n initializedClient.setConsent(configuredConsent);\n }\n setClient(initializedClient);\n onReady?.(initializedClient);\n } catch (error) {\n const normalizedError = error instanceof Error ? error : new Error(String(error));\n onError?.(normalizedError);\n }\n }, [\n enabled,\n config.clientId,\n config.workspaceId,\n config.appId,\n config.writeKey,\n config.apiHost,\n config.consent,\n config.gdprConsent,\n onReady,\n onError\n ]);\n\n return <DmdContext.Provider value={client}>{children}</DmdContext.Provider>;\n}\n","import type { DmdBrowserConfig, DmdLegacyConfig } from './types';\n\nfunction requireString(value: string | undefined, field: string): string {\n if (typeof value !== 'string' || value.trim() === '') {\n throw new Error(`DMD SDK config ${field} is required`);\n }\n return value;\n}\n\nexport function normalizeBrowserConfig(config: DmdBrowserConfig): DmdLegacyConfig {\n const writeKey = config.writeKey || config.token;\n const legacyConfig: DmdLegacyConfig = {\n client_id: requireString(config.clientId, 'clientId'),\n workspace_id: requireString(config.workspaceId, 'workspaceId'),\n app_id: requireString(config.appId, 'appId'),\n token: requireString(writeKey, 'writeKey')\n };\n\n if (config.apiHost !== undefined) legacyConfig.api_host = config.apiHost;\n if (config.uiHost !== undefined) legacyConfig.ui_host = config.uiHost;\n if (config.deeplink !== undefined) legacyConfig.deeplink = config.deeplink;\n if (config.debug !== undefined) legacyConfig.debug = config.debug;\n if (config.consent !== undefined) legacyConfig.consent = config.consent;\n if (config.gdprConsent !== undefined) legacyConfig.gdprConsent = config.gdprConsent;\n if (config.autocapture !== undefined) legacyConfig.autocapture = config.autocapture;\n if (config.capturePageview !== undefined) legacyConfig.capture_pageview = config.capturePageview;\n if (config.capturePageleave !== undefined) legacyConfig.capture_pageleave = config.capturePageleave;\n if (config.captureDeadClicks !== undefined) legacyConfig.capture_dead_clicks = config.captureDeadClicks;\n if (config.crossSubdomainCookie !== undefined) legacyConfig.cross_subdomain_cookie = config.crossSubdomainCookie;\n if (config.disablePersistence !== undefined) legacyConfig.disable_persistence = config.disablePersistence;\n if (config.disableSurveys !== undefined) legacyConfig.disable_surveys = config.disableSurveys;\n if (config.disableSessionRecording !== undefined) legacyConfig.disable_session_recording = config.disableSessionRecording;\n if (config.enableHeatmaps !== undefined) legacyConfig.enable_heatmaps = config.enableHeatmaps;\n if (config.maskAllText !== undefined) legacyConfig.mask_all_text = config.maskAllText;\n if (config.maskAllElementAttributes !== undefined) {\n legacyConfig.mask_all_element_attributes = config.maskAllElementAttributes;\n }\n if (config.persistence !== undefined) legacyConfig.persistence = config.persistence;\n if (config.propertyDenylist !== undefined) legacyConfig.property_denylist = config.propertyDenylist;\n if (config.sessionIdleTimeoutSeconds !== undefined) {\n legacyConfig.session_idle_timeout_seconds = config.sessionIdleTimeoutSeconds;\n }\n if (config.beforeSend !== undefined) legacyConfig.before_send = config.beforeSend;\n\n return legacyConfig;\n}\n","export function isBrowserRuntime(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\nexport function getBrowserWindow(): Window | undefined {\n return typeof window === 'undefined' ? undefined : window;\n}\n","import type {\n DmdConsentInput,\n DmdConsentPurpose,\n DmdConsentState,\n DmdPurposeConsent\n} from './types';\n\nexport type DmdResolvedConsent = Record<DmdConsentPurpose, DmdConsentState>;\n\nconst purposes: DmdConsentPurpose[] = [\n 'analytics',\n 'advertising',\n 'personalization',\n 'functional',\n 'saleOfData'\n];\n\nfunction normalizeConsentValue(value: unknown): DmdConsentState {\n if (value === true) return 'granted';\n if (value === false) return 'denied';\n if (value === 'granted' || value === 'denied' || value === 'pending') return value;\n return 'pending';\n}\n\nexport function normalizeConsent(input: DmdConsentInput | undefined): DmdResolvedConsent {\n const defaultValue = normalizeConsentValue(input ?? 'pending');\n const resolved = Object.fromEntries(\n purposes.map(purpose => [purpose, defaultValue])\n ) as DmdResolvedConsent;\n\n if (input && typeof input === 'object') {\n for (const purpose of purposes) {\n const value = input[purpose];\n if (value !== undefined) {\n resolved[purpose] = normalizeConsentValue(value);\n }\n }\n }\n\n return resolved;\n}\n\nexport function mergeConsent(current: DmdResolvedConsent, update: DmdPurposeConsent): DmdResolvedConsent {\n const next = { ...current };\n for (const [purpose, value] of Object.entries(update) as Array<[DmdConsentPurpose, DmdConsentState]>) {\n next[purpose] = normalizeConsentValue(value);\n }\n return next;\n}\n\nexport function canCollectPurpose(consent: DmdResolvedConsent, purpose: DmdConsentPurpose): boolean {\n return consent[purpose] === 'granted';\n}\n","export interface DmdQueuedRecord {\n messageId: string;\n savedAt: number;\n attempts: number;\n lastError?: string;\n payload: Record<string, unknown>;\n}\n\nexport interface DmdDeliveryDiagnostics {\n queued: number;\n inFlight: number;\n dropped: Array<{ messageId?: string; reason: string; timestamp: string }>;\n lastError?: string;\n}\n\nexport interface DmdDeliveryManager {\n send(payload: Record<string, unknown>): Promise<void>;\n flushQueue(): Promise<void>;\n clearQueue(reason: string): void;\n enqueueForTests(record: DmdQueuedRecord): void;\n flushExpired(): void;\n acquireFlushLease(): boolean;\n releaseFlushLease(): void;\n getDiagnostics(): DmdDeliveryDiagnostics;\n}\n\nexport interface DmdDeliveryStorage {\n getItem(key: string): string | null;\n setItem(key: string, value: string): unknown;\n removeItem(key: string): unknown;\n}\n\nfunction createId(prefix: string): string {\n return `${prefix}_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;\n}\n\nfunction stableStringify(value: unknown): string {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return JSON.stringify(value);\n }\n return JSON.stringify(\n Object.fromEntries(\n Object.entries(value as Record<string, unknown>).sort(([left], [right]) => left.localeCompare(right))\n )\n );\n}\n\nfunction createIdempotencyKey(payload: Record<string, unknown>, messageId: string): string {\n const event = String(payload.event ?? payload.type ?? 'event');\n const properties = payload.properties as Record<string, unknown> | undefined;\n const orderId = properties?.orderId ?? properties?.order_id ?? properties?.transaction_id;\n if (orderId !== undefined) return `${event}:${String(orderId)}`;\n return `${event}:${stableStringify(properties ?? {}) || messageId}`;\n}\n\nexport function createDeliveryManager(config: {\n endpoint: string;\n fetch?: typeof fetch;\n queueTtlMs?: number;\n maxQueueSize?: number;\n storage?: DmdDeliveryStorage;\n queueKey?: string;\n lockKey?: string;\n lockTtlMs?: number;\n tabId?: string;\n retryDelayMs?: number;\n maxRetryDelayMs?: number;\n maxPayloadBytes?: number;\n batchSize?: number;\n onDrop?: (event: { messageId?: string; reason: string; timestamp: string }) => void;\n onError?: (error: Error) => void;\n}): DmdDeliveryManager {\n const queue: DmdQueuedRecord[] = [];\n const diagnostics: DmdDeliveryDiagnostics = { queued: 0, inFlight: 0, dropped: [] };\n const maxQueueSize = config.maxQueueSize ?? 100;\n const queueKey = config.queueKey ?? 'dmd_delivery_queue';\n const lockKey = config.lockKey ?? 'dmd_delivery_flush_lock';\n const lockTtlMs = config.lockTtlMs ?? 5_000;\n const tabId = config.tabId ?? createId('tab');\n const batchSize = config.batchSize ?? 25;\n const maxPayloadBytes = config.maxPayloadBytes ?? 64_000;\n\n function recordDrop(event: { messageId?: string; reason: string; timestamp: string }): void {\n diagnostics.dropped.push(event);\n config.onDrop?.(event);\n }\n\n function recordError(error: Error): void {\n diagnostics.lastError = error.message;\n config.onError?.(error);\n }\n\n function payloadByteLength(payload: Record<string, unknown>): number {\n const serialized = JSON.stringify(payload);\n if (typeof TextEncoder !== 'undefined') {\n return new TextEncoder().encode(serialized).length;\n }\n return serialized.length;\n }\n\n function recordStorageUnavailable(): void {\n recordDrop({\n reason: 'storage_unavailable',\n timestamp: new Date().toISOString()\n });\n }\n\n function safeGetItem(key: string): string | null {\n try {\n return config.storage?.getItem(key) ?? null;\n } catch {\n recordStorageUnavailable();\n return null;\n }\n }\n\n function safeSetItem(key: string, value: string): boolean {\n try {\n config.storage?.setItem(key, value);\n return true;\n } catch {\n recordStorageUnavailable();\n return false;\n }\n }\n\n function safeRemoveItem(key: string): boolean {\n try {\n config.storage?.removeItem(key);\n return true;\n } catch {\n recordStorageUnavailable();\n return false;\n }\n }\n\n function persistQueue(): void {\n if (!config.storage) return;\n if (queue.length === 0) {\n safeRemoveItem(queueKey);\n return;\n }\n safeSetItem(queueKey, JSON.stringify(queue));\n }\n\n function loadQueue(): void {\n if (!config.storage) return;\n const rawQueue = safeGetItem(queueKey);\n if (!rawQueue) return;\n try {\n const records = JSON.parse(rawQueue) as DmdQueuedRecord[];\n queue.splice(0, queue.length, ...records.filter(record => record && typeof record.messageId === 'string'));\n diagnostics.queued = queue.length;\n } catch {\n safeRemoveItem(queueKey);\n recordDrop({\n reason: 'queue_corrupt',\n timestamp: new Date().toISOString()\n });\n }\n }\n\n function enqueue(record: DmdQueuedRecord): void {\n queue.push(record);\n while (queue.length > maxQueueSize) {\n const dropped = queue.shift();\n const diagnostic: { messageId?: string; reason: string; timestamp: string } = {\n reason: 'queue_limit_exceeded',\n timestamp: new Date().toISOString()\n };\n if (dropped?.messageId !== undefined) diagnostic.messageId = dropped.messageId;\n recordDrop(diagnostic);\n }\n diagnostics.queued = queue.length;\n persistQueue();\n }\n\n function withEnvelope(payload: Record<string, unknown>): Record<string, unknown> {\n const messageId = String(payload.messageId ?? createId('msg'));\n return {\n ...payload,\n messageId,\n idempotencyKey: String(payload.idempotencyKey ?? createIdempotencyKey(payload, messageId))\n };\n }\n\n async function deliver(body: Record<string, unknown>): Promise<void> {\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== 'function') {\n throw new Error('fetch_unavailable');\n }\n\n const response = await fetchImpl(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n keepalive: true\n });\n if (!response.ok) throw new Error(`HTTP ${response.status}`);\n }\n\n loadQueue();\n\n return {\n async send(payload: Record<string, unknown>): Promise<void> {\n const body = withEnvelope(payload);\n\n if (payloadByteLength(body) > maxPayloadBytes) {\n recordDrop({\n messageId: String(body.messageId),\n reason: 'payload_too_large',\n timestamp: new Date().toISOString()\n });\n return;\n }\n\n diagnostics.inFlight += 1;\n try {\n await deliver(body);\n } catch (error) {\n const deliveryError = error instanceof Error ? error : new Error(String(error));\n recordError(deliveryError);\n enqueue({\n messageId: String(body.messageId),\n savedAt: Date.now(),\n attempts: 1,\n lastError: deliveryError.message,\n payload: body\n });\n } finally {\n diagnostics.inFlight -= 1;\n diagnostics.queued = queue.length;\n }\n },\n async flushQueue(): Promise<void> {\n this.flushExpired();\n if (queue.length === 0 || !this.acquireFlushLease()) return;\n\n diagnostics.inFlight += 1;\n try {\n let sentInBatch = 0;\n for (let index = 0; index < queue.length && sentInBatch < batchSize;) {\n const record = queue[index];\n if (!record) {\n index += 1;\n continue;\n }\n\n try {\n await deliver(record.payload);\n queue.splice(index, 1);\n sentInBatch += 1;\n persistQueue();\n } catch (error) {\n const deliveryError = error instanceof Error ? error : new Error(String(error));\n record.attempts += 1;\n record.lastError = deliveryError.message;\n recordError(deliveryError);\n index += 1;\n persistQueue();\n break;\n }\n }\n } finally {\n diagnostics.inFlight -= 1;\n diagnostics.queued = queue.length;\n this.releaseFlushLease();\n }\n },\n clearQueue(reason: string): void {\n for (const record of queue) {\n recordDrop({\n messageId: record.messageId,\n reason,\n timestamp: new Date().toISOString()\n });\n }\n queue.splice(0, queue.length);\n diagnostics.queued = 0;\n persistQueue();\n },\n enqueueForTests(record: DmdQueuedRecord): void {\n enqueue(record);\n },\n flushExpired(): void {\n const ttl = config.queueTtlMs ?? 86_400_000;\n const now = Date.now();\n for (let index = queue.length - 1; index >= 0; index -= 1) {\n const record = queue[index];\n if (record && now - record.savedAt > ttl) {\n recordDrop({\n messageId: record.messageId,\n reason: 'queue_ttl_expired',\n timestamp: new Date().toISOString()\n });\n queue.splice(index, 1);\n }\n }\n diagnostics.queued = queue.length;\n persistQueue();\n },\n acquireFlushLease(): boolean {\n if (!config.storage) return true;\n\n const now = Date.now();\n const rawLock = safeGetItem(lockKey);\n let existingLock: { owner?: string; expiresAt?: number } | undefined;\n if (rawLock) {\n try {\n existingLock = JSON.parse(rawLock) as { owner?: string; expiresAt?: number };\n } catch {\n existingLock = undefined;\n }\n }\n\n const lockExpired = !existingLock?.expiresAt || existingLock.expiresAt <= now;\n const lockOwnedByThisTab = existingLock?.owner === tabId;\n if (!existingLock || lockExpired || lockOwnedByThisTab) {\n if (!safeSetItem(lockKey, JSON.stringify({ owner: tabId, expiresAt: now + lockTtlMs }))) {\n return true;\n }\n return true;\n }\n\n return false;\n },\n releaseFlushLease(): void {\n if (!config.storage) return;\n const rawLock = safeGetItem(lockKey);\n if (!rawLock) return;\n\n try {\n const existingLock = JSON.parse(rawLock) as { owner?: string };\n if (existingLock.owner === tabId) {\n safeRemoveItem(lockKey);\n }\n } catch {\n safeRemoveItem(lockKey);\n }\n },\n getDiagnostics(): DmdDeliveryDiagnostics {\n return diagnostics;\n }\n };\n}\n","const sensitiveKeys = new Set([\n 'email',\n 'phone',\n 'mobile',\n 'address',\n 'address1',\n 'address2',\n 'first_name',\n 'last_name',\n 'name',\n 'token',\n 'secret',\n 'password',\n 'session',\n 'cookie'\n]);\n\nexport function redactUrl(\n url: string,\n allowQueryKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']\n): string {\n const parsed = new URL(url, 'https://placeholder.local');\n for (const key of Array.from(parsed.searchParams.keys())) {\n if (!allowQueryKeys.includes(key)) {\n parsed.searchParams.set(key, '[REDACTED]');\n }\n }\n return url.startsWith('http') ? parsed.toString() : `${parsed.pathname}${parsed.search}`;\n}\n\nfunction sanitizeValue(value: unknown, allow: Set<string>): unknown {\n if (Array.isArray(value)) {\n return value.map(item => sanitizeValue(item, allow));\n }\n\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .filter(([key]) => !sensitiveKeys.has(key.toLowerCase()) || allow.has(key.toLowerCase()))\n .map(([key, nestedValue]) => [key, sanitizeValue(nestedValue, allow)])\n );\n }\n\n return value;\n}\n\nexport function sanitizeProperties(input: Record<string, unknown>, allowRawKeys: string[] = []): Record<string, unknown> {\n const allow = new Set(allowRawKeys.map(key => key.toLowerCase()));\n return sanitizeValue(input, allow) as Record<string, unknown>;\n}\n\nexport async function sha256LowerTrimmed(value: string): Promise<string> {\n const bytes = new TextEncoder().encode(value.trim().toLowerCase());\n const digest = await crypto.subtle.digest('SHA-256', bytes);\n return Array.from(new Uint8Array(digest)).map(byte => byte.toString(16).padStart(2, '0')).join('');\n}\n","const reservedKeys = new Set(['messageId', 'timestamp', 'type', 'event', 'anonymousId', 'userId', 'context']);\n\nexport interface DmdSchemaValidationResult {\n ok: boolean;\n errors: string[];\n}\n\nexport function validateEventEnvelope(\n envelope: {\n type?: unknown;\n event?: unknown;\n properties?: Record<string, unknown>;\n messageId?: unknown;\n timestamp?: unknown;\n },\n options: { mode?: 'off' | 'warn' | 'strict' } = {}\n): DmdSchemaValidationResult {\n if (options.mode === 'off') return { ok: true, errors: [] };\n const errors: string[] = [];\n if (typeof envelope.type !== 'string') errors.push('type must be a string');\n if (envelope.type === 'track' && typeof envelope.event !== 'string') {\n errors.push('track event must include event name');\n }\n if (typeof envelope.messageId !== 'string') errors.push('messageId must be a string');\n if (typeof envelope.timestamp !== 'string') errors.push('timestamp must be an ISO string');\n for (const key of Object.keys(envelope.properties ?? {})) {\n if (reservedKeys.has(key)) errors.push(`properties.${key} is reserved`);\n }\n return { ok: errors.length === 0, errors };\n}\n","import type { DmdDroppedEventDiagnostic, DmdDroppedEventReason, DmdDroppedEventType } from '../../core/diagnostics';\nimport type { DmdBrowserConfig, DmdConsentInput, DmdEventOptions, DmdHealthStatus } from '../../core/types';\nimport { getBrowserWindow } from '../../core/environment';\nimport { canCollectPurpose, mergeConsent, normalizeConsent, type DmdResolvedConsent } from './consent';\nimport { createDeliveryManager, type DmdDeliveryManager } from './delivery';\nimport { sanitizeProperties } from './privacy';\nimport { validateEventEnvelope } from './schema';\nimport type { DmdIdentityState } from './types';\n\ninterface DmdPreparedEvent {\n type: 'track' | 'page' | 'identify' | 'group' | 'alias';\n event: string;\n properties: Record<string, unknown>;\n messageId: string;\n timestamp: string;\n context: Record<string, unknown>;\n anonymousId: string;\n userId?: string;\n groupId?: string;\n clientId: string;\n workspaceId: string;\n appId: string;\n writeKey: string;\n consent: DmdResolvedConsent;\n}\n\nfunction createId(prefix: string): string {\n return `${prefix}_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;\n}\n\nfunction endpointFromConfig(config: DmdBrowserConfig): string {\n const host = config.apiHost ?? 'https://sdk.drivemetadata.com/v2';\n return `${host.replace(/\\/$/, '')}/data-collector`;\n}\n\nfunction getBrowserStorage() {\n const browserWindow = getBrowserWindow();\n try {\n return browserWindow?.localStorage;\n } catch {\n return undefined;\n }\n}\n\nexport class DriveMetaDataSDK {\n public initialized = true;\n public queue: unknown[] = [];\n public offline = false;\n public gdprConsent: 'granted' | 'denied' | 'pending';\n\n private readonly endpoint: string;\n private readonly config: DmdBrowserConfig;\n private readonly writeKey: string;\n private readonly delivery: DmdDeliveryManager;\n private identity: DmdIdentityState;\n private consentState: DmdResolvedConsent;\n private droppedEvents = 0;\n private lastError: string | undefined;\n private lastDroppedEvent: DmdDroppedEventDiagnostic | undefined;\n private retryTimer: ReturnType<typeof setTimeout> | undefined;\n private retryDelayMs: number;\n private readonly initialRetryDelayMs: number;\n private readonly maxRetryDelayMs: number;\n private lifecycleCleanup: (() => void) | undefined;\n\n constructor(config: DmdBrowserConfig) {\n this.config = config;\n this.endpoint = endpointFromConfig(config);\n const storage = getBrowserStorage();\n const deliveryConfig: Parameters<typeof createDeliveryManager>[0] = {\n endpoint: this.endpoint,\n };\n if (config.delivery?.maxQueueSize !== undefined) deliveryConfig.maxQueueSize = config.delivery.maxQueueSize;\n if (config.delivery?.queueTtlMs !== undefined) deliveryConfig.queueTtlMs = config.delivery.queueTtlMs;\n if (config.delivery?.retryDelayMs !== undefined) deliveryConfig.retryDelayMs = config.delivery.retryDelayMs;\n if (config.delivery?.maxRetryDelayMs !== undefined) deliveryConfig.maxRetryDelayMs = config.delivery.maxRetryDelayMs;\n if (config.delivery?.maxPayloadBytes !== undefined) deliveryConfig.maxPayloadBytes = config.delivery.maxPayloadBytes;\n if (config.delivery?.batchSize !== undefined) deliveryConfig.batchSize = config.delivery.batchSize;\n if (config.onDrop !== undefined) deliveryConfig.onDrop = config.onDrop;\n if (config.onError !== undefined) deliveryConfig.onError = config.onError;\n this.delivery = createDeliveryManager(storage ? {\n ...deliveryConfig,\n storage\n } : deliveryConfig);\n this.initialRetryDelayMs = config.delivery?.retryDelayMs ?? 1_000;\n this.retryDelayMs = this.initialRetryDelayMs;\n this.maxRetryDelayMs = config.delivery?.maxRetryDelayMs ?? 30_000;\n this.writeKey = config.writeKey || config.token || '';\n this.identity = { anonymousId: createId('anon') };\n this.consentState = normalizeConsent(config.gdprConsent ?? config.consent);\n this.gdprConsent = this.consentState.analytics;\n if (!config.delivery?.disableLifecycleFlush) {\n this.installLifecycleFlush();\n }\n }\n\n trackEvent(event: string, properties: Record<string, unknown> = {}, options: DmdEventOptions = {}): void {\n this.sendPreparedEvent('track', event, properties, options);\n }\n\n page(name?: string, properties: Record<string, unknown> = {}, options: DmdEventOptions = {}): void {\n this.sendPreparedEvent('page', 'page_view', { name, ...properties }, options);\n }\n\n trackPageview(): void {\n this.page();\n }\n\n identify(userId: string, traits: Record<string, unknown> = {}, options: DmdEventOptions = {}): void {\n this.identity = { ...this.identity, userId, traits };\n this.sendPreparedEvent('identify', 'identify', { userId, traits }, options);\n }\n\n identifyUser(userId: string, traits: Record<string, unknown> = {}): void {\n this.identify(userId, traits);\n }\n\n group(groupId: string, traits: Record<string, unknown> = {}, options: DmdEventOptions = {}): void {\n this.identity = { ...this.identity, groupId };\n this.sendPreparedEvent('group', 'group', { groupId, traits }, options);\n }\n\n alias(previousId: string, userId: string, options: DmdEventOptions = {}): void {\n this.sendPreparedEvent('alias', 'alias', { previousId, userId }, options);\n }\n\n async flush(): Promise<void> {\n await this.delivery.flushQueue();\n const diagnostics = this.delivery.getDiagnostics();\n this.offline = diagnostics.queued > 0;\n this.lastError = diagnostics.lastError;\n if (diagnostics.queued > 0) {\n this.scheduleRetryFlush();\n } else {\n this.retryDelayMs = this.initialRetryDelayMs;\n }\n }\n\n reset(): void {\n this.identity = { anonymousId: createId('anon') };\n this.queue = [];\n this.offline = false;\n if (this.retryTimer !== undefined) {\n clearTimeout(this.retryTimer);\n this.retryTimer = undefined;\n }\n this.lifecycleCleanup?.();\n this.lifecycleCleanup = undefined;\n this.delivery.clearQueue('manual_clear');\n }\n\n setConsent(consent: DmdConsentInput): void {\n this.consentState = typeof consent === 'object'\n ? mergeConsent(this.consentState, consent)\n : normalizeConsent(consent);\n this.gdprConsent = this.consentState.analytics;\n if (!canCollectPurpose(this.consentState, 'analytics')) {\n this.queue = [];\n this.delivery.clearQueue('consent_revoked');\n }\n }\n\n getHealth(): DmdHealthStatus {\n const deliveryDiagnostics = this.delivery.getDiagnostics();\n const health: DmdHealthStatus = {\n initialized: this.initialized,\n consent: this.gdprConsent,\n consentPurposes: this.consentState,\n queueSize: deliveryDiagnostics.queued,\n offline: this.offline || deliveryDiagnostics.queued > 0,\n droppedEvents: this.droppedEvents + deliveryDiagnostics.dropped.length,\n delivery: deliveryDiagnostics\n };\n const lastError = this.lastError ?? deliveryDiagnostics.lastError;\n if (lastError !== undefined) health.lastError = lastError;\n if (this.lastDroppedEvent !== undefined) health.lastDroppedEvent = this.lastDroppedEvent;\n return health;\n }\n\n sendEvent(payload: unknown): void {\n void this.delivery.send(payload as Record<string, unknown>).then(() => {\n const diagnostics = this.delivery.getDiagnostics();\n this.offline = diagnostics.queued > 0;\n this.lastError = diagnostics.lastError;\n if (diagnostics.queued > 0) {\n this.scheduleRetryFlush();\n }\n });\n }\n\n private installLifecycleFlush(): void {\n const browserWindow = getBrowserWindow();\n if (!browserWindow) return;\n if (typeof browserWindow.addEventListener !== 'function') return;\n if (typeof browserWindow.removeEventListener !== 'function') return;\n\n const flushOnLifecycle = () => {\n void this.flush();\n };\n const flushOnVisibility = () => {\n if (browserWindow.document?.visibilityState === 'hidden') {\n void this.flush();\n }\n };\n\n browserWindow.addEventListener('online', flushOnLifecycle);\n browserWindow.addEventListener('pagehide', flushOnLifecycle);\n if (typeof browserWindow.document?.addEventListener === 'function') {\n browserWindow.document.addEventListener('visibilitychange', flushOnVisibility);\n }\n\n this.lifecycleCleanup = () => {\n browserWindow.removeEventListener('online', flushOnLifecycle);\n browserWindow.removeEventListener('pagehide', flushOnLifecycle);\n if (typeof browserWindow.document?.removeEventListener === 'function') {\n browserWindow.document.removeEventListener('visibilitychange', flushOnVisibility);\n }\n };\n }\n\n private scheduleRetryFlush(): void {\n if (this.retryTimer !== undefined) return;\n\n const delay = Math.min(this.retryDelayMs, this.maxRetryDelayMs);\n this.retryTimer = setTimeout(() => {\n this.retryTimer = undefined;\n void this.flush().then(() => {\n if (this.delivery.getDiagnostics().queued > 0) {\n this.retryDelayMs = Math.min(this.retryDelayMs * 2, this.maxRetryDelayMs);\n this.scheduleRetryFlush();\n }\n });\n }, delay);\n }\n\n private sendPreparedEvent(\n type: DmdPreparedEvent['type'],\n event: string,\n properties: Record<string, unknown>,\n options: DmdEventOptions\n ): void {\n void this.prepareAndSendEvent(type, event, properties, options);\n }\n\n private async prepareAndSendEvent(\n type: DmdPreparedEvent['type'],\n event: string,\n properties: Record<string, unknown>,\n options: DmdEventOptions\n ): Promise<void> {\n if (!canCollectPurpose(this.consentState, 'analytics')) {\n this.recordDrop(type, 'consent_denied', event);\n return;\n }\n\n let prepared: DmdPreparedEvent = {\n type,\n event,\n properties: sanitizeProperties(properties),\n messageId: options.messageId ?? createId('msg'),\n timestamp: options.timestamp ?? new Date().toISOString(),\n context: options.context ?? {},\n anonymousId: this.identity.anonymousId,\n clientId: this.config.clientId,\n workspaceId: this.config.workspaceId,\n appId: this.config.appId,\n writeKey: this.writeKey,\n consent: this.consentState\n };\n\n if (this.identity.userId !== undefined) prepared.userId = this.identity.userId;\n if (this.identity.groupId !== undefined) prepared.groupId = this.identity.groupId;\n\n if (this.config.beforeSend !== undefined) {\n const beforeSendResult = await this.config.beforeSend(prepared);\n if (beforeSendResult === null) {\n this.recordDrop(type, 'before_send_dropped', event);\n return;\n }\n prepared = {\n ...prepared,\n ...beforeSendResult,\n properties: sanitizeProperties(beforeSendResult.properties ?? prepared.properties)\n };\n }\n\n const validation = validateEventEnvelope(prepared, { mode: this.config.schemaValidation ?? 'warn' });\n if (!validation.ok && this.config.schemaValidation === 'strict') {\n this.recordDrop(type, 'invalid_payload', event);\n return;\n }\n if (!validation.ok) {\n this.lastError = `DMD SDK schema warning: ${validation.errors.join(', ')}`;\n }\n\n this.sendEvent(prepared);\n }\n\n private recordDrop(type: DmdDroppedEventType, reason: DmdDroppedEventReason, event?: string): void {\n this.droppedEvents += 1;\n this.lastDroppedEvent = {\n type,\n reason,\n timestamp: new Date().toISOString()\n };\n if (event !== undefined) this.lastDroppedEvent.event = event;\n this.lastError = `DMD SDK ${type} dropped because ${reason}`;\n }\n}\n","import { getBrowserWindow, isBrowserRuntime } from '../core/environment';\n\nexport type LegacySdkConstructor = new (config: unknown) => LegacySdkInstance;\n\nexport interface LegacySdkInstance {\n sendEvent?: (payload: unknown) => void;\n trackEvent?: (event: string, properties?: Record<string, unknown>, options?: unknown) => void;\n identify?: (userId: string, traits?: Record<string, unknown>, options?: unknown) => void;\n identifyUser?: (userId: string, traits?: Record<string, unknown>) => void;\n page?: (name?: string, properties?: Record<string, unknown>, options?: unknown) => void;\n group?: (groupId: string, traits?: Record<string, unknown>, options?: unknown) => void;\n alias?: (previousId: string, userId: string, options?: unknown) => void;\n flush?: () => Promise<void>;\n reset?: () => void;\n setConsent?: (consent: unknown) => void;\n getHealth?: () => unknown;\n trackPageview?: () => void;\n blockTrackingForMe?: () => void;\n gdprConsent?: 'granted' | 'denied' | 'pending';\n initialized?: boolean;\n queue?: unknown[];\n offline?: boolean;\n}\n\ninterface DmdWindow extends Window {\n DriveMetaDataSDK?: LegacySdkConstructor;\n __DriveMetaDataSDKInstance?: LegacySdkInstance;\n}\n\nexport function getLegacySdkInstanceFromWindow(): LegacySdkInstance | undefined {\n const browserWindow = getBrowserWindow() as DmdWindow | undefined;\n return browserWindow?.__DriveMetaDataSDKInstance;\n}\n\nexport function ensureLegacySdkLoaded(): LegacySdkConstructor {\n if (!isBrowserRuntime()) {\n throw new Error('DMD legacy SDK is only available in a browser runtime');\n }\n\n const browserWindow = getBrowserWindow() as DmdWindow | undefined;\n if (!browserWindow?.DriveMetaDataSDK) {\n throw new Error('DMD legacy SDK constructor is missing from window.DriveMetaDataSDK');\n }\n\n return browserWindow.DriveMetaDataSDK;\n}\n","import { normalizeBrowserConfig } from '../core/config';\nimport type { DmdDroppedEventDiagnostic, DmdDroppedEventType } from '../core/diagnostics';\nimport type {\n DmdBrowserClient,\n DmdBrowserConfig,\n DmdConsentInput,\n DmdEventOptions,\n DmdHealthStatus\n} from '../core/types';\nimport { DriveMetaDataSDK } from './core/DriveMetaDataSDK';\nimport {\n ensureLegacySdkLoaded,\n getLegacySdkInstanceFromWindow,\n type LegacySdkInstance\n} from './legacy-loader';\n\ntype DmdRuntimeInstance = LegacySdkInstance | DriveMetaDataSDK;\n\nexport interface DmdBrowserClientWithLegacy extends DmdBrowserClient {\n __legacy: DmdRuntimeInstance;\n}\n\nlet singleton: DmdRuntimeInstance | undefined;\nlet publicSingleton: DmdBrowserClientWithLegacy | undefined;\nlet droppedEvents = 0;\nlet lastError: string | undefined;\nlet lastDroppedEvent: DmdDroppedEventDiagnostic | undefined;\n\nfunction createPublicClient(instance: DmdRuntimeInstance): DmdBrowserClientWithLegacy {\n return {\n __legacy: instance,\n track(event, properties, options) {\n if (instance.trackEvent) {\n instance.trackEvent(event, properties, options);\n return;\n }\n instance.sendEvent?.({ eventName: event, event, properties, options });\n },\n identify(userId, traits, options) {\n if (instance.identify) {\n instance.identify(userId, traits, options);\n return;\n }\n instance.identifyUser?.(userId, traits);\n },\n page(name, properties, options) {\n if (instance.page) {\n instance.page(name, properties, options);\n return;\n }\n instance.trackPageview?.();\n },\n group(groupId, traits, options) {\n instance.group?.(groupId, traits, options);\n },\n alias(previousId, userId, options) {\n instance.alias?.(previousId, userId, options);\n },\n async flush() {\n await instance.flush?.();\n },\n reset() {\n instance.reset?.();\n singleton = undefined;\n publicSingleton = undefined;\n },\n setConsent(consent) {\n if (instance.setConsent) {\n instance.setConsent(consent);\n return;\n }\n if (typeof consent === 'string') {\n instance.gdprConsent = consent;\n }\n },\n getHealth() {\n if (instance.getHealth) {\n return instance.getHealth() as DmdHealthStatus;\n }\n return getDmdHealth();\n }\n };\n}\n\nfunction setSingleton(instance: DmdRuntimeInstance): DmdBrowserClientWithLegacy {\n singleton = instance;\n publicSingleton = createPublicClient(instance);\n return publicSingleton;\n}\n\nfunction recordDroppedEvent(type: DmdDroppedEventType, event?: string): void {\n droppedEvents += 1;\n lastDroppedEvent = {\n type,\n reason: 'not_initialized',\n timestamp: new Date().toISOString()\n };\n if (event !== undefined) {\n lastDroppedEvent.event = event;\n }\n lastError = `DMD SDK ${type} called before initialization`;\n}\n\nexport function initDmdSDK(config: DmdBrowserConfig): DmdBrowserClientWithLegacy {\n if (publicSingleton) {\n return publicSingleton;\n }\n\n const legacyConfig = normalizeBrowserConfig(config);\n const existingInstance = getLegacySdkInstanceFromWindow();\n if (existingInstance) {\n return setSingleton(existingInstance);\n }\n\n try {\n let instance: DmdRuntimeInstance;\n try {\n const LegacySdk = ensureLegacySdkLoaded();\n instance = new LegacySdk(legacyConfig);\n } catch (error) {\n if (error instanceof Error && error.message.includes('constructor is missing')) {\n instance = new DriveMetaDataSDK(config);\n } else {\n throw error;\n }\n }\n return setSingleton(instance);\n } catch (error) {\n lastError = error instanceof Error ? error.message : String(error);\n throw error;\n }\n}\n\nexport function getDmdSDK(): DmdBrowserClientWithLegacy | undefined {\n return publicSingleton;\n}\n\nexport function track(event: string, properties?: Record<string, unknown>, options?: DmdEventOptions): void {\n const sdk = getDmdSDK();\n if (!sdk) {\n recordDroppedEvent('track', event);\n return;\n }\n sdk.track(event, properties, options);\n}\n\nexport function identify(userId: string, traits?: Record<string, unknown>, options?: DmdEventOptions): void {\n const sdk = getDmdSDK();\n if (!sdk) {\n recordDroppedEvent('identify');\n return;\n }\n sdk.identify(userId, traits, options);\n}\n\nexport function page(name?: string, properties?: Record<string, unknown>, options?: DmdEventOptions): void {\n const sdk = getDmdSDK();\n if (!sdk) {\n recordDroppedEvent('page');\n return;\n }\n sdk.page(name, properties, options);\n}\n\nexport function group(groupId: string, traits?: Record<string, unknown>, options?: DmdEventOptions): void {\n const sdk = getDmdSDK();\n if (!sdk) {\n recordDroppedEvent('group');\n return;\n }\n sdk.group(groupId, traits, options);\n}\n\nexport function alias(previousId: string, userId: string, options?: DmdEventOptions): void {\n const sdk = getDmdSDK();\n if (!sdk) {\n recordDroppedEvent('alias');\n return;\n }\n sdk.alias(previousId, userId, options);\n}\n\nexport async function flush(): Promise<void> {\n const sdk = getDmdSDK();\n if (!sdk) {\n recordDroppedEvent('flush');\n return;\n }\n await sdk.flush();\n}\n\nexport function reset(): void {\n singleton?.reset?.();\n singleton = undefined;\n publicSingleton = undefined;\n}\n\nexport function setConsent(consent: DmdConsentInput): void {\n getDmdSDK()?.setConsent(consent);\n}\n\nexport const consent = {\n update(state: DmdConsentInput): void {\n setConsent(state);\n }\n};\n\nexport async function ready(): Promise<DmdBrowserClientWithLegacy | undefined> {\n return getDmdSDK();\n}\n\nexport function getDmdHealth(): DmdHealthStatus {\n if (singleton?.getHealth) {\n return singleton.getHealth() as DmdHealthStatus;\n }\n\n const health: DmdHealthStatus = {\n initialized: Boolean(singleton?.initialized ?? singleton),\n consent: singleton?.gdprConsent ?? 'pending',\n queueSize: singleton?.queue?.length ?? 0,\n offline: Boolean(singleton?.offline),\n droppedEvents\n };\n\n if (lastError !== undefined) {\n health.lastError = lastError;\n }\n if (lastDroppedEvent !== undefined) {\n health.lastDroppedEvent = lastDroppedEvent;\n }\n\n return health;\n}\n\nexport function resetDmdSDKForTests(): void {\n singleton?.reset?.();\n singleton = undefined;\n publicSingleton = undefined;\n droppedEvents = 0;\n lastError = undefined;\n lastDroppedEvent = undefined;\n}\n","import React from 'react';\nimport {\n alias,\n flush,\n getDmdHealth,\n group,\n identify,\n page,\n reset,\n setConsent,\n track\n} from '../browser/client';\nimport type { DmdBrowserClient, DmdConsentInput, DmdEventOptions, DmdHealthStatus } from '../core/types';\nimport { DmdContext } from './DmdProvider';\n\nexport function useDmdSDK(): DmdBrowserClient | undefined {\n return React.useContext(DmdContext);\n}\n\nexport function useTrackEvent(): (\n event: string,\n properties?: Record<string, unknown>,\n options?: DmdEventOptions\n) => void {\n return React.useCallback((event: string, properties?: Record<string, unknown>, options?: DmdEventOptions) => {\n track(event, properties, options);\n }, []);\n}\n\nexport function useIdentify(): (userId: string, traits?: Record<string, unknown>) => void {\n return React.useCallback((userId: string, traits?: Record<string, unknown>) => {\n identify(userId, traits);\n }, []);\n}\n\nexport function usePage(): (\n name?: string,\n properties?: Record<string, unknown>,\n options?: DmdEventOptions\n) => void {\n return React.useCallback((name?: string, properties?: Record<string, unknown>, options?: DmdEventOptions) => {\n page(name, properties, options);\n }, []);\n}\n\nexport function useGroup(): (\n groupId: string,\n traits?: Record<string, unknown>,\n options?: DmdEventOptions\n) => void {\n return React.useCallback((groupId: string, traits?: Record<string, unknown>, options?: DmdEventOptions) => {\n group(groupId, traits, options);\n }, []);\n}\n\nexport function useAlias(): (previousId: string, userId: string, options?: DmdEventOptions) => void {\n return React.useCallback((previousId: string, userId: string, options?: DmdEventOptions) => {\n alias(previousId, userId, options);\n }, []);\n}\n\nexport function useReset(): () => void {\n return React.useCallback(() => {\n reset();\n }, []);\n}\n\nexport function useDmdFlush(): () => Promise<void> {\n return React.useCallback(async () => {\n await flush();\n }, []);\n}\n\nexport function useDmdConsent(): (consent: DmdConsentInput) => void {\n return React.useCallback((consent: DmdConsentInput) => {\n setConsent(consent);\n }, []);\n}\n\nexport function useDmdHealth(): DmdHealthStatus {\n const client = useDmdSDK();\n const [health, setHealth] = React.useState<DmdHealthStatus>(() => getDmdHealth());\n\n React.useEffect(() => {\n setHealth(getDmdHealth());\n }, [client]);\n\n return health;\n}\n"],"mappings":"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","names":["createId","lastError","React","React"]}
@@ -0,0 +1,106 @@
1
+ type DmdDroppedEventType = 'track' | 'identify' | 'page' | 'group' | 'alias' | 'consent' | 'flush';
2
+ type DmdDroppedEventReason = 'not_initialized' | 'consent_denied' | 'invalid_payload' | 'before_send_dropped' | 'storage_unavailable';
3
+ interface DmdDroppedEventDiagnostic {
4
+ type: DmdDroppedEventType;
5
+ reason: DmdDroppedEventReason;
6
+ event?: string;
7
+ timestamp: string;
8
+ }
9
+
10
+ type DmdConsentState = 'granted' | 'denied' | 'pending';
11
+ type DmdConsentPurpose = 'analytics' | 'advertising' | 'personalization' | 'functional' | 'saleOfData';
12
+ type DmdPurposeConsent = Partial<Record<DmdConsentPurpose, DmdConsentState>>;
13
+ type DmdConsentInput = DmdConsentState | boolean | DmdPurposeConsent;
14
+ type DmdPersistenceMode = 'localStorage+cookie' | 'localStorage' | 'cookie' | 'memory' | 'none';
15
+ type DmdDeliveryDropReason = 'queue_limit_exceeded' | 'queue_ttl_expired' | 'payload_too_large' | 'consent_revoked' | 'queue_corrupt' | 'manual_clear';
16
+ interface DmdDeliveryEventDiagnostic {
17
+ messageId?: string;
18
+ reason: DmdDeliveryDropReason | string;
19
+ timestamp: string;
20
+ }
21
+ interface DmdBrowserConfig {
22
+ clientId: string;
23
+ workspaceId: string;
24
+ appId: string;
25
+ writeKey: string;
26
+ /**
27
+ * Legacy CDN compatibility only. Browser tokens are not treated as secrets.
28
+ * New npm integrations should use writeKey.
29
+ */
30
+ token?: string;
31
+ apiHost?: string;
32
+ uiHost?: string;
33
+ deeplink?: string;
34
+ debug?: boolean;
35
+ consent?: DmdConsentInput;
36
+ gdprConsent?: DmdConsentInput;
37
+ autocapture?: boolean;
38
+ capturePageview?: boolean;
39
+ capturePageleave?: boolean;
40
+ captureDeadClicks?: boolean;
41
+ crossSubdomainCookie?: boolean;
42
+ disablePersistence?: boolean;
43
+ disableSurveys?: boolean;
44
+ disableSessionRecording?: boolean;
45
+ enableHeatmaps?: boolean;
46
+ maskAllText?: boolean;
47
+ maskAllElementAttributes?: boolean;
48
+ persistence?: DmdPersistenceMode;
49
+ propertyDenylist?: string[];
50
+ sessionIdleTimeoutSeconds?: number;
51
+ schemaValidation?: 'off' | 'warn' | 'strict';
52
+ delivery?: {
53
+ maxQueueSize?: number;
54
+ queueTtlMs?: number;
55
+ retryDelayMs?: number;
56
+ maxRetryDelayMs?: number;
57
+ maxPayloadBytes?: number;
58
+ batchSize?: number;
59
+ disableLifecycleFlush?: boolean;
60
+ };
61
+ onDrop?: (event: DmdDeliveryEventDiagnostic) => void;
62
+ onError?: (error: Error) => void;
63
+ beforeSend?: (event: DmdEventPayload) => DmdEventPayload | null | Promise<DmdEventPayload | null>;
64
+ }
65
+ interface DmdEventPayload {
66
+ event: string;
67
+ properties?: Record<string, unknown>;
68
+ userId?: string;
69
+ anonymousId?: string;
70
+ timestamp?: string;
71
+ }
72
+ interface DmdHealthStatus {
73
+ initialized: boolean;
74
+ consent: DmdConsentState;
75
+ consentPurposes?: Record<DmdConsentPurpose, DmdConsentState>;
76
+ queueSize: number;
77
+ offline: boolean;
78
+ droppedEvents: number;
79
+ lastError?: string;
80
+ lastDroppedEvent?: DmdDroppedEventDiagnostic;
81
+ delivery?: {
82
+ queued: number;
83
+ inFlight: number;
84
+ dropped: DmdDeliveryEventDiagnostic[];
85
+ lastError?: string;
86
+ };
87
+ }
88
+ interface DmdBrowserClient {
89
+ track(event: string, properties?: Record<string, unknown>, options?: DmdEventOptions): void;
90
+ identify(userId: string, traits?: Record<string, unknown>, options?: DmdEventOptions): void;
91
+ page(name?: string, properties?: Record<string, unknown>, options?: DmdEventOptions): void;
92
+ group(groupId: string, traits?: Record<string, unknown>, options?: DmdEventOptions): void;
93
+ alias(previousId: string, userId: string, options?: DmdEventOptions): void;
94
+ flush(): Promise<void>;
95
+ reset(): void;
96
+ setConsent(consent: DmdConsentInput): void;
97
+ getHealth(): DmdHealthStatus;
98
+ }
99
+ interface DmdEventOptions {
100
+ messageId?: string;
101
+ timestamp?: string;
102
+ context?: Record<string, unknown>;
103
+ integrations?: Record<string, boolean>;
104
+ }
105
+
106
+ export type { DmdBrowserClient as D, DmdBrowserConfig as a, DmdConsentInput as b, DmdConsentPurpose as c, DmdConsentState as d, DmdDeliveryDropReason as e, DmdDeliveryEventDiagnostic as f, DmdDroppedEventDiagnostic as g, DmdDroppedEventReason as h, DmdDroppedEventType as i, DmdEventOptions as j, DmdEventPayload as k, DmdHealthStatus as l };
@@ -0,0 +1,106 @@
1
+ type DmdDroppedEventType = 'track' | 'identify' | 'page' | 'group' | 'alias' | 'consent' | 'flush';
2
+ type DmdDroppedEventReason = 'not_initialized' | 'consent_denied' | 'invalid_payload' | 'before_send_dropped' | 'storage_unavailable';
3
+ interface DmdDroppedEventDiagnostic {
4
+ type: DmdDroppedEventType;
5
+ reason: DmdDroppedEventReason;
6
+ event?: string;
7
+ timestamp: string;
8
+ }
9
+
10
+ type DmdConsentState = 'granted' | 'denied' | 'pending';
11
+ type DmdConsentPurpose = 'analytics' | 'advertising' | 'personalization' | 'functional' | 'saleOfData';
12
+ type DmdPurposeConsent = Partial<Record<DmdConsentPurpose, DmdConsentState>>;
13
+ type DmdConsentInput = DmdConsentState | boolean | DmdPurposeConsent;
14
+ type DmdPersistenceMode = 'localStorage+cookie' | 'localStorage' | 'cookie' | 'memory' | 'none';
15
+ type DmdDeliveryDropReason = 'queue_limit_exceeded' | 'queue_ttl_expired' | 'payload_too_large' | 'consent_revoked' | 'queue_corrupt' | 'manual_clear';
16
+ interface DmdDeliveryEventDiagnostic {
17
+ messageId?: string;
18
+ reason: DmdDeliveryDropReason | string;
19
+ timestamp: string;
20
+ }
21
+ interface DmdBrowserConfig {
22
+ clientId: string;
23
+ workspaceId: string;
24
+ appId: string;
25
+ writeKey: string;
26
+ /**
27
+ * Legacy CDN compatibility only. Browser tokens are not treated as secrets.
28
+ * New npm integrations should use writeKey.
29
+ */
30
+ token?: string;
31
+ apiHost?: string;
32
+ uiHost?: string;
33
+ deeplink?: string;
34
+ debug?: boolean;
35
+ consent?: DmdConsentInput;
36
+ gdprConsent?: DmdConsentInput;
37
+ autocapture?: boolean;
38
+ capturePageview?: boolean;
39
+ capturePageleave?: boolean;
40
+ captureDeadClicks?: boolean;
41
+ crossSubdomainCookie?: boolean;
42
+ disablePersistence?: boolean;
43
+ disableSurveys?: boolean;
44
+ disableSessionRecording?: boolean;
45
+ enableHeatmaps?: boolean;
46
+ maskAllText?: boolean;
47
+ maskAllElementAttributes?: boolean;
48
+ persistence?: DmdPersistenceMode;
49
+ propertyDenylist?: string[];
50
+ sessionIdleTimeoutSeconds?: number;
51
+ schemaValidation?: 'off' | 'warn' | 'strict';
52
+ delivery?: {
53
+ maxQueueSize?: number;
54
+ queueTtlMs?: number;
55
+ retryDelayMs?: number;
56
+ maxRetryDelayMs?: number;
57
+ maxPayloadBytes?: number;
58
+ batchSize?: number;
59
+ disableLifecycleFlush?: boolean;
60
+ };
61
+ onDrop?: (event: DmdDeliveryEventDiagnostic) => void;
62
+ onError?: (error: Error) => void;
63
+ beforeSend?: (event: DmdEventPayload) => DmdEventPayload | null | Promise<DmdEventPayload | null>;
64
+ }
65
+ interface DmdEventPayload {
66
+ event: string;
67
+ properties?: Record<string, unknown>;
68
+ userId?: string;
69
+ anonymousId?: string;
70
+ timestamp?: string;
71
+ }
72
+ interface DmdHealthStatus {
73
+ initialized: boolean;
74
+ consent: DmdConsentState;
75
+ consentPurposes?: Record<DmdConsentPurpose, DmdConsentState>;
76
+ queueSize: number;
77
+ offline: boolean;
78
+ droppedEvents: number;
79
+ lastError?: string;
80
+ lastDroppedEvent?: DmdDroppedEventDiagnostic;
81
+ delivery?: {
82
+ queued: number;
83
+ inFlight: number;
84
+ dropped: DmdDeliveryEventDiagnostic[];
85
+ lastError?: string;
86
+ };
87
+ }
88
+ interface DmdBrowserClient {
89
+ track(event: string, properties?: Record<string, unknown>, options?: DmdEventOptions): void;
90
+ identify(userId: string, traits?: Record<string, unknown>, options?: DmdEventOptions): void;
91
+ page(name?: string, properties?: Record<string, unknown>, options?: DmdEventOptions): void;
92
+ group(groupId: string, traits?: Record<string, unknown>, options?: DmdEventOptions): void;
93
+ alias(previousId: string, userId: string, options?: DmdEventOptions): void;
94
+ flush(): Promise<void>;
95
+ reset(): void;
96
+ setConsent(consent: DmdConsentInput): void;
97
+ getHealth(): DmdHealthStatus;
98
+ }
99
+ interface DmdEventOptions {
100
+ messageId?: string;
101
+ timestamp?: string;
102
+ context?: Record<string, unknown>;
103
+ integrations?: Record<string, boolean>;
104
+ }
105
+
106
+ export type { DmdBrowserClient as D, DmdBrowserConfig as a, DmdConsentInput as b, DmdConsentPurpose as c, DmdConsentState as d, DmdDeliveryDropReason as e, DmdDeliveryEventDiagnostic as f, DmdDroppedEventDiagnostic as g, DmdDroppedEventReason as h, DmdDroppedEventType as i, DmdEventOptions as j, DmdEventPayload as k, DmdHealthStatus as l };
@@ -0,0 +1,106 @@
1
+ # Angular Integration
2
+
3
+ ## Install
4
+
5
+ ```bash
6
+ npm install @drivemetadata/sdk
7
+ ```
8
+
9
+ ## Standalone App Setup
10
+
11
+ Add the provider to your Angular application config:
12
+
13
+ ```ts
14
+ import { ApplicationConfig } from '@angular/core';
15
+ import { provideDmdAnalytics } from '@drivemetadata/sdk/angular';
16
+
17
+ export const appConfig: ApplicationConfig = {
18
+ providers: [
19
+ provideDmdAnalytics({
20
+ clientId: 'client_xxx',
21
+ workspaceId: 'workspace_xxx',
22
+ appId: 'app_xxx',
23
+ writeKey: 'public_write_key',
24
+ consent: { analytics: 'granted', advertising: 'denied' }
25
+ })
26
+ ]
27
+ };
28
+ ```
29
+
30
+ Initialize the SDK once from your application shell:
31
+
32
+ ```ts
33
+ import { Component, OnInit } from '@angular/core';
34
+ import { DmdAnalyticsService } from '@drivemetadata/sdk/angular';
35
+
36
+ @Component({
37
+ selector: 'app-root',
38
+ template: '<router-outlet />'
39
+ })
40
+ export class AppComponent implements OnInit {
41
+ constructor(private readonly dmd: DmdAnalyticsService) {}
42
+
43
+ ngOnInit() {
44
+ this.dmd.init();
45
+ }
46
+ }
47
+ ```
48
+
49
+ ## Manual Initialization
50
+
51
+ If you do not use `provideDmdAnalytics`, pass config directly:
52
+
53
+ ```ts
54
+ this.dmd.init({
55
+ clientId: 'client_xxx',
56
+ workspaceId: 'workspace_xxx',
57
+ appId: 'app_xxx',
58
+ writeKey: 'public_write_key',
59
+ consent: { analytics: 'granted', advertising: 'denied' }
60
+ });
61
+ ```
62
+
63
+ ## Tracking Events
64
+
65
+ ```ts
66
+ this.dmd.track('Checkout Started', {
67
+ source: 'cart'
68
+ });
69
+ ```
70
+
71
+ ## Page, Group, Alias, And Flush
72
+
73
+ ```ts
74
+ this.dmd.page('Checkout', { source: 'cart' });
75
+ this.dmd.group('account_123', { tier: 'enterprise' });
76
+ this.dmd.alias('anonymous_123', 'user_123');
77
+ await this.dmd.flush();
78
+ ```
79
+
80
+ ## Identifying Users
81
+
82
+ ```ts
83
+ this.dmd.identify('user_123', {
84
+ plan: 'enterprise'
85
+ });
86
+ ```
87
+
88
+ ## Consent
89
+
90
+ ```ts
91
+ this.dmd.setConsent('granted');
92
+ ```
93
+
94
+ If consent is omitted, analytics defaults to `pending` and events are dropped until consent is granted.
95
+
96
+ ## Health
97
+
98
+ ```ts
99
+ console.log(this.dmd.getHealth());
100
+ ```
101
+
102
+ ## SSR Safety
103
+
104
+ `@drivemetadata/sdk/angular` can be imported in server-rendered Angular builds. SDK initialization must run only in the browser because the underlying browser SDK uses DOM, cookies, and storage.
105
+
106
+ For Angular Universal, inject `PLATFORM_ID` in your application shell and call `this.dmd.init()` only when `isPlatformBrowser(platformId)` is true.
package/docs/index.md ADDED
@@ -0,0 +1,19 @@
1
+ # DriveMetaData SDK Documentation
2
+
3
+ ## Integration Guides
4
+
5
+ - [Browser NPM SDK](./npm-browser-sdk.md)
6
+ - [React and Next.js](./react-next-integration.md)
7
+ - [Angular](./angular-integration.md)
8
+ - [Node Server](./node-server-integration.md)
9
+
10
+ ## Enterprise Readiness
11
+
12
+ - [Security and Privacy](./security-privacy.md)
13
+ - [CDN to NPM Migration](./migration-cdn-to-npm.md)
14
+ - [Release Checklist](./release-checklist.md)
15
+
16
+ ## Existing SDK References
17
+
18
+ - [SDK v3 Deep Analysis](./dmd-sdk-v3-deep-analysis.md)
19
+ - [SDK v3 Test Cases](./dmd-sdk-v3-test-cases.md)
@@ -0,0 +1,99 @@
1
+ # CDN to NPM Migration
2
+
3
+ The existing CDN script remains supported:
4
+
5
+ ```html
6
+ <script src="https://example-cdn/drivemetadata/dmdSDK_v3.js"></script>
7
+ ```
8
+
9
+ The npm SDK adds typed imports and framework adapters.
10
+
11
+ ## Before
12
+
13
+ ```html
14
+ <script src="/dmdSDK_v3.js"></script>
15
+ <script>
16
+ window.dmdSDK = new window.DriveMetaDataSDK({
17
+ client_id: 'client_xxx',
18
+ workspace_id: 'workspace_xxx',
19
+ app_id: 'app_xxx',
20
+ writeKey: 'public_write_key',
21
+ consent: { analytics: 'granted', advertising: 'denied' }
22
+ });
23
+ window.dmdSDK.trackEvent('Product Viewed', { sku: 'sku_123' });
24
+ </script>
25
+ ```
26
+
27
+ ## After
28
+
29
+ ```ts
30
+ import { initDmdSDK, track } from '@drivemetadata/sdk/browser';
31
+
32
+ initDmdSDK({
33
+ clientId: 'client_xxx',
34
+ workspaceId: 'workspace_xxx',
35
+ appId: 'app_xxx',
36
+ writeKey: 'public_write_key',
37
+ consent: { analytics: 'granted', advertising: 'denied' }
38
+ });
39
+
40
+ track('Product Viewed', { sku: 'sku_123' });
41
+ ```
42
+
43
+ ## Config Mapping
44
+
45
+ | CDN config | NPM config |
46
+ | --- | --- |
47
+ | `client_id` | `clientId` |
48
+ | `workspace_id` | `workspaceId` |
49
+ | `app_id` | `appId` |
50
+ | `token` | `writeKey` |
51
+ | `api_host` | `apiHost` |
52
+ | `capture_pageview` | `capturePageview` |
53
+ | `capture_pageleave` | `capturePageleave` |
54
+ | `capture_dead_clicks` | `captureDeadClicks` |
55
+ | `disable_persistence` | `disablePersistence` |
56
+ | `mask_all_text` | `maskAllText` |
57
+ | `mask_all_element_attributes` | `maskAllElementAttributes` |
58
+
59
+ ## Compatibility
60
+
61
+ The npm browser entry no longer requires a global CDN constructor. The global CDN script path remains available for customers who cannot move to npm immediately.
62
+
63
+ ## Behavior Parity Contract
64
+
65
+ | Behavior | CDN `dmdSDK_v3.js` | npm browser SDK | Release Requirement |
66
+ |---|---|---|---|
67
+ | `track` | Sends event payload with configured client/workspace/app IDs | Same public event semantics | Covered by parity fixture |
68
+ | `page` | Supports page view tracking | Same public page API | Covered by parity fixture |
69
+ | `identify` | Associates user traits | Same public identify API | Covered by parity fixture |
70
+ | `group` | Associates account/group traits when available | Same public group API | Covered by parity fixture |
71
+ | `alias` | Links previous and current IDs when available | Same public alias API | Covered by parity fixture |
72
+ | Consent denied | Drops analytics events | Drops analytics events and purges queue | Covered by consent tests |
73
+ | Offline failure | Queues where supported | Persists queue in browser storage | Covered by delivery tests |
74
+ | PII masking | Legacy masking behavior | Recursive property sanitization | Covered by privacy tests |
75
+
76
+ ## Legacy Parity Release Rule
77
+
78
+ Before public npm release, the parity fixture suite must cover:
79
+
80
+ - track
81
+ - page
82
+ - identify
83
+ - group
84
+ - alias
85
+ - consent denied
86
+ - consent revocation queue purge
87
+ - nested PII redaction
88
+ - offline queue persistence
89
+ - reset cleanup
90
+
91
+ The CDN script remains supported during migration. New framework integrations should use npm entry points.
92
+
93
+ Behavior differences:
94
+
95
+ - `track()` uses the SDK event enrichment and delivery path.
96
+ - Browser `token` terminology is replaced by `writeKey`.
97
+ - Runtime purpose-level consent can be updated with `consent.update()`.
98
+ - npm browser analytics defaults to `pending` when consent is omitted.
99
+ - Health diagnostics are available through `getDmdHealth()`.