- Add full Telegram bot functionality with Z.AI API integration
- Implement 4 tools: Bash, FileEdit, WebSearch, Git
- Add 3 agents: Code Reviewer, Architect, DevOps Engineer
- Add 6 skills for common coding tasks
- Add systemd service file for 24/7 operation
- Add nginx configuration for HTTPS webhook
- Add comprehensive documentation
- Implement WebSocket server for real-time updates
- Add logging system with Winston
- Add environment validation
🤖 zCode CLI X - Agentic coder with Z.AI + Telegram integration
1 line
15 KiB
Plaintext
1 line
15 KiB
Plaintext
{"version":3,"file":"growthbook-tracking.mjs","names":["loadSDKVersion","EVENT_EXPERIMENT_VIEWED","EVENT_FEATURE_EVALUATED","SDK_VERSION","parseString","value","parseAttributes","attributes","user_id","device_id","anonymous_id","id","page_id","session_id","utmCampaign","utmContent","utmMedium","utmSource","utmTerm","pageTitle","nested","topLevel","utm_campaign","undefined","utm_content","utm_medium","utm_source","utm_term","page_title","getEventPayload","eventName","properties","url","event_name","properties_json","sdk_language","sdk_version","context_json","track","clientKey","ingestorHost","events","length","endpoint","body","JSON","stringify","fetch","method","headers","Accept","credentials","e","console","error","growthbookTrackingPlugin","queueFlushInterval","enable","debug","dedupeCacheSize","dedupeKeyAttributes","eventFilter","gb","getClientKey","Error","eventCache","Set","_q","timer","flush","clearTimeout","promise","setEventLogger","userContext","data","dedupeKeyData","key","k","has","delete","add","size","oldest","values","next","payload","log","parse","push","Promise","resolve","reject","setTimeout","then","catch","document","visibilityState","addEventListener","onDestroy","window","prevEvents","Array","isArray","gbEvents","event","isDestroyed","logEvent"],"sources":["../../../src/plugins/growthbook-tracking.ts"],"sourcesContent":["import { loadSDKVersion } from \"../util\";\nimport type { Attributes, EventProperties } from \"../types/growthbook\";\nimport type { GrowthBook } from \"../GrowthBook\";\nimport type {\n GrowthBookClient,\n UserScopedGrowthBook,\n} from \"../GrowthBookClient\";\nimport { EVENT_EXPERIMENT_VIEWED, EVENT_FEATURE_EVALUATED } from \"../core\";\n\nconst SDK_VERSION = loadSDKVersion();\n\ntype GlobalTrackedEvent = {\n eventName: string;\n properties: Record<string, unknown>;\n};\ndeclare global {\n interface Window {\n gbEvents?:\n | (GlobalTrackedEvent | string)[]\n | {\n push: (event: GlobalTrackedEvent | string) => void;\n };\n }\n}\n\ntype EventPayload = {\n event_name: string;\n properties_json: Record<string, unknown>;\n sdk_language: string;\n sdk_version: string;\n url: string;\n context_json: Record<string, unknown>;\n user_id: string | null;\n device_id: string | null;\n page_id: string | null;\n session_id: string | null;\n page_title?: string;\n utm_source?: string;\n utm_medium?: string;\n utm_campaign?: string;\n utm_term?: string;\n utm_content?: string;\n};\n\nfunction parseString(value: unknown): null | string {\n return typeof value === \"string\" ? value : null;\n}\n\nfunction parseAttributes(attributes: Attributes): {\n nested: Attributes;\n topLevel: {\n user_id: string | null;\n device_id: string | null;\n page_id: string | null;\n session_id: string | null;\n page_title?: string;\n utm_source?: string;\n utm_medium?: string;\n utm_campaign?: string;\n utm_term?: string;\n utm_content?: string;\n };\n} {\n const {\n user_id,\n device_id,\n anonymous_id,\n id,\n page_id,\n session_id,\n utmCampaign,\n utmContent,\n utmMedium,\n utmSource,\n utmTerm,\n pageTitle,\n ...nested\n } = attributes;\n\n return {\n nested,\n topLevel: {\n user_id: parseString(user_id),\n device_id: parseString(device_id || anonymous_id || id),\n page_id: parseString(page_id),\n session_id: parseString(session_id),\n utm_campaign: parseString(utmCampaign) || undefined,\n utm_content: parseString(utmContent) || undefined,\n utm_medium: parseString(utmMedium) || undefined,\n utm_source: parseString(utmSource) || undefined,\n utm_term: parseString(utmTerm) || undefined,\n page_title: parseString(pageTitle) || undefined,\n },\n };\n}\n\ntype EventData = {\n eventName: string;\n properties: EventProperties;\n attributes: Attributes;\n url: string;\n};\n\nfunction getEventPayload({\n eventName,\n properties,\n attributes,\n url,\n}: EventData): EventPayload {\n const { nested, topLevel } = parseAttributes(attributes || {});\n\n return {\n event_name: eventName,\n properties_json: properties || {},\n ...topLevel,\n sdk_language: \"js\",\n sdk_version: SDK_VERSION,\n url: url,\n context_json: nested,\n };\n}\n\nasync function track({\n clientKey,\n ingestorHost,\n events,\n}: {\n events: EventPayload[];\n clientKey: string;\n ingestorHost?: string;\n}) {\n if (!events.length) return;\n\n const endpoint = `${\n ingestorHost || \"https://us1.gb-ingest.com\"\n }/track?client_key=${clientKey}`;\n const body = JSON.stringify(events);\n\n try {\n await fetch(endpoint, {\n method: \"POST\",\n body,\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"text/plain\",\n },\n credentials: \"omit\",\n });\n } catch (e) {\n console.error(\"Failed to track event\", e);\n }\n}\n\nexport function growthbookTrackingPlugin({\n queueFlushInterval = 100,\n ingestorHost,\n enable = true,\n debug,\n dedupeCacheSize = 1000,\n dedupeKeyAttributes = [],\n eventFilter,\n}: {\n // TODO: add option to allow filtering out certain attributes that contain PII\n queueFlushInterval?: number;\n ingestorHost?: string;\n enable?: boolean;\n debug?: boolean;\n dedupeCacheSize?: number;\n dedupeKeyAttributes?: string[];\n eventFilter?: (event: EventData) => boolean;\n} = {}) {\n return (gb: GrowthBook | UserScopedGrowthBook | GrowthBookClient) => {\n const clientKey = gb.getClientKey();\n if (!clientKey) {\n throw new Error(\"clientKey must be specified to use event logging\");\n }\n\n // LRU cache for events to avoid duplicates\n const eventCache = new Set<string>();\n\n if (\"setEventLogger\" in gb) {\n let _q: EventPayload[] = [];\n let timer: NodeJS.Timeout | null = null;\n const flush = async () => {\n const events = _q;\n _q = [];\n timer && clearTimeout(timer);\n timer = null;\n events.length && (await track({ clientKey, events, ingestorHost }));\n };\n\n let promise: Promise<void> | null = null;\n gb.setEventLogger(async (eventName, properties, userContext) => {\n const data: EventData = {\n eventName,\n properties,\n attributes: userContext.attributes || {},\n url: userContext.url || \"\",\n };\n\n // Skip logging if the event is being filtered\n if (eventFilter && !eventFilter(data)) {\n return;\n }\n\n // De-dupe Feature Evaluated and Experiment Viewed events\n if (\n eventName === EVENT_FEATURE_EVALUATED ||\n eventName === EVENT_EXPERIMENT_VIEWED\n ) {\n // Build the key for de-duping\n const dedupeKeyData: Record<string, unknown> = {\n eventName,\n properties,\n };\n for (const key of dedupeKeyAttributes) {\n dedupeKeyData[\"attr:\" + key] = data.attributes[key];\n }\n\n const k = JSON.stringify(dedupeKeyData);\n // Duplicate event fired recently, move to end of LRU cache and skip\n if (eventCache.has(k)) {\n eventCache.delete(k);\n eventCache.add(k);\n return;\n }\n eventCache.add(k);\n\n // If the cache is too big, remove the oldest item\n if (eventCache.size > dedupeCacheSize) {\n const oldest = eventCache.values().next().value;\n oldest && eventCache.delete(oldest);\n }\n }\n\n const payload = getEventPayload(data);\n\n debug &&\n console.log(\n \"Logging event to GrowthBook\",\n JSON.parse(JSON.stringify(payload)),\n );\n if (!enable) return;\n\n _q.push(payload);\n\n // Only one in-progress promise at a time\n if (!promise) {\n promise = new Promise((resolve, reject) => {\n // Flush the queue after a delay\n timer = setTimeout(() => {\n flush().then(resolve).catch(reject);\n promise = null;\n }, queueFlushInterval);\n });\n }\n await promise;\n });\n\n // Flush the queue on page unload\n if (typeof document !== \"undefined\" && document.visibilityState) {\n document.addEventListener(\"visibilitychange\", () => {\n if (document.visibilityState === \"hidden\") {\n flush().catch(console.error);\n }\n });\n }\n\n // Flush the queue when the growthbook instance is destroyed\n \"onDestroy\" in gb &&\n gb.onDestroy(() => {\n flush().catch(console.error);\n });\n }\n\n // Listen on window.gbEvents.push if in a browser\n // This makes it easier to integrate with Segment, GTM, etc.\n if (typeof window !== \"undefined\" && !(\"createScopedInstance\" in gb)) {\n const prevEvents = Array.isArray(window.gbEvents) ? window.gbEvents : [];\n window.gbEvents = {\n push: (event: GlobalTrackedEvent | string) => {\n if (\"isDestroyed\" in gb && gb.isDestroyed()) {\n // If trying to log and the instance has been destroyed, switch back to just an array\n // This will let the next GrowthBook instance pick it up\n window.gbEvents = [event];\n return;\n }\n\n if (typeof event === \"string\") {\n gb.logEvent(event);\n } else if (event) {\n gb.logEvent(event.eventName, event.properties);\n }\n },\n };\n for (const event of prevEvents) {\n window.gbEvents.push(event);\n }\n }\n };\n}\n"],"mappings":"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","ignoreList":[]} |