diff --git a/package.json b/package.json index 5413685..e20dfbc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/proxy", - "version": "0.2.1", + "version": "0.2.2", "description": "A CLI tool to run an Express server that proxies CRUD requests to a ZenStack backend", "main": "index.js", "publishConfig": { @@ -33,7 +33,8 @@ "express": "^4.19.2", "mixpanel": "^0.19.1", "semver": "^7.7.3", - "tsx": "^4.20.6" + "tsx": "^4.20.6", + "uuid": "^13.0.0" }, "devDependencies": { "@types/cors": "^2.8.17", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 003af7b..2457397 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,9 @@ importers: tsx: specifier: ^4.20.6 version: 4.21.0 + uuid: + specifier: ^13.0.0 + version: 13.0.0 devDependencies: '@types/cors': specifier: ^2.8.17 @@ -1041,6 +1044,10 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} + uuid@13.0.0: + resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==} + hasBin: true + uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true @@ -2054,6 +2061,8 @@ snapshots: utils-merge@1.0.1: {} + uuid@13.0.0: {} + uuid@9.0.1: {} vary@1.1.2: {} diff --git a/src/index.ts b/src/index.ts index 54e1fb3..93d4712 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,7 +10,6 @@ import 'dotenv/config' import { getVersion } from './utils/version-utils' import { telemetry } from './telemetry' import { CliError } from './cli-error' - export function createProgram() { const program = new Command() @@ -32,7 +31,7 @@ export function createProgram() { : path.join(process.cwd(), options.schema) if (!fs.existsSync(zmodelPath)) { - console.error(`Error: ZModel schema file not found: ${zmodelPath}`) + console.error(`ZModel schema file not found: ${zmodelPath}`) console.error('Please provide a valid path using the -s option.') process.exit(1) } diff --git a/src/telemetry.ts b/src/telemetry.ts index b614658..7cdbb14 100644 --- a/src/telemetry.ts +++ b/src/telemetry.ts @@ -8,6 +8,7 @@ import isDocker from './utils/is-docker' import { isWsl } from './utils/is-wsl' import { getMachineId } from './utils/machine-id-utils' import { getPrismaVersion, getVersion } from './utils/version-utils' +import { v5 as uuidv5 } from 'uuid' /** * Telemetry events @@ -18,7 +19,7 @@ export type TelemetryEvents = 'proxy:start' | 'proxy:complete' | 'proxy:error' */ export class Telemetry { private readonly mixpanel: Mixpanel | undefined - private readonly hostId = getMachineId() + private readonly hostId = this.getDeviceId() private readonly sessionid = randomUUID() private readonly _os_type = os.type() private readonly _os_release = os.release() @@ -40,6 +41,12 @@ export class Telemetry { } } + private getDeviceId() { + const hostId = getMachineId() + // namespace UUID for generating UUIDv5 from DNS 'zenstack.dev' + return uuidv5(hostId, '133cac15-3efb-50fa-b5fc-4b90e441e563') + } + get isTracking() { return !!this.mixpanel } diff --git a/src/utils/machine-id-utils.ts b/src/utils/machine-id-utils.ts index c3c89c5..5f29927 100644 --- a/src/utils/machine-id-utils.ts +++ b/src/utils/machine-id-utils.ts @@ -1,7 +1,8 @@ // modified from https://github.com/automation-stack/node-machine-id import { execSync } from 'child_process' -import { createHash, randomUUID } from 'node:crypto' +import { createHash } from 'node:crypto' +import { v4 as uuid } from 'uuid' const { platform } = process const win32RegBinPath = { @@ -31,7 +32,7 @@ function hash(guid: string): string { return createHash('sha256').update(guid).digest('hex') } -function expose(result: string): string | undefined { +function expose(result: string): string { switch (platform) { case 'darwin': return result @@ -62,16 +63,13 @@ function expose(result: string): string | undefined { export function getMachineId() { if (!(platform in guid)) { - return randomUUID() + return uuid() } try { const value = execSync(guid[platform as keyof typeof guid]) const id = expose(value.toString()) - if (!id) { - return randomUUID() - } return hash(id) } catch { - return randomUUID() + return uuid() } } diff --git a/src/zmodel-parser.ts b/src/zmodel-parser.ts index 9c7b2f2..7fb80d6 100644 --- a/src/zmodel-parser.ts +++ b/src/zmodel-parser.ts @@ -157,7 +157,9 @@ function parseGenerator(content: string): GeneratorConfig { // Match generator block for prisma client const generatorMatch = content.match(/generator\s+\w+\s*\{([^}]+)\}/s) if (!generatorMatch) { - throw new CliError('No generator block found in zmodel schema') + throw new CliError( + 'No generator block found in zmodel schema.\nZenStack V3 is not supported, V3 will have built-in proxy support soon.' + ) } const generatorBlock = generatorMatch[1]