@zenstackhq/cli 3.0.0-alpha.9 → 3.0.0-beta.2

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.
package/dist/index.js CHANGED
@@ -1,10 +1,14 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, { get: all[name], enumerable: true });
6
+ };
3
7
 
4
8
  // src/index.ts
5
9
  import { ZModelLanguageMetaData } from "@zenstackhq/language";
6
- import colors5 from "colors";
7
- import { Command, Option } from "commander";
10
+ import colors7 from "colors";
11
+ import { Command, CommanderError, Option } from "commander";
8
12
 
9
13
  // src/actions/db.ts
10
14
  import fs2 from "fs";
@@ -12,10 +16,10 @@ import fs2 from "fs";
12
16
  // src/utils/exec-utils.ts
13
17
  import { execSync as _exec } from "child_process";
14
18
  function execSync(cmd, options) {
15
- const { env, ...restOptions } = options ?? {};
16
- const mergedEnv = env ? {
19
+ const { env: env2, ...restOptions } = options ?? {};
20
+ const mergedEnv = env2 ? {
17
21
  ...process.env,
18
- ...env
22
+ ...env2
19
23
  } : void 0;
20
24
  _exec(cmd, {
21
25
  encoding: "utf-8",
@@ -33,6 +37,7 @@ __name(execPackage, "execPackage");
33
37
 
34
38
  // src/actions/action-utils.ts
35
39
  import { loadDocument } from "@zenstackhq/language";
40
+ import { isDataSource } from "@zenstackhq/language/ast";
36
41
  import { PrismaSchemaGenerator } from "@zenstackhq/sdk";
37
42
  import colors from "colors";
38
43
  import fs from "fs";
@@ -53,6 +58,13 @@ function getSchemaFile(file) {
53
58
  }
54
59
  return file;
55
60
  }
61
+ const pkgJsonConfig = getPkgJsonConfig(process.cwd());
62
+ if (pkgJsonConfig.schema) {
63
+ if (!fs.existsSync(pkgJsonConfig.schema)) {
64
+ throw new CliError(`Schema file not found: ${pkgJsonConfig.schema}`);
65
+ }
66
+ return pkgJsonConfig.schema;
67
+ }
56
68
  if (fs.existsSync("./zenstack/schema.zmodel")) {
57
69
  return "./zenstack/schema.zmodel";
58
70
  } else if (fs.existsSync("./schema.zmodel")) {
@@ -65,12 +77,14 @@ __name(getSchemaFile, "getSchemaFile");
65
77
  async function loadSchemaDocument(schemaFile) {
66
78
  const loadResult = await loadDocument(schemaFile);
67
79
  if (!loadResult.success) {
68
- console.error(colors.red("Error loading schema:"));
69
80
  loadResult.errors.forEach((err) => {
70
81
  console.error(colors.red(err));
71
82
  });
72
- throw new CliError("Failed to load schema");
83
+ throw new CliError("Schema contains errors. See above for details.");
73
84
  }
85
+ loadResult.warnings.forEach((warn) => {
86
+ console.warn(colors.yellow(warn));
87
+ });
74
88
  return loadResult.model;
75
89
  }
76
90
  __name(loadSchemaDocument, "loadSchemaDocument");
@@ -82,14 +96,62 @@ function handleSubProcessError(err) {
82
96
  }
83
97
  }
84
98
  __name(handleSubProcessError, "handleSubProcessError");
85
- async function generateTempPrismaSchema(zmodelPath) {
99
+ async function generateTempPrismaSchema(zmodelPath, folder) {
86
100
  const model = await loadSchemaDocument(zmodelPath);
101
+ if (!model.declarations.some(isDataSource)) {
102
+ throw new CliError("Schema must define a datasource");
103
+ }
87
104
  const prismaSchema = await new PrismaSchemaGenerator(model).generate();
88
- const prismaSchemaFile = path.resolve(path.dirname(zmodelPath), "~schema.prisma");
105
+ if (!folder) {
106
+ folder = path.dirname(zmodelPath);
107
+ }
108
+ const prismaSchemaFile = path.resolve(folder, "~schema.prisma");
89
109
  fs.writeFileSync(prismaSchemaFile, prismaSchema);
90
110
  return prismaSchemaFile;
91
111
  }
92
112
  __name(generateTempPrismaSchema, "generateTempPrismaSchema");
113
+ function getPkgJsonConfig(startPath) {
114
+ const result = {
115
+ schema: void 0,
116
+ output: void 0
117
+ };
118
+ const pkgJsonFile = findUp([
119
+ "package.json"
120
+ ], startPath, false);
121
+ if (!pkgJsonFile) {
122
+ return result;
123
+ }
124
+ let pkgJson = void 0;
125
+ try {
126
+ pkgJson = JSON.parse(fs.readFileSync(pkgJsonFile, "utf8"));
127
+ } catch {
128
+ return result;
129
+ }
130
+ if (pkgJson.zenstack && typeof pkgJson.zenstack === "object") {
131
+ result.schema = pkgJson.zenstack.schema && path.resolve(path.dirname(pkgJsonFile), pkgJson.zenstack.schema);
132
+ result.output = pkgJson.zenstack.output && path.resolve(path.dirname(pkgJsonFile), pkgJson.zenstack.output);
133
+ }
134
+ return result;
135
+ }
136
+ __name(getPkgJsonConfig, "getPkgJsonConfig");
137
+ function findUp(names, cwd = process.cwd(), multiple = false, result = []) {
138
+ if (!names.some((name) => !!name)) {
139
+ return void 0;
140
+ }
141
+ const target = names.find((name) => fs.existsSync(path.join(cwd, name)));
142
+ if (multiple === false && target) {
143
+ return path.join(cwd, target);
144
+ }
145
+ if (target) {
146
+ result.push(path.join(cwd, target));
147
+ }
148
+ const up = path.resolve(cwd, "..");
149
+ if (up === cwd) {
150
+ return multiple && result.length > 0 ? result : void 0;
151
+ }
152
+ return findUp(names, up, multiple, result);
153
+ }
154
+ __name(findUp, "findUp");
93
155
 
94
156
  // src/actions/db.ts
95
157
  async function run(command, options) {
@@ -104,11 +166,15 @@ async function runPush(options) {
104
166
  const schemaFile = getSchemaFile(options.schema);
105
167
  const prismaSchemaFile = await generateTempPrismaSchema(schemaFile);
106
168
  try {
107
- const cmd = `prisma db push --schema "${prismaSchemaFile}"${options.acceptDataLoss ? " --accept-data-loss" : ""}${options.forceReset ? " --force-reset" : ""} --skip-generate`;
169
+ const cmd = [
170
+ "prisma db push",
171
+ ` --schema "${prismaSchemaFile}"`,
172
+ options.acceptDataLoss ? " --accept-data-loss" : "",
173
+ options.forceReset ? " --force-reset" : "",
174
+ " --skip-generate"
175
+ ].join("");
108
176
  try {
109
- await execPackage(cmd, {
110
- stdio: "inherit"
111
- });
177
+ await execPackage(cmd);
112
178
  } catch (err) {
113
179
  handleSubProcessError(err);
114
180
  }
@@ -123,30 +189,73 @@ __name(runPush, "runPush");
123
189
  // src/actions/generate.ts
124
190
  import { invariant } from "@zenstackhq/common-helpers";
125
191
  import { isPlugin } from "@zenstackhq/language/ast";
126
- import { PrismaSchemaGenerator as PrismaSchemaGenerator2, TsSchemaGenerator } from "@zenstackhq/sdk";
192
+ import { getLiteral, getLiteralArray } from "@zenstackhq/language/utils";
127
193
  import colors2 from "colors";
194
+ import path4 from "path";
195
+ import ora from "ora";
196
+
197
+ // src/plugins/index.ts
198
+ var plugins_exports = {};
199
+ __export(plugins_exports, {
200
+ prisma: () => prisma_default,
201
+ typescript: () => typescript_default
202
+ });
203
+
204
+ // src/plugins/prisma.ts
205
+ import { PrismaSchemaGenerator as PrismaSchemaGenerator2 } from "@zenstackhq/sdk";
128
206
  import fs3 from "fs";
129
207
  import path2 from "path";
130
- async function run2(options) {
131
- const schemaFile = getSchemaFile(options.schema);
132
- const model = await loadSchemaDocument(schemaFile);
133
- const outputPath = options.output ?? path2.dirname(schemaFile);
134
- const tsSchemaFile = path2.join(outputPath, "schema.ts");
135
- await new TsSchemaGenerator().generate(schemaFile, [], tsSchemaFile);
136
- await runPlugins(model, outputPath, tsSchemaFile);
137
- if (options.savePrismaSchema) {
208
+ var plugin = {
209
+ name: "Prisma Schema Generator",
210
+ statusText: "Generating Prisma schema",
211
+ async generate({ model, schemaFile, defaultOutputPath, pluginOptions }) {
212
+ let outFile = path2.join(defaultOutputPath, "schema.prisma");
213
+ if (typeof pluginOptions["output"] === "string") {
214
+ outFile = path2.resolve(path2.dirname(schemaFile), pluginOptions["output"]);
215
+ if (!fs3.existsSync(path2.dirname(outFile))) {
216
+ fs3.mkdirSync(path2.dirname(outFile), {
217
+ recursive: true
218
+ });
219
+ }
220
+ }
138
221
  const prismaSchema = await new PrismaSchemaGenerator2(model).generate();
139
- let prismaSchemaFile = path2.join(outputPath, "schema.prisma");
140
- if (typeof options.savePrismaSchema === "string") {
141
- prismaSchemaFile = path2.resolve(outputPath, options.savePrismaSchema);
142
- fs3.mkdirSync(path2.dirname(prismaSchemaFile), {
143
- recursive: true
144
- });
222
+ fs3.writeFileSync(outFile, prismaSchema);
223
+ }
224
+ };
225
+ var prisma_default = plugin;
226
+
227
+ // src/plugins/typescript.ts
228
+ import { TsSchemaGenerator } from "@zenstackhq/sdk";
229
+ import fs4 from "fs";
230
+ import path3 from "path";
231
+ var plugin2 = {
232
+ name: "TypeScript Schema Generator",
233
+ statusText: "Generating TypeScript schema",
234
+ async generate({ model, defaultOutputPath, pluginOptions }) {
235
+ let outDir = defaultOutputPath;
236
+ if (typeof pluginOptions["output"] === "string") {
237
+ outDir = path3.resolve(defaultOutputPath, pluginOptions["output"]);
238
+ if (!fs4.existsSync(outDir)) {
239
+ fs4.mkdirSync(outDir, {
240
+ recursive: true
241
+ });
242
+ }
145
243
  }
146
- fs3.writeFileSync(prismaSchemaFile, prismaSchema);
244
+ await new TsSchemaGenerator().generate(model, outDir);
147
245
  }
246
+ };
247
+ var typescript_default = plugin2;
248
+
249
+ // src/actions/generate.ts
250
+ async function run2(options) {
251
+ const start = Date.now();
252
+ const schemaFile = getSchemaFile(options.schema);
253
+ const model = await loadSchemaDocument(schemaFile);
254
+ const outputPath = getOutputPath(options, schemaFile);
255
+ await runPlugins(schemaFile, model, outputPath, options);
148
256
  if (!options.silent) {
149
- console.log(colors2.green("Generation completed successfully."));
257
+ console.log(colors2.green(`Generation completed successfully in ${Date.now() - start}ms.
258
+ `));
150
259
  console.log(`You can now create a ZenStack client with it.
151
260
 
152
261
  \`\`\`ts
@@ -154,37 +263,112 @@ import { ZenStackClient } from '@zenstackhq/runtime';
154
263
  import { schema } from '${outputPath}/schema';
155
264
 
156
265
  const client = new ZenStackClient(schema, {
157
- dialectConfig: { ... }
266
+ dialect: { ... }
158
267
  });
159
268
  \`\`\`
160
- `);
269
+
270
+ Check documentation: https://zenstack.dev/docs/3.x`);
161
271
  }
162
272
  }
163
273
  __name(run2, "run");
164
- async function runPlugins(model, outputPath, tsSchemaFile) {
274
+ function getOutputPath(options, schemaFile) {
275
+ if (options.output) {
276
+ return options.output;
277
+ }
278
+ const pkgJsonConfig = getPkgJsonConfig(process.cwd());
279
+ if (pkgJsonConfig.output) {
280
+ return pkgJsonConfig.output;
281
+ } else {
282
+ return path4.dirname(schemaFile);
283
+ }
284
+ }
285
+ __name(getOutputPath, "getOutputPath");
286
+ async function runPlugins(schemaFile, model, outputPath, options) {
165
287
  const plugins = model.declarations.filter(isPlugin);
166
- for (const plugin of plugins) {
167
- const providerField = plugin.fields.find((f) => f.name === "provider");
168
- invariant(providerField, `Plugin ${plugin.name} does not have a provider field`);
169
- const provider = providerField.value.value;
170
- let useProvider = provider;
171
- if (useProvider.startsWith("@core/")) {
172
- useProvider = `@zenstackhq/runtime/plugins/${useProvider.slice(6)}`;
288
+ const processedPlugins = [];
289
+ for (const plugin3 of plugins) {
290
+ const provider = getPluginProvider(plugin3);
291
+ let cliPlugin;
292
+ if (provider.startsWith("@core/")) {
293
+ cliPlugin = plugins_exports[provider.slice("@core/".length)];
294
+ if (!cliPlugin) {
295
+ throw new CliError(`Unknown core plugin: ${provider}`);
296
+ }
297
+ } else {
298
+ let moduleSpec = provider;
299
+ if (moduleSpec.startsWith(".")) {
300
+ moduleSpec = path4.resolve(path4.dirname(schemaFile), moduleSpec);
301
+ }
302
+ try {
303
+ cliPlugin = (await import(moduleSpec)).default;
304
+ } catch (error) {
305
+ throw new CliError(`Failed to load plugin ${provider}: ${error}`);
306
+ }
173
307
  }
174
- const generator = (await import(useProvider)).default;
175
- console.log("Running generator:", provider);
176
- await generator({
177
- model,
178
- outputPath,
179
- tsSchemaFile
308
+ processedPlugins.push({
309
+ cliPlugin,
310
+ pluginOptions: getPluginOptions(plugin3)
180
311
  });
181
312
  }
313
+ const defaultPlugins = [
314
+ typescript_default
315
+ ].reverse();
316
+ defaultPlugins.forEach((d) => {
317
+ if (!processedPlugins.some((p) => p.cliPlugin === d)) {
318
+ processedPlugins.push({
319
+ cliPlugin: d,
320
+ pluginOptions: {}
321
+ });
322
+ }
323
+ });
324
+ for (const { cliPlugin, pluginOptions } of processedPlugins) {
325
+ invariant(typeof cliPlugin.generate === "function", `Plugin ${cliPlugin.name} does not have a generate function`);
326
+ let spinner;
327
+ if (!options.silent) {
328
+ spinner = ora(cliPlugin.statusText ?? `Running plugin ${cliPlugin.name}`).start();
329
+ }
330
+ try {
331
+ await cliPlugin.generate({
332
+ schemaFile,
333
+ model,
334
+ defaultOutputPath: outputPath,
335
+ pluginOptions
336
+ });
337
+ spinner?.succeed();
338
+ } catch (err) {
339
+ spinner?.fail();
340
+ console.error(err);
341
+ }
342
+ }
182
343
  }
183
344
  __name(runPlugins, "runPlugins");
345
+ function getPluginProvider(plugin3) {
346
+ const providerField = plugin3.fields.find((f) => f.name === "provider");
347
+ invariant(providerField, `Plugin ${plugin3.name} does not have a provider field`);
348
+ const provider = providerField.value.value;
349
+ return provider;
350
+ }
351
+ __name(getPluginProvider, "getPluginProvider");
352
+ function getPluginOptions(plugin3) {
353
+ const result = {};
354
+ for (const field of plugin3.fields) {
355
+ if (field.name === "provider") {
356
+ continue;
357
+ }
358
+ const value = getLiteral(field.value) ?? getLiteralArray(field.value);
359
+ if (value === void 0) {
360
+ console.warn(`Plugin "${plugin3.name}" option "${field.name}" has unsupported value, skipping`);
361
+ continue;
362
+ }
363
+ result[field.name] = value;
364
+ }
365
+ return result;
366
+ }
367
+ __name(getPluginOptions, "getPluginOptions");
184
368
 
185
369
  // src/actions/info.ts
186
370
  import colors3 from "colors";
187
- import path3 from "path";
371
+ import path5 from "path";
188
372
  async function run3(projectPath) {
189
373
  const packages = await getZenStackPackages(projectPath);
190
374
  if (!packages) {
@@ -193,11 +377,11 @@ async function run3(projectPath) {
193
377
  }
194
378
  console.log("Installed ZenStack Packages:");
195
379
  const versions = /* @__PURE__ */ new Set();
196
- for (const { pkg, version } of packages) {
197
- if (version) {
198
- versions.add(version);
380
+ for (const { pkg, version: version2 } of packages) {
381
+ if (version2) {
382
+ versions.add(version2);
199
383
  }
200
- console.log(` ${colors3.green(pkg.padEnd(20))} ${version}`);
384
+ console.log(` ${colors3.green(pkg.padEnd(20))} ${version2}`);
201
385
  }
202
386
  if (versions.size > 1) {
203
387
  console.warn(colors3.yellow("WARNING: Multiple versions of Zenstack packages detected. This may cause issues."));
@@ -206,9 +390,9 @@ async function run3(projectPath) {
206
390
  __name(run3, "run");
207
391
  async function getZenStackPackages(projectPath) {
208
392
  let pkgJson;
209
- const resolvedPath = path3.resolve(projectPath);
393
+ const resolvedPath = path5.resolve(projectPath);
210
394
  try {
211
- pkgJson = (await import(path3.join(resolvedPath, "package.json"), {
395
+ pkgJson = (await import(path5.join(resolvedPath, "package.json"), {
212
396
  with: {
213
397
  type: "json"
214
398
  }
@@ -227,6 +411,9 @@ async function getZenStackPackages(projectPath) {
227
411
  type: "json"
228
412
  }
229
413
  })).default;
414
+ if (depPkgJson.private) {
415
+ return void 0;
416
+ }
230
417
  return {
231
418
  pkg,
232
419
  version: depPkgJson.version
@@ -238,15 +425,15 @@ async function getZenStackPackages(projectPath) {
238
425
  };
239
426
  }
240
427
  }));
241
- return result;
428
+ return result.filter((p) => !!p);
242
429
  }
243
430
  __name(getZenStackPackages, "getZenStackPackages");
244
431
 
245
432
  // src/actions/init.ts
246
433
  import colors4 from "colors";
247
- import fs4 from "fs";
248
- import path4 from "path";
249
- import ora from "ora";
434
+ import fs5 from "fs";
435
+ import path6 from "path";
436
+ import ora2 from "ora";
250
437
  import { detect, resolveCommand } from "package-manager-detector";
251
438
 
252
439
  // src/actions/templates.ts
@@ -308,7 +495,7 @@ async function run4(projectPath) {
308
495
  if (!resolved) {
309
496
  throw new CliError(`Unable to determine how to install package "${pkg.name}". Please install it manually.`);
310
497
  }
311
- const spinner = ora(`Installing "${pkg.name}"`).start();
498
+ const spinner = ora2(`Installing "${pkg.name}"`).start();
312
499
  try {
313
500
  execSync(`${resolved.command} ${resolved.args.join(" ")}`, {
314
501
  cwd: projectPath
@@ -320,11 +507,11 @@ async function run4(projectPath) {
320
507
  }
321
508
  }
322
509
  const generationFolder = "zenstack";
323
- if (!fs4.existsSync(path4.join(projectPath, generationFolder))) {
324
- fs4.mkdirSync(path4.join(projectPath, generationFolder));
510
+ if (!fs5.existsSync(path6.join(projectPath, generationFolder))) {
511
+ fs5.mkdirSync(path6.join(projectPath, generationFolder));
325
512
  }
326
- if (!fs4.existsSync(path4.join(projectPath, generationFolder, "schema.zmodel"))) {
327
- fs4.writeFileSync(path4.join(projectPath, generationFolder, "schema.zmodel"), STARTER_ZMODEL);
513
+ if (!fs5.existsSync(path6.join(projectPath, generationFolder, "schema.zmodel"))) {
514
+ fs5.writeFileSync(path6.join(projectPath, generationFolder, "schema.zmodel"), STARTER_ZMODEL);
328
515
  } else {
329
516
  console.log(colors4.yellow("Schema file already exists. Skipping generation of sample."));
330
517
  }
@@ -335,10 +522,12 @@ async function run4(projectPath) {
335
522
  __name(run4, "run");
336
523
 
337
524
  // src/actions/migrate.ts
338
- import fs5 from "fs";
525
+ import fs6 from "fs";
526
+ import path7 from "path";
339
527
  async function run5(command, options) {
340
528
  const schemaFile = getSchemaFile(options.schema);
341
- const prismaSchemaFile = await generateTempPrismaSchema(schemaFile);
529
+ const prismaSchemaDir = options.migrations ? path7.dirname(options.migrations) : void 0;
530
+ const prismaSchemaFile = await generateTempPrismaSchema(schemaFile, prismaSchemaDir);
342
531
  try {
343
532
  switch (command) {
344
533
  case "dev":
@@ -353,19 +542,27 @@ async function run5(command, options) {
353
542
  case "status":
354
543
  await runStatus(prismaSchemaFile, options);
355
544
  break;
545
+ case "resolve":
546
+ await runResolve(prismaSchemaFile, options);
547
+ break;
356
548
  }
357
549
  } finally {
358
- if (fs5.existsSync(prismaSchemaFile)) {
359
- fs5.unlinkSync(prismaSchemaFile);
550
+ if (fs6.existsSync(prismaSchemaFile)) {
551
+ fs6.unlinkSync(prismaSchemaFile);
360
552
  }
361
553
  }
362
554
  }
363
555
  __name(run5, "run");
364
556
  async function runDev(prismaSchemaFile, options) {
365
557
  try {
366
- await execPackage(`prisma migrate dev --schema "${prismaSchemaFile}" --skip-generate${options.name ? ` --name ${options.name}` : ""}${options.createOnly ? " --create-only" : ""}`, {
367
- stdio: "inherit"
368
- });
558
+ const cmd = [
559
+ "prisma migrate dev",
560
+ ` --schema "${prismaSchemaFile}"`,
561
+ " --skip-generate",
562
+ options.name ? ` --name ${options.name}` : "",
563
+ options.createOnly ? " --create-only" : ""
564
+ ].join("");
565
+ await execPackage(cmd);
369
566
  } catch (err) {
370
567
  handleSubProcessError2(err);
371
568
  }
@@ -373,9 +570,12 @@ async function runDev(prismaSchemaFile, options) {
373
570
  __name(runDev, "runDev");
374
571
  async function runReset(prismaSchemaFile, options) {
375
572
  try {
376
- await execPackage(`prisma migrate reset --schema "${prismaSchemaFile}"${options.force ? " --force" : ""}`, {
377
- stdio: "inherit"
378
- });
573
+ const cmd = [
574
+ "prisma migrate reset",
575
+ ` --schema "${prismaSchemaFile}"`,
576
+ options.force ? " --force" : ""
577
+ ].join("");
578
+ await execPackage(cmd);
379
579
  } catch (err) {
380
580
  handleSubProcessError2(err);
381
581
  }
@@ -383,9 +583,11 @@ async function runReset(prismaSchemaFile, options) {
383
583
  __name(runReset, "runReset");
384
584
  async function runDeploy(prismaSchemaFile, _options) {
385
585
  try {
386
- await execPackage(`prisma migrate deploy --schema "${prismaSchemaFile}"`, {
387
- stdio: "inherit"
388
- });
586
+ const cmd = [
587
+ "prisma migrate deploy",
588
+ ` --schema "${prismaSchemaFile}"`
589
+ ].join("");
590
+ await execPackage(cmd);
389
591
  } catch (err) {
390
592
  handleSubProcessError2(err);
391
593
  }
@@ -393,14 +595,29 @@ async function runDeploy(prismaSchemaFile, _options) {
393
595
  __name(runDeploy, "runDeploy");
394
596
  async function runStatus(prismaSchemaFile, _options) {
395
597
  try {
396
- await execPackage(`prisma migrate status --schema "${prismaSchemaFile}"`, {
397
- stdio: "inherit"
398
- });
598
+ await execPackage(`prisma migrate status --schema "${prismaSchemaFile}"`);
399
599
  } catch (err) {
400
600
  handleSubProcessError2(err);
401
601
  }
402
602
  }
403
603
  __name(runStatus, "runStatus");
604
+ async function runResolve(prismaSchemaFile, options) {
605
+ if (!options.applied && !options.rolledBack) {
606
+ throw new CliError("Either --applied or --rolled-back option must be provided");
607
+ }
608
+ try {
609
+ const cmd = [
610
+ "prisma migrate resolve",
611
+ ` --schema "${prismaSchemaFile}"`,
612
+ options.applied ? ` --applied ${options.applied}` : "",
613
+ options.rolledBack ? ` --rolled-back ${options.rolledBack}` : ""
614
+ ].join("");
615
+ await execPackage(cmd);
616
+ } catch (err) {
617
+ handleSubProcessError2(err);
618
+ }
619
+ }
620
+ __name(runResolve, "runResolve");
404
621
  function handleSubProcessError2(err) {
405
622
  if (err instanceof Error && "status" in err && typeof err.status === "number") {
406
623
  process.exit(err.status);
@@ -410,60 +627,383 @@ function handleSubProcessError2(err) {
410
627
  }
411
628
  __name(handleSubProcessError2, "handleSubProcessError");
412
629
 
630
+ // src/actions/check.ts
631
+ import colors5 from "colors";
632
+ async function run6(options) {
633
+ const schemaFile = getSchemaFile(options.schema);
634
+ try {
635
+ await loadSchemaDocument(schemaFile);
636
+ console.log(colors5.green("\u2713 Schema validation completed successfully."));
637
+ } catch (error) {
638
+ console.error(colors5.red("\u2717 Schema validation failed."));
639
+ throw error;
640
+ }
641
+ }
642
+ __name(run6, "run");
643
+
644
+ // src/telemetry.ts
645
+ import { init } from "mixpanel";
646
+ import { randomUUID as randomUUID2 } from "crypto";
647
+ import fs11 from "fs";
648
+ import * as os2 from "os";
649
+
650
+ // src/constants.ts
651
+ var TELEMETRY_TRACKING_TOKEN = "<TELEMETRY_TRACKING_TOKEN>";
652
+
653
+ // src/utils/is-ci.ts
654
+ import { env } from "process";
655
+ var isInCi = env["CI"] !== "0" && env["CI"] !== "false" && ("CI" in env || "CONTINUOUS_INTEGRATION" in env || Object.keys(env).some((key) => key.startsWith("CI_")));
656
+
657
+ // src/utils/is-container.ts
658
+ import fs8 from "fs";
659
+
660
+ // src/utils/is-docker.ts
661
+ import fs7 from "fs";
662
+ var isDockerCached;
663
+ function hasDockerEnv() {
664
+ try {
665
+ fs7.statSync("/.dockerenv");
666
+ return true;
667
+ } catch {
668
+ return false;
669
+ }
670
+ }
671
+ __name(hasDockerEnv, "hasDockerEnv");
672
+ function hasDockerCGroup() {
673
+ try {
674
+ return fs7.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
675
+ } catch {
676
+ return false;
677
+ }
678
+ }
679
+ __name(hasDockerCGroup, "hasDockerCGroup");
680
+ function isDocker() {
681
+ if (isDockerCached === void 0) {
682
+ isDockerCached = hasDockerEnv() || hasDockerCGroup();
683
+ }
684
+ return isDockerCached;
685
+ }
686
+ __name(isDocker, "isDocker");
687
+
688
+ // src/utils/is-container.ts
689
+ var cachedResult;
690
+ var hasContainerEnv = /* @__PURE__ */ __name(() => {
691
+ try {
692
+ fs8.statSync("/run/.containerenv");
693
+ return true;
694
+ } catch {
695
+ return false;
696
+ }
697
+ }, "hasContainerEnv");
698
+ function isInContainer() {
699
+ if (cachedResult === void 0) {
700
+ cachedResult = hasContainerEnv() || isDocker();
701
+ }
702
+ return cachedResult;
703
+ }
704
+ __name(isInContainer, "isInContainer");
705
+
706
+ // src/utils/is-wsl.ts
707
+ import process2 from "process";
708
+ import os from "os";
709
+ import fs9 from "fs";
710
+ var isWsl = /* @__PURE__ */ __name(() => {
711
+ if (process2.platform !== "linux") {
712
+ return false;
713
+ }
714
+ if (os.release().toLowerCase().includes("microsoft")) {
715
+ return true;
716
+ }
717
+ try {
718
+ return fs9.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft");
719
+ } catch {
720
+ return false;
721
+ }
722
+ }, "isWsl");
723
+
724
+ // src/utils/machine-id-utils.ts
725
+ import { execSync as execSync2 } from "child_process";
726
+ import { createHash, randomUUID } from "crypto";
727
+ var { platform } = process;
728
+ var win32RegBinPath = {
729
+ native: "%windir%\\System32",
730
+ mixed: "%windir%\\sysnative\\cmd.exe /c %windir%\\System32"
731
+ };
732
+ var guid = {
733
+ darwin: "ioreg -rd1 -c IOPlatformExpertDevice",
734
+ win32: `${win32RegBinPath[isWindowsProcessMixedOrNativeArchitecture()]}\\REG.exe QUERY HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography /v MachineGuid`,
735
+ linux: "( cat /var/lib/dbus/machine-id /etc/machine-id 2> /dev/null || hostname 2> /dev/null) | head -n 1 || :",
736
+ freebsd: "kenv -q smbios.system.uuid || sysctl -n kern.hostuuid"
737
+ };
738
+ function isWindowsProcessMixedOrNativeArchitecture() {
739
+ if (process.arch === "ia32" && process.env.hasOwnProperty("PROCESSOR_ARCHITEW6432")) {
740
+ return "mixed";
741
+ }
742
+ return "native";
743
+ }
744
+ __name(isWindowsProcessMixedOrNativeArchitecture, "isWindowsProcessMixedOrNativeArchitecture");
745
+ function hash(guid2) {
746
+ return createHash("sha256").update(guid2).digest("hex");
747
+ }
748
+ __name(hash, "hash");
749
+ function expose(result) {
750
+ switch (platform) {
751
+ case "darwin":
752
+ return result.split("IOPlatformUUID")[1]?.split("\n")[0]?.replace(/=|\s+|"/gi, "").toLowerCase();
753
+ case "win32":
754
+ return result.toString().split("REG_SZ")[1]?.replace(/\r+|\n+|\s+/gi, "").toLowerCase();
755
+ case "linux":
756
+ return result.toString().replace(/\r+|\n+|\s+/gi, "").toLowerCase();
757
+ case "freebsd":
758
+ return result.toString().replace(/\r+|\n+|\s+/gi, "").toLowerCase();
759
+ default:
760
+ throw new Error(`Unsupported platform: ${process.platform}`);
761
+ }
762
+ }
763
+ __name(expose, "expose");
764
+ function getMachineId() {
765
+ if (!(platform in guid)) {
766
+ return randomUUID();
767
+ }
768
+ try {
769
+ const value = execSync2(guid[platform]);
770
+ const id = expose(value.toString());
771
+ if (!id) {
772
+ return randomUUID();
773
+ }
774
+ return hash(id);
775
+ } catch {
776
+ return randomUUID();
777
+ }
778
+ }
779
+ __name(getMachineId, "getMachineId");
780
+
413
781
  // src/utils/version-utils.ts
414
- import fs6 from "fs";
415
- import path5 from "path";
782
+ import colors6 from "colors";
783
+ import fs10 from "fs";
784
+ import path8 from "path";
416
785
  import { fileURLToPath } from "url";
786
+ import semver from "semver";
787
+ var CHECK_VERSION_TIMEOUT = 2e3;
788
+ var VERSION_CHECK_TAG = "next";
417
789
  function getVersion() {
418
790
  try {
419
- const _dirname = typeof __dirname !== "undefined" ? __dirname : path5.dirname(fileURLToPath(import.meta.url));
420
- return JSON.parse(fs6.readFileSync(path5.join(_dirname, "../package.json"), "utf8")).version;
791
+ const _dirname = typeof __dirname !== "undefined" ? __dirname : path8.dirname(fileURLToPath(import.meta.url));
792
+ return JSON.parse(fs10.readFileSync(path8.join(_dirname, "../package.json"), "utf8")).version;
421
793
  } catch {
422
794
  return void 0;
423
795
  }
424
796
  }
425
797
  __name(getVersion, "getVersion");
798
+ async function checkNewVersion() {
799
+ const currVersion = getVersion();
800
+ let latestVersion;
801
+ try {
802
+ latestVersion = await getLatestVersion();
803
+ } catch {
804
+ return;
805
+ }
806
+ if (latestVersion && currVersion && semver.gt(latestVersion, currVersion)) {
807
+ console.log(`A newer version ${colors6.cyan(latestVersion)} is available.`);
808
+ }
809
+ }
810
+ __name(checkNewVersion, "checkNewVersion");
811
+ async function getLatestVersion() {
812
+ const fetchResult = await fetch(`https://registry.npmjs.org/@zenstackhq/cli/${VERSION_CHECK_TAG}`, {
813
+ headers: {
814
+ accept: "application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*"
815
+ },
816
+ signal: AbortSignal.timeout(CHECK_VERSION_TIMEOUT)
817
+ });
818
+ if (fetchResult.ok) {
819
+ const data = await fetchResult.json();
820
+ const latestVersion = data?.version;
821
+ if (typeof latestVersion === "string" && semver.valid(latestVersion)) {
822
+ return latestVersion;
823
+ }
824
+ }
825
+ throw new Error("invalid npm registry response");
826
+ }
827
+ __name(getLatestVersion, "getLatestVersion");
828
+
829
+ // src/telemetry.ts
830
+ var Telemetry = class {
831
+ static {
832
+ __name(this, "Telemetry");
833
+ }
834
+ mixpanel;
835
+ hostId = getMachineId();
836
+ sessionid = randomUUID2();
837
+ _os_type = os2.type();
838
+ _os_release = os2.release();
839
+ _os_arch = os2.arch();
840
+ _os_version = os2.version();
841
+ _os_platform = os2.platform();
842
+ version = getVersion();
843
+ prismaVersion = this.getPrismaVersion();
844
+ isDocker = isDocker();
845
+ isWsl = isWsl();
846
+ isContainer = isInContainer();
847
+ isCi = isInCi;
848
+ constructor() {
849
+ if (process.env["DO_NOT_TRACK"] !== "1" && TELEMETRY_TRACKING_TOKEN) {
850
+ this.mixpanel = init(TELEMETRY_TRACKING_TOKEN, {
851
+ geolocate: true
852
+ });
853
+ }
854
+ }
855
+ get isTracking() {
856
+ return !!this.mixpanel;
857
+ }
858
+ track(event, properties = {}) {
859
+ if (this.mixpanel) {
860
+ const payload = {
861
+ distinct_id: this.hostId,
862
+ session: this.sessionid,
863
+ time: /* @__PURE__ */ new Date(),
864
+ $os: this._os_type,
865
+ osType: this._os_type,
866
+ osRelease: this._os_release,
867
+ osPlatform: this._os_platform,
868
+ osArch: this._os_arch,
869
+ osVersion: this._os_version,
870
+ nodeVersion: process.version,
871
+ version: this.version,
872
+ prismaVersion: this.prismaVersion,
873
+ isDocker: this.isDocker,
874
+ isWsl: this.isWsl,
875
+ isContainer: this.isContainer,
876
+ isCi: this.isCi,
877
+ ...properties
878
+ };
879
+ this.mixpanel.track(event, payload);
880
+ }
881
+ }
882
+ trackError(err) {
883
+ this.track("cli:error", {
884
+ message: err.message,
885
+ stack: err.stack
886
+ });
887
+ }
888
+ async trackSpan(startEvent, completeEvent, errorEvent, properties, action) {
889
+ this.track(startEvent, properties);
890
+ const start = Date.now();
891
+ let success = true;
892
+ try {
893
+ return await action();
894
+ } catch (err) {
895
+ this.track(errorEvent, {
896
+ message: err.message,
897
+ stack: err.stack,
898
+ ...properties
899
+ });
900
+ success = false;
901
+ throw err;
902
+ } finally {
903
+ this.track(completeEvent, {
904
+ duration: Date.now() - start,
905
+ success,
906
+ ...properties
907
+ });
908
+ }
909
+ }
910
+ async trackCommand(command, action) {
911
+ await this.trackSpan("cli:command:start", "cli:command:complete", "cli:command:error", {
912
+ command
913
+ }, action);
914
+ }
915
+ async trackCli(action) {
916
+ await this.trackSpan("cli:start", "cli:complete", "cli:error", {}, action);
917
+ }
918
+ getPrismaVersion() {
919
+ try {
920
+ const packageJsonPath = import.meta.resolve("prisma/package.json");
921
+ const packageJsonUrl = new URL(packageJsonPath);
922
+ const packageJson = JSON.parse(fs11.readFileSync(packageJsonUrl, "utf8"));
923
+ return packageJson.version;
924
+ } catch {
925
+ return void 0;
926
+ }
927
+ }
928
+ };
929
+ var telemetry = new Telemetry();
426
930
 
427
931
  // src/index.ts
428
932
  var generateAction = /* @__PURE__ */ __name(async (options) => {
429
- await run2(options);
933
+ await telemetry.trackCommand("generate", () => run2(options));
430
934
  }, "generateAction");
431
- var migrateAction = /* @__PURE__ */ __name(async (command, options) => {
432
- await run5(command, options);
935
+ var migrateAction = /* @__PURE__ */ __name(async (subCommand, options) => {
936
+ await telemetry.trackCommand(`migrate ${subCommand}`, () => run5(subCommand, options));
433
937
  }, "migrateAction");
434
- var dbAction = /* @__PURE__ */ __name(async (command, options) => {
435
- await run(command, options);
938
+ var dbAction = /* @__PURE__ */ __name(async (subCommand, options) => {
939
+ await telemetry.trackCommand(`db ${subCommand}`, () => run(subCommand, options));
436
940
  }, "dbAction");
437
941
  var infoAction = /* @__PURE__ */ __name(async (projectPath) => {
438
- await run3(projectPath);
942
+ await telemetry.trackCommand("info", () => run3(projectPath));
439
943
  }, "infoAction");
440
944
  var initAction = /* @__PURE__ */ __name(async (projectPath) => {
441
- await run4(projectPath);
945
+ await telemetry.trackCommand("init", () => run4(projectPath));
442
946
  }, "initAction");
947
+ var checkAction = /* @__PURE__ */ __name(async (options) => {
948
+ await telemetry.trackCommand("check", () => run6(options));
949
+ }, "checkAction");
443
950
  function createProgram() {
444
- const program2 = new Command("zenstack");
445
- program2.version(getVersion(), "-v --version", "display CLI version");
951
+ const program = new Command("zen");
952
+ program.version(getVersion(), "-v --version", "display CLI version");
446
953
  const schemaExtensions = ZModelLanguageMetaData.fileExtensions.join(", ");
447
- program2.description(`${colors5.bold.blue("\u03B6")} ZenStack is a Prisma power pack for building full-stack apps.
448
-
449
- Documentation: https://zenstack.dev.`).showHelpAfterError().showSuggestionAfterError();
450
- const schemaOption = new Option("--schema <file>", `schema file (with extension ${schemaExtensions}). Defaults to "schema.zmodel" unless specified in package.json.`);
451
- program2.command("generate").description("Run code generation.").addOption(schemaOption).addOption(new Option("--silent", "do not print any output")).addOption(new Option("--save-prisma-schema [path]", "save a Prisma schema file, by default into the output directory")).addOption(new Option("-o, --output <path>", "default output directory for core plugins")).action(generateAction);
452
- const migrateCommand = program2.command("migrate").description("Update the database schema with migrations.");
453
- migrateCommand.command("dev").addOption(schemaOption).addOption(new Option("-n, --name <name>", "migration name")).addOption(new Option("--create-only", "only create migration, do not apply")).description("Create a migration from changes in schema and apply it to the database.").action((options) => migrateAction("dev", options));
454
- migrateCommand.command("reset").addOption(schemaOption).addOption(new Option("--force", "skip the confirmation prompt")).description("Reset your database and apply all migrations, all data will be lost.").action((options) => migrateAction("reset", options));
455
- migrateCommand.command("deploy").addOption(schemaOption).description("Deploy your pending migrations to your production/staging database.").action((options) => migrateAction("deploy", options));
456
- migrateCommand.command("status").addOption(schemaOption).description("check the status of your database migrations.").action((options) => migrateAction("status", options));
457
- const dbCommand = program2.command("db").description("Manage your database schema during development.");
458
- dbCommand.command("push").description("Push the state from your schema to your database").addOption(schemaOption).addOption(new Option("--accept-data-loss", "ignore data loss warnings")).addOption(new Option("--force-reset", "force a reset of the database before push")).action((options) => dbAction("push", options));
459
- program2.command("info").description("Get information of installed ZenStack and related packages.").argument("[path]", "project path", ".").action(infoAction);
460
- program2.command("init").description("Initialize an existing project for ZenStack.").argument("[path]", "project path", ".").action(initAction);
461
- return program2;
954
+ program.description(`${colors7.bold.blue("\u03B6")} ZenStack is the data layer for modern TypeScript apps.
955
+
956
+ Documentation: https://zenstack.dev/docs/3.x`).showHelpAfterError().showSuggestionAfterError();
957
+ const schemaOption = new Option("--schema <file>", `schema file (with extension ${schemaExtensions}). Defaults to "zenstack/schema.zmodel" unless specified in package.json.`);
958
+ const noVersionCheckOption = new Option("--no-version-check", "do not check for new version");
959
+ program.command("generate").description("Run code generation plugins.").addOption(schemaOption).addOption(noVersionCheckOption).addOption(new Option("-o, --output <path>", "default output directory for code generation")).addOption(new Option("--silent", "suppress all output except errors").default(false)).action(generateAction);
960
+ const migrateCommand = program.command("migrate").description("Run database schema migration related tasks.");
961
+ const migrationsOption = new Option("--migrations <path>", 'path that contains the "migrations" directory');
962
+ migrateCommand.command("dev").addOption(schemaOption).addOption(noVersionCheckOption).addOption(new Option("-n, --name <name>", "migration name")).addOption(new Option("--create-only", "only create migration, do not apply")).addOption(migrationsOption).description("Create a migration from changes in schema and apply it to the database.").action((options) => migrateAction("dev", options));
963
+ migrateCommand.command("reset").addOption(schemaOption).addOption(new Option("--force", "skip the confirmation prompt")).addOption(migrationsOption).addOption(noVersionCheckOption).description("Reset your database and apply all migrations, all data will be lost.").action((options) => migrateAction("reset", options));
964
+ migrateCommand.command("deploy").addOption(schemaOption).addOption(noVersionCheckOption).addOption(migrationsOption).description("Deploy your pending migrations to your production/staging database.").action((options) => migrateAction("deploy", options));
965
+ migrateCommand.command("status").addOption(schemaOption).addOption(noVersionCheckOption).addOption(migrationsOption).description("Check the status of your database migrations.").action((options) => migrateAction("status", options));
966
+ migrateCommand.command("resolve").addOption(schemaOption).addOption(noVersionCheckOption).addOption(migrationsOption).addOption(new Option("--applied <migration>", "record a specific migration as applied")).addOption(new Option("--rolled-back <migration>", "record a specific migration as rolled back")).description("Resolve issues with database migrations in deployment databases.").action((options) => migrateAction("resolve", options));
967
+ const dbCommand = program.command("db").description("Manage your database schema during development.");
968
+ dbCommand.command("push").description("Push the state from your schema to your database.").addOption(schemaOption).addOption(noVersionCheckOption).addOption(new Option("--accept-data-loss", "ignore data loss warnings")).addOption(new Option("--force-reset", "force a reset of the database before push")).action((options) => dbAction("push", options));
969
+ program.command("info").description("Get information of installed ZenStack packages.").argument("[path]", "project path", ".").addOption(noVersionCheckOption).action(infoAction);
970
+ program.command("init").description("Initialize an existing project for ZenStack.").argument("[path]", "project path", ".").addOption(noVersionCheckOption).action(initAction);
971
+ program.command("check").description("Check a ZModel schema for syntax or semantic errors.").addOption(schemaOption).addOption(noVersionCheckOption).action(checkAction);
972
+ program.hook("preAction", async (_thisCommand, actionCommand) => {
973
+ if (actionCommand.getOptionValue("versionCheck") !== false) {
974
+ await checkNewVersion();
975
+ }
976
+ });
977
+ return program;
462
978
  }
463
979
  __name(createProgram, "createProgram");
464
- var program = createProgram();
465
- program.parse(process.argv);
466
- export {
467
- createProgram
468
- };
980
+ async function main() {
981
+ let exitCode = 0;
982
+ const program = createProgram();
983
+ program.exitOverride();
984
+ try {
985
+ await telemetry.trackCli(async () => {
986
+ await program.parseAsync();
987
+ });
988
+ } catch (e) {
989
+ if (e instanceof CommanderError) {
990
+ exitCode = e.exitCode;
991
+ } else if (e instanceof CliError) {
992
+ console.error(colors7.red(e.message));
993
+ exitCode = 1;
994
+ } else {
995
+ console.error(colors7.red(`Unhandled error: ${e}`));
996
+ exitCode = 1;
997
+ }
998
+ }
999
+ if (telemetry.isTracking) {
1000
+ setTimeout(() => {
1001
+ process.exit(exitCode);
1002
+ }, 200);
1003
+ } else {
1004
+ process.exit(exitCode);
1005
+ }
1006
+ }
1007
+ __name(main, "main");
1008
+ main();
469
1009
  //# sourceMappingURL=index.js.map