@zenstackhq/cli 3.4.0-beta.3 → 3.4.0

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
@@ -37,6 +37,8 @@ var CliError = class extends Error {
37
37
  };
38
38
 
39
39
  // src/actions/action-utils.ts
40
+ import terminalLink from "terminal-link";
41
+ import { z } from "zod";
40
42
  function getSchemaFile(file) {
41
43
  if (file) {
42
44
  if (!fs.existsSync(file)) {
@@ -212,6 +214,58 @@ async function getZenStackPackages(searchPath) {
212
214
  return result.filter((p) => !!p);
213
215
  }
214
216
  __name(getZenStackPackages, "getZenStackPackages");
217
+ var FETCH_CLI_MAX_TIME = 1e3;
218
+ var CLI_CONFIG_ENDPOINT = "https://zenstack.dev/config/cli-v3.json";
219
+ var usageTipsSchema = z.object({
220
+ notifications: z.array(z.object({
221
+ title: z.string(),
222
+ url: z.url().optional(),
223
+ active: z.boolean()
224
+ }))
225
+ });
226
+ function startUsageTipsFetch() {
227
+ let fetchedData = void 0;
228
+ let fetchComplete = false;
229
+ const start = Date.now();
230
+ const controller = new AbortController();
231
+ fetch(CLI_CONFIG_ENDPOINT, {
232
+ headers: {
233
+ accept: "application/json"
234
+ },
235
+ signal: controller.signal
236
+ }).then(async (res) => {
237
+ if (!res.ok) return;
238
+ const data = await res.json();
239
+ const parseResult = usageTipsSchema.safeParse(data);
240
+ if (parseResult.success) {
241
+ fetchedData = parseResult.data;
242
+ }
243
+ }).catch(() => {
244
+ }).finally(() => {
245
+ fetchComplete = true;
246
+ });
247
+ return async () => {
248
+ const elapsed = Date.now() - start;
249
+ if (!fetchComplete && elapsed < FETCH_CLI_MAX_TIME) {
250
+ await new Promise((resolve) => setTimeout(resolve, FETCH_CLI_MAX_TIME - elapsed));
251
+ }
252
+ if (!fetchComplete) {
253
+ controller.abort();
254
+ return;
255
+ }
256
+ if (!fetchedData) return;
257
+ const activeItems = fetchedData.notifications.filter((item) => item.active);
258
+ if (activeItems.length > 0) {
259
+ const item = activeItems[Math.floor(Math.random() * activeItems.length)];
260
+ if (item.url) {
261
+ console.log(terminalLink(item.title, item.url));
262
+ } else {
263
+ console.log(item.title);
264
+ }
265
+ }
266
+ };
267
+ }
268
+ __name(startUsageTipsFetch, "startUsageTipsFetch");
215
269
 
216
270
  // src/actions/check.ts
217
271
  async function run(options) {
@@ -2183,8 +2237,8 @@ var sqlite = {
2183
2237
  return void 0;
2184
2238
  },
2185
2239
  async introspect(connectionString, _options) {
2186
- const SQLite2 = (await import("better-sqlite3")).default;
2187
- const db = new SQLite2(connectionString, {
2240
+ const SQLite = (await import("better-sqlite3")).default;
2241
+ const db = new SQLite(connectionString, {
2188
2242
  readonly: true
2189
2243
  });
2190
2244
  try {
@@ -2881,13 +2935,14 @@ import { invariant, singleDebounce } from "@zenstackhq/common-helpers";
2881
2935
  import { ZModelLanguageMetaData } from "@zenstackhq/language";
2882
2936
  import { isPlugin } from "@zenstackhq/language/ast";
2883
2937
  import { getLiteral, getLiteralArray as getLiteralArray2 } from "@zenstackhq/language/utils";
2938
+ import { watch } from "chokidar";
2884
2939
  import colors6 from "colors";
2885
2940
  import { createJiti } from "jiti";
2886
2941
  import fs6 from "fs";
2887
2942
  import path5 from "path";
2888
2943
  import { pathToFileURL } from "url";
2889
- import { watch } from "chokidar";
2890
2944
  import ora2 from "ora";
2945
+ import semver from "semver";
2891
2946
 
2892
2947
  // src/plugins/index.ts
2893
2948
  var plugins_exports = {};
@@ -2942,25 +2997,30 @@ var plugin2 = {
2942
2997
  if (importWithFileExtension && typeof importWithFileExtension !== "string") {
2943
2998
  throw new Error('The "importWithFileExtension" option must be a string if specified.');
2944
2999
  }
3000
+ const generateModelTypes = pluginOptions["generateModels"] !== false;
3001
+ const generateInputTypes = pluginOptions["generateInput"] !== false;
2945
3002
  await new TsSchemaGenerator().generate(model, {
2946
3003
  outDir,
2947
3004
  lite,
2948
3005
  liteOnly,
2949
- importWithFileExtension
3006
+ importWithFileExtension,
3007
+ generateModelTypes,
3008
+ generateInputTypes
2950
3009
  });
2951
3010
  }
2952
3011
  };
2953
3012
  var typescript_default = plugin2;
2954
3013
 
2955
3014
  // src/actions/generate.ts
2956
- import semver from "semver";
2957
3015
  async function run4(options) {
2958
3016
  try {
2959
3017
  await checkForMismatchedPackages(process.cwd());
2960
3018
  } catch (err) {
2961
3019
  console.warn(colors6.yellow(`Failed to check for mismatched ZenStack packages: ${err}`));
2962
3020
  }
3021
+ const maybeShowUsageTips = options.tips && !options.silent && !options.watch ? startUsageTipsFetch() : void 0;
2963
3022
  const model = await pureGenerate(options, false);
3023
+ await maybeShowUsageTips?.();
2964
3024
  if (options.watch) {
2965
3025
  const logsEnabled = !options.silent;
2966
3026
  if (logsEnabled) {
@@ -3078,12 +3138,18 @@ async function runPlugins(schemaFile, model, outputPath, options) {
3078
3138
  if (cliPlugin) {
3079
3139
  const pluginOptions = getPluginOptions(plugin3);
3080
3140
  if (provider === "@core/typescript") {
3081
- if (pluginOptions["lite"] === void 0) {
3141
+ if (options.lite !== void 0) {
3082
3142
  pluginOptions["lite"] = options.lite;
3083
3143
  }
3084
- if (pluginOptions["liteOnly"] === void 0) {
3144
+ if (options.liteOnly !== void 0) {
3085
3145
  pluginOptions["liteOnly"] = options.liteOnly;
3086
3146
  }
3147
+ if (options.generateModels !== void 0) {
3148
+ pluginOptions["generateModels"] = options.generateModels;
3149
+ }
3150
+ if (options.generateInput !== void 0) {
3151
+ pluginOptions["generateInput"] = options.generateInput;
3152
+ }
3087
3153
  }
3088
3154
  processedPlugins.push({
3089
3155
  cliPlugin,
@@ -3096,7 +3162,9 @@ async function runPlugins(schemaFile, model, outputPath, options) {
3096
3162
  plugin: typescript_default,
3097
3163
  options: {
3098
3164
  lite: options.lite,
3099
- liteOnly: options.liteOnly
3165
+ liteOnly: options.liteOnly,
3166
+ generateModels: options.generateModels,
3167
+ generateInput: options.generateInput
3100
3168
  }
3101
3169
  }
3102
3170
  ];
@@ -3514,14 +3582,11 @@ import { PostgresDialect } from "@zenstackhq/orm/dialects/postgres";
3514
3582
  import { SqliteDialect } from "@zenstackhq/orm/dialects/sqlite";
3515
3583
  import { RPCApiHandler } from "@zenstackhq/server/api";
3516
3584
  import { ZenStackMiddleware } from "@zenstackhq/server/express";
3517
- import SQLite from "better-sqlite3";
3518
3585
  import colors11 from "colors";
3519
3586
  import cors from "cors";
3520
3587
  import express from "express";
3521
3588
  import { createJiti as createJiti2 } from "jiti";
3522
- import { createPool as createMysqlPool } from "mysql2";
3523
3589
  import path9 from "path";
3524
- import { Pool as PgPool } from "pg";
3525
3590
 
3526
3591
  // src/utils/version-utils.ts
3527
3592
  import colors10 from "colors";
@@ -3530,7 +3595,7 @@ import path8 from "path";
3530
3595
  import { fileURLToPath as fileURLToPath2 } from "url";
3531
3596
  import semver2 from "semver";
3532
3597
  var CHECK_VERSION_TIMEOUT = 2e3;
3533
- var VERSION_CHECK_TAG = "next";
3598
+ var VERSION_CHECK_TAG = "latest";
3534
3599
  function getVersion() {
3535
3600
  try {
3536
3601
  const _dirname = typeof __dirname !== "undefined" ? __dirname : path8.dirname(fileURLToPath2(import.meta.url));
@@ -3595,7 +3660,7 @@ async function run9(options) {
3595
3660
  databaseUrl = evaluateUrl(schemaUrl);
3596
3661
  }
3597
3662
  const provider = getStringLiteral2(dataSource?.fields.find((f) => f.name === "provider")?.value);
3598
- const dialect = createDialect(provider, databaseUrl, outputPath);
3663
+ const dialect = await createDialect(provider, databaseUrl, outputPath);
3599
3664
  const jiti = createJiti2(import.meta.url);
3600
3665
  const schemaModule = await jiti.import(path9.join(outputPath, "schema"));
3601
3666
  const schema = schemaModule.schema;
@@ -3655,9 +3720,15 @@ function redactDatabaseUrl(url) {
3655
3720
  }
3656
3721
  }
3657
3722
  __name(redactDatabaseUrl, "redactDatabaseUrl");
3658
- function createDialect(provider, databaseUrl, outputPath) {
3723
+ async function createDialect(provider, databaseUrl, outputPath) {
3659
3724
  switch (provider) {
3660
3725
  case "sqlite": {
3726
+ let SQLite;
3727
+ try {
3728
+ SQLite = (await import("better-sqlite3")).default;
3729
+ } catch {
3730
+ throw new CliError(`Package "better-sqlite3" is required for SQLite support. Please install it with: npm install better-sqlite3`);
3731
+ }
3661
3732
  let resolvedUrl = databaseUrl.trim();
3662
3733
  if (resolvedUrl.startsWith("file:")) {
3663
3734
  const filePath = resolvedUrl.substring("file:".length);
@@ -3670,18 +3741,32 @@ function createDialect(provider, databaseUrl, outputPath) {
3670
3741
  database: new SQLite(resolvedUrl)
3671
3742
  });
3672
3743
  }
3673
- case "postgresql":
3744
+ case "postgresql": {
3745
+ let PgPool;
3746
+ try {
3747
+ PgPool = (await import("pg")).Pool;
3748
+ } catch {
3749
+ throw new CliError(`Package "pg" is required for PostgreSQL support. Please install it with: npm install pg`);
3750
+ }
3674
3751
  console.log(colors11.gray(`Connecting to PostgreSQL database at: ${redactDatabaseUrl(databaseUrl)}`));
3675
3752
  return new PostgresDialect({
3676
3753
  pool: new PgPool({
3677
3754
  connectionString: databaseUrl
3678
3755
  })
3679
3756
  });
3680
- case "mysql":
3757
+ }
3758
+ case "mysql": {
3759
+ let createMysqlPool;
3760
+ try {
3761
+ createMysqlPool = (await import("mysql2")).createPool;
3762
+ } catch {
3763
+ throw new CliError(`Package "mysql2" is required for MySQL support. Please install it with: npm install mysql2`);
3764
+ }
3681
3765
  console.log(colors11.gray(`Connecting to MySQL database at: ${redactDatabaseUrl(databaseUrl)}`));
3682
3766
  return new MysqlDialect({
3683
3767
  pool: createMysqlPool(databaseUrl)
3684
3768
  });
3769
+ }
3685
3770
  default:
3686
3771
  throw new CliError(`Unsupported database provider: ${provider}`);
3687
3772
  }
@@ -3745,7 +3830,7 @@ import fs13 from "fs";
3745
3830
  import * as os2 from "os";
3746
3831
 
3747
3832
  // src/constants.ts
3748
- var TELEMETRY_TRACKING_TOKEN = "<TELEMETRY_TRACKING_TOKEN>";
3833
+ var TELEMETRY_TRACKING_TOKEN = "74944eb779d7d3b4ce185be843fde9fc";
3749
3834
 
3750
3835
  // src/utils/is-ci.ts
3751
3836
  import { env } from "process";
@@ -4005,6 +4090,17 @@ var seedAction = /* @__PURE__ */ __name(async (options, args) => {
4005
4090
  var proxyAction = /* @__PURE__ */ __name(async (options) => {
4006
4091
  await telemetry.trackCommand("proxy", () => run9(options));
4007
4092
  }, "proxyAction");
4093
+ function triStateBooleanOption(flag, description) {
4094
+ return new Option(flag, description).choices([
4095
+ "true",
4096
+ "false"
4097
+ ]).argParser((value) => {
4098
+ if (value === void 0 || value === "true") return true;
4099
+ if (value === "false") return false;
4100
+ throw new CliError(`Invalid value for ${flag}: ${value}`);
4101
+ });
4102
+ }
4103
+ __name(triStateBooleanOption, "triStateBooleanOption");
4008
4104
  function createProgram() {
4009
4105
  const program = new Command("zen").alias("zenstack").helpOption("-h, --help", "Show this help message").version(getVersion(), "-v --version", "Show CLI version");
4010
4106
  const schemaExtensions = ZModelLanguageMetaData2.fileExtensions.join(", ");
@@ -4013,7 +4109,8 @@ function createProgram() {
4013
4109
  Documentation: https://zenstack.dev/docs`).showHelpAfterError().showSuggestionAfterError();
4014
4110
  const schemaOption = new Option("--schema <file>", `schema file (with extension ${schemaExtensions}). Defaults to "zenstack/schema.zmodel" unless specified in package.json.`);
4015
4111
  const noVersionCheckOption = new Option("--no-version-check", "do not check for new version");
4016
- 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("-w, --watch", "enable watch mode").default(false)).addOption(new Option("--lite", "also generate a lite version of schema without attributes").default(false)).addOption(new Option("--lite-only", "only generate lite version of schema without attributes").default(false)).addOption(new Option("--silent", "suppress all output except errors").default(false)).action(generateAction);
4112
+ const noTipsOption = new Option("--no-tips", "do not show usage tips");
4113
+ program.command("generate").description("Run code generation plugins").addOption(schemaOption).addOption(noVersionCheckOption).addOption(noTipsOption).addOption(new Option("-o, --output <path>", "default output directory for code generation")).addOption(new Option("-w, --watch", "enable watch mode").default(false)).addOption(triStateBooleanOption("--lite [boolean]", "also generate a lite version of schema without attributes, defaults to false")).addOption(triStateBooleanOption("--lite-only [boolean]", "only generate lite version of schema without attributes, defaults to false")).addOption(triStateBooleanOption("--generate-models [boolean]", "generate models.ts file, defaults to true")).addOption(triStateBooleanOption("--generate-input [boolean]", "generate input.ts file, defaults to true")).addOption(new Option("--silent", "suppress all output except errors").default(false)).action(generateAction);
4017
4114
  const migrateCommand = program.command("migrate").description("Run database schema migration related tasks.");
4018
4115
  const migrationsOption = new Option("--migrations <path>", 'path that contains the "migrations" directory');
4019
4116
  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));