Skip to content

Commit def99f3

Browse files
authored
Merge pull request #17 from zenstackhq/dev
fix: shows v3 not supported message
2 parents 004579b + 13b76e0 commit def99f3

6 files changed

Lines changed: 59 additions & 40 deletions

File tree

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@zenstackhq/proxy",
3-
"version": "0.2.1",
3+
"version": "0.2.3",
44
"description": "A CLI tool to run an Express server that proxies CRUD requests to a ZenStack backend",
55
"main": "index.js",
66
"publishConfig": {
@@ -33,7 +33,8 @@
3333
"express": "^4.19.2",
3434
"mixpanel": "^0.19.1",
3535
"semver": "^7.7.3",
36-
"tsx": "^4.20.6"
36+
"tsx": "^4.20.6",
37+
"uuid": "^13.0.0"
3738
},
3839
"devDependencies": {
3940
"@types/cors": "^2.8.17",

pnpm-lock.yaml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import 'dotenv/config'
1010
import { getVersion } from './utils/version-utils'
1111
import { telemetry } from './telemetry'
1212
import { CliError } from './cli-error'
13-
1413
export function createProgram() {
1514
const program = new Command()
1615

@@ -32,7 +31,7 @@ export function createProgram() {
3231
: path.join(process.cwd(), options.schema)
3332

3433
if (!fs.existsSync(zmodelPath)) {
35-
console.error(`Error: ZModel schema file not found: ${zmodelPath}`)
34+
console.error(`ZModel schema file not found: ${zmodelPath}`)
3635
console.error('Please provide a valid path using the -s option.')
3736
process.exit(1)
3837
}

src/telemetry.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import isDocker from './utils/is-docker'
88
import { isWsl } from './utils/is-wsl'
99
import { getMachineId } from './utils/machine-id-utils'
1010
import { getPrismaVersion, getVersion } from './utils/version-utils'
11+
import { v5 as uuidv5 } from 'uuid'
1112

1213
/**
1314
* Telemetry events
@@ -18,7 +19,7 @@ export type TelemetryEvents = 'proxy:start' | 'proxy:complete' | 'proxy:error'
1819
*/
1920
export class Telemetry {
2021
private readonly mixpanel: Mixpanel | undefined
21-
private readonly hostId = getMachineId()
22+
private readonly hostId = this.getDeviceId()
2223
private readonly sessionid = randomUUID()
2324
private readonly _os_type = os.type()
2425
private readonly _os_release = os.release()
@@ -40,6 +41,12 @@ export class Telemetry {
4041
}
4142
}
4243

44+
private getDeviceId() {
45+
const hostId = getMachineId()
46+
// namespace UUID for generating UUIDv5 from DNS 'zenstack.dev'
47+
return uuidv5(hostId, '133cac15-3efb-50fa-b5fc-4b90e441e563')
48+
}
49+
4350
get isTracking() {
4451
return !!this.mixpanel
4552
}

src/utils/machine-id-utils.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// modified from https://github.com/automation-stack/node-machine-id
22

33
import { execSync } from 'child_process'
4-
import { createHash, randomUUID } from 'node:crypto'
4+
import { createHash } from 'node:crypto'
5+
import { v4 as uuid } from 'uuid'
56

67
const { platform } = process
78
const win32RegBinPath = {
@@ -31,7 +32,7 @@ function hash(guid: string): string {
3132
return createHash('sha256').update(guid).digest('hex')
3233
}
3334

34-
function expose(result: string): string | undefined {
35+
function expose(result: string): string {
3536
switch (platform) {
3637
case 'darwin':
3738
return result
@@ -62,16 +63,13 @@ function expose(result: string): string | undefined {
6263

6364
export function getMachineId() {
6465
if (!(platform in guid)) {
65-
return randomUUID()
66+
return uuid()
6667
}
6768
try {
6869
const value = execSync(guid[platform as keyof typeof guid])
6970
const id = expose(value.toString())
70-
if (!id) {
71-
return randomUUID()
72-
}
7371
return hash(id)
7472
} catch {
75-
return randomUUID()
73+
return uuid()
7674
}
7775
}

src/zmodel-parser.ts

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,9 @@ function loadPrismaConfig(schemaDir: string): string | null {
7171

7272
// Use Function constructor to safely evaluate the object literal
7373
// This is safer than eval as it doesn't have access to the local scope
74-
try {
75-
const configFn = new Function('env', `return ${configObjectStr}`)
76-
const config = configFn(env)
77-
78-
return config?.datasource?.url || null
79-
} catch (evalError) {
80-
console.warn(`Warning: Could not evaluate config object: ${evalError}`)
81-
return null
82-
}
74+
const configFn = new Function('env', `return ${configObjectStr}`)
75+
const config = configFn(env)
76+
return config?.datasource?.url
8377
} catch (error) {
8478
if (error instanceof Error && error.message.includes('Environment variable')) {
8579
throw error
@@ -117,34 +111,43 @@ function parseDatasource(
117111
return { provider, url: datasourceUrlOverride }
118112
}
119113

120-
// Extract url from schema
121-
let urlMatch = datasourceBlock.match(/url\s*=\s*['"]([^'"]+)['"]/)
114+
// Extract url value using single regex (could be string literal, env() call, or expression)
115+
const urlMatch = datasourceBlock.match(/url\s*=\s*([^\n]+)/)
122116
let url: string | null = null
123117

124118
if (urlMatch) {
125-
url = urlMatch[1]
126-
} else {
127-
// Try to match env("xxx")
128-
const envMatch = datasourceBlock.match(/url\s*=\s*env\(\s*['"]([^'"]+)['"]\s*\)/)
129-
if (envMatch) {
130-
const envVar = envMatch[1]
131-
const envValue = process.env[envVar]
132-
if (envValue) {
133-
url = envValue
119+
const urlValueStr = urlMatch[1].trim()
120+
121+
// Create env helper function
122+
const env = (varName: string) => {
123+
const value = process.env[varName]
124+
if (!value) {
125+
throw new CliError(`Environment variable ${varName} is not set`)
134126
}
127+
return value
135128
}
136-
}
137129

138-
// If no URL found in schema, try prisma.config.ts (Prisma 7)
139-
if (!url) {
130+
try {
131+
// Use Function constructor to evaluate the url value
132+
const urlFn = new Function('env', `return ${urlValueStr}`)
133+
url = urlFn(env)
134+
} catch (evalError) {
135+
throw new CliError(
136+
'Could not evaluate datasource url from schema, you could provide it via -d option.'
137+
)
138+
}
139+
} else {
140140
url = loadPrismaConfig(schemaDir)
141+
// If still no URL found, throw error
142+
if (url == null) {
143+
throw new CliError(
144+
'No datasource URL found. For Prisma 7, ensure prisma.config.ts exists with datasource configuration, or provide the URL via -d option.'
145+
)
146+
}
141147
}
142148

143-
// If still no URL found, throw error
144149
if (!url) {
145-
throw new CliError(
146-
'No datasource URL found. For Prisma 7, ensure prisma.config.ts exists with datasource configuration, or provide the URL via --datasource-url option.'
147-
)
150+
throw new CliError('datasource url has no value, you could provide it via -d option.')
148151
}
149152

150153
return { provider, url }
@@ -157,7 +160,9 @@ function parseGenerator(content: string): GeneratorConfig {
157160
// Match generator block for prisma client
158161
const generatorMatch = content.match(/generator\s+\w+\s*\{([^}]+)\}/s)
159162
if (!generatorMatch) {
160-
throw new CliError('No generator block found in zmodel schema')
163+
throw new CliError(
164+
'No generator block found in zmodel schema.\nZenStack V3 is not supported, V3 will have built-in proxy support soon.'
165+
)
161166
}
162167

163168
const generatorBlock = generatorMatch[1]

0 commit comments

Comments
 (0)