From c4e543f8d4a691def3b7cbaa8254f9feb9a51e9e Mon Sep 17 00:00:00 2001 From: Julian Labeit Date: Wed, 3 Sep 2025 16:48:33 +0200 Subject: [PATCH 1/2] feat(mixpanel): allow also tracking server side events --- README.md | 1 + src/generators/typescripts.ts | 21 +++++++++++++++++++-- src/index.ts | 10 ++++++++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 97d0f90..a4336ce 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ npx lexigen -u -s -p { return event.schemaJson.description ? `/**\n * ${event.schemaJson.description}\n */\n` : '' } -export const generate = async (events: EventSchema[]): Promise => { +export const generate = async (events: EventSchema[], serverSide: boolean): Promise => { const formattedEvents = await Promise.all(events.map(async event => { const interfaceName = `${pascalCase(event.name)}Properties` const functionName = `track${pascalCase(event.name)}Event` const params = await generateParamsForEvent(event, interfaceName) const shouldParamsBeOptional = !Object.keys(event.schemaJson.properties ?? {}).length // eslint-disable-next-line max-len + if (serverSide) { + return `${params}\n${formatDescription(event)}export const ${functionName} = (distinct_id: string, properties${shouldParamsBeOptional ? '?' : ''}: ${interfaceName}) => mixpanel?.track('${event.name}', { distinct_id, ...properties })` + } + // eslint-disable-next-line max-len return `${params}\n${formatDescription(event)}export const ${functionName} = (properties${shouldParamsBeOptional ? '?' : ''}: ${interfaceName}) => mixpanel.track('${event.name}', properties)` })) - return `/* eslint-disable */\nimport mixpanel from 'mixpanel-browser'\n\n${formattedEvents.join('\n\n')}` + if (serverSide) { + return `/* eslint-disable */ +import Mixpanel from 'mixpanel' + +let mixpanel: Mixpanel.Mixpanel | undefined +export const initMixpanel = (token: string) => { + mixpanel = Mixpanel.init(token) +} +${formattedEvents.join('\n\n')}` + } + return ` +/* eslint-disable */ +import mixpanel from 'mixpanel-browser' +${formattedEvents.join('\n\n')}` } diff --git a/src/index.ts b/src/index.ts index 8f94779..2599427 100644 --- a/src/index.ts +++ b/src/index.ts @@ -18,7 +18,7 @@ const generators: Record = { dart: generateDart, } -const { username, secret, project, target, filter } = yargs(hideBin(process.argv)) +const { username, secret, project, target, filter, serverSide } = yargs(hideBin(process.argv)) .option('username', { alias: 'u', type: 'string', @@ -44,6 +44,12 @@ const { username, secret, project, target, filter } = yargs(hideBin(process.argv description: 'A target API to generate.', default: 'typescript', }) + .option('server-side', { + alias: 'ss', + type: 'boolean', + description: 'Generate server-side code.', + default: false, + }) .option('filter', { alias: 'f', type: 'string', @@ -52,5 +58,5 @@ const { username, secret, project, target, filter } = yargs(hideBin(process.argv .parseSync() fetchEventsSchema(username, secret, project, filter) - .then(generators[target as GenerationOptions]) + .then((schema) => generators[target as GenerationOptions](schema, serverSide)) .then(console.log) From c9cfa3e86f02a9f4880fad40b7662d8785f27919 Mon Sep 17 00:00:00 2001 From: Julian Labeit Date: Thu, 4 Sep 2025 13:15:34 +0200 Subject: [PATCH 2/2] fix: identify users correctly --- src/generators/typescripts.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/generators/typescripts.ts b/src/generators/typescripts.ts index 3fe86e3..eb5522b 100644 --- a/src/generators/typescripts.ts +++ b/src/generators/typescripts.ts @@ -28,7 +28,7 @@ export const generate = async (events: EventSchema[], serverSide: boolean): Prom const shouldParamsBeOptional = !Object.keys(event.schemaJson.properties ?? {}).length // eslint-disable-next-line max-len if (serverSide) { - return `${params}\n${formatDescription(event)}export const ${functionName} = (distinct_id: string, properties${shouldParamsBeOptional ? '?' : ''}: ${interfaceName}) => mixpanel?.track('${event.name}', { distinct_id, ...properties })` + return `${params}\n${formatDescription(event)}export const ${functionName} = async (userId: string, properties${shouldParamsBeOptional ? '?' : ''}: ${interfaceName}) => mixpanel?.track('${event.name}', { distinct_id: await sha256(userId), ...properties })` } // eslint-disable-next-line max-len return `${params}\n${formatDescription(event)}export const ${functionName} = (properties${shouldParamsBeOptional ? '?' : ''}: ${interfaceName}) => mixpanel.track('${event.name}', properties)` @@ -41,10 +41,15 @@ let mixpanel: Mixpanel.Mixpanel | undefined export const initMixpanel = (token: string) => { mixpanel = Mixpanel.init(token) } +const sha256 = async (str: string): Promise => { + const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(str)) + return Array.prototype.map.call(new Uint8Array(buf), x => (('00' + x.toString(16)).slice(-2))).join('').slice(0, 16) +} ${formattedEvents.join('\n\n')}` } return ` /* eslint-disable */ import mixpanel from 'mixpanel-browser' + ${formattedEvents.join('\n\n')}` }