@zenstackhq/cli 3.3.0-beta.2 → 3.3.0-beta.4

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.cjs CHANGED
@@ -28,8 +28,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  ));
29
29
 
30
30
  // src/index.ts
31
- var import_language4 = require("@zenstackhq/language");
32
- var import_colors9 = __toESM(require("colors"), 1);
31
+ var import_language5 = require("@zenstackhq/language");
32
+ var import_colors10 = __toESM(require("colors"), 1);
33
33
  var import_commander = require("commander");
34
34
 
35
35
  // src/actions/check.ts
@@ -170,6 +170,18 @@ async function requireDataSourceUrl(schemaFile) {
170
170
  }
171
171
  }
172
172
  __name(requireDataSourceUrl, "requireDataSourceUrl");
173
+ function getOutputPath(options, schemaFile) {
174
+ if (options.output) {
175
+ return options.output;
176
+ }
177
+ const pkgJsonConfig = getPkgJsonConfig(process.cwd());
178
+ if (pkgJsonConfig.output) {
179
+ return pkgJsonConfig.output;
180
+ } else {
181
+ return import_node_path.default.dirname(schemaFile);
182
+ }
183
+ }
184
+ __name(getOutputPath, "getOutputPath");
173
185
 
174
186
  // src/actions/check.ts
175
187
  async function run(options) {
@@ -231,7 +243,7 @@ function execPrisma(args, options) {
231
243
  execPackage(`prisma ${args}`, _options);
232
244
  return;
233
245
  }
234
- execSync(`node ${prismaPath} ${args}`, _options);
246
+ execSync(`node "${prismaPath}" ${args}`, _options);
235
247
  }
236
248
  __name(execPrisma, "execPrisma");
237
249
 
@@ -466,18 +478,6 @@ Check documentation: https://zenstack.dev/docs/`);
466
478
  return model;
467
479
  }
468
480
  __name(pureGenerate, "pureGenerate");
469
- function getOutputPath(options, schemaFile) {
470
- if (options.output) {
471
- return options.output;
472
- }
473
- const pkgJsonConfig = getPkgJsonConfig(process.cwd());
474
- if (pkgJsonConfig.output) {
475
- return pkgJsonConfig.output;
476
- } else {
477
- return import_node_path4.default.dirname(schemaFile);
478
- }
479
- }
480
- __name(getOutputPath, "getOutputPath");
481
481
  async function runPlugins(schemaFile, model, outputPath, options) {
482
482
  const plugins = model.declarations.filter(import_ast2.isPlugin);
483
483
  const processedPlugins = [];
@@ -929,6 +929,211 @@ function handleSubProcessError2(err) {
929
929
  }
930
930
  __name(handleSubProcessError2, "handleSubProcessError");
931
931
 
932
+ // src/actions/proxy.ts
933
+ var import_language4 = require("@zenstackhq/language");
934
+ var import_ast3 = require("@zenstackhq/language/ast");
935
+ var import_utils2 = require("@zenstackhq/language/utils");
936
+ var import_orm = require("@zenstackhq/orm");
937
+ var import_mysql = require("@zenstackhq/orm/dialects/mysql");
938
+ var import_postgres = require("@zenstackhq/orm/dialects/postgres");
939
+ var import_sqlite = require("@zenstackhq/orm/dialects/sqlite");
940
+ var import_api = require("@zenstackhq/server/api");
941
+ var import_express = require("@zenstackhq/server/express");
942
+ var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
943
+ var import_colors9 = __toESM(require("colors"), 1);
944
+ var import_cors = __toESM(require("cors"), 1);
945
+ var import_express2 = __toESM(require("express"), 1);
946
+ var import_jiti2 = require("jiti");
947
+ var import_mysql2 = require("mysql2");
948
+ var import_node_path9 = __toESM(require("path"), 1);
949
+ var import_pg = require("pg");
950
+
951
+ // src/utils/version-utils.ts
952
+ var import_colors8 = __toESM(require("colors"), 1);
953
+ var import_node_fs9 = __toESM(require("fs"), 1);
954
+ var import_node_path8 = __toESM(require("path"), 1);
955
+ var import_node_url2 = require("url");
956
+ var import_semver = __toESM(require("semver"), 1);
957
+ var import_meta2 = {};
958
+ var CHECK_VERSION_TIMEOUT = 2e3;
959
+ var VERSION_CHECK_TAG = "next";
960
+ function getVersion() {
961
+ try {
962
+ const _dirname = typeof __dirname !== "undefined" ? __dirname : import_node_path8.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url));
963
+ return JSON.parse(import_node_fs9.default.readFileSync(import_node_path8.default.join(_dirname, "../package.json"), "utf8")).version;
964
+ } catch {
965
+ return void 0;
966
+ }
967
+ }
968
+ __name(getVersion, "getVersion");
969
+ async function checkNewVersion() {
970
+ const currVersion = getVersion();
971
+ let latestVersion;
972
+ try {
973
+ latestVersion = await getLatestVersion();
974
+ } catch {
975
+ return;
976
+ }
977
+ if (latestVersion && currVersion && import_semver.default.gt(latestVersion, currVersion)) {
978
+ console.log(`A newer version ${import_colors8.default.cyan(latestVersion)} is available.`);
979
+ }
980
+ }
981
+ __name(checkNewVersion, "checkNewVersion");
982
+ async function getLatestVersion() {
983
+ const fetchResult = await fetch(`https://registry.npmjs.org/@zenstackhq/cli/${VERSION_CHECK_TAG}`, {
984
+ headers: {
985
+ accept: "application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*"
986
+ },
987
+ signal: AbortSignal.timeout(CHECK_VERSION_TIMEOUT)
988
+ });
989
+ if (fetchResult.ok) {
990
+ const data = await fetchResult.json();
991
+ const latestVersion = data?.version;
992
+ if (typeof latestVersion === "string" && import_semver.default.valid(latestVersion)) {
993
+ return latestVersion;
994
+ }
995
+ }
996
+ throw new Error("invalid npm registry response");
997
+ }
998
+ __name(getLatestVersion, "getLatestVersion");
999
+
1000
+ // src/actions/proxy.ts
1001
+ var import_meta3 = {};
1002
+ async function run9(options) {
1003
+ const schemaFile = getSchemaFile(options.schema);
1004
+ console.log(import_colors9.default.gray(`Loading ZModel schema from: ${schemaFile}`));
1005
+ let outputPath = getOutputPath(options, schemaFile);
1006
+ if (!import_node_path9.default.isAbsolute(outputPath)) {
1007
+ outputPath = import_node_path9.default.resolve(process.cwd(), outputPath);
1008
+ }
1009
+ const model = await loadSchemaDocument(schemaFile);
1010
+ const dataSource = model.declarations.find(import_ast3.isDataSource);
1011
+ let databaseUrl = options.databaseUrl;
1012
+ if (!databaseUrl) {
1013
+ const schemaUrl = dataSource?.fields.find((f) => f.name === "url")?.value;
1014
+ if (!schemaUrl) {
1015
+ throw new CliError(`The schema's "datasource" does not have a "url" field, please provide it with -d option.`);
1016
+ }
1017
+ const zModelGenerator = new import_language4.ZModelCodeGenerator();
1018
+ const url = zModelGenerator.generate(schemaUrl);
1019
+ databaseUrl = evaluateUrl(url);
1020
+ }
1021
+ const provider = (0, import_utils2.getStringLiteral)(dataSource?.fields.find((f) => f.name === "provider")?.value);
1022
+ const dialect = createDialect(provider, databaseUrl, outputPath);
1023
+ const jiti = (0, import_jiti2.createJiti)(import_meta3.url);
1024
+ const schemaModule = await jiti.import(import_node_path9.default.join(outputPath, "schema"));
1025
+ const allowedLogLevels = [
1026
+ "error",
1027
+ "query"
1028
+ ];
1029
+ const log = options.logLevel?.filter((level) => allowedLogLevels.includes(level));
1030
+ const db = new import_orm.ZenStackClient(schemaModule.schema, {
1031
+ dialect,
1032
+ log: log && log.length > 0 ? log : void 0
1033
+ });
1034
+ try {
1035
+ await db.$connect();
1036
+ } catch (err) {
1037
+ throw new CliError(`Failed to connect to the database: ${err instanceof Error ? err.message : String(err)}`);
1038
+ }
1039
+ startServer(db, schemaModule.schema, options);
1040
+ }
1041
+ __name(run9, "run");
1042
+ function evaluateUrl(value) {
1043
+ const env2 = /* @__PURE__ */ __name((varName) => {
1044
+ const envValue = process.env[varName];
1045
+ if (!envValue) {
1046
+ throw new CliError(`Environment variable ${varName} is not set`);
1047
+ }
1048
+ return envValue;
1049
+ }, "env");
1050
+ try {
1051
+ const urlFn = new Function("env", `return ${value}`);
1052
+ const url = urlFn(env2);
1053
+ return url;
1054
+ } catch (err) {
1055
+ if (err instanceof CliError) {
1056
+ throw err;
1057
+ }
1058
+ throw new CliError("Could not evaluate datasource url from schema, you could provide it via -d option.");
1059
+ }
1060
+ }
1061
+ __name(evaluateUrl, "evaluateUrl");
1062
+ function createDialect(provider, databaseUrl, outputPath) {
1063
+ switch (provider) {
1064
+ case "sqlite": {
1065
+ let resolvedUrl = databaseUrl.trim();
1066
+ if (resolvedUrl.startsWith("file:")) {
1067
+ const filePath = resolvedUrl.substring("file:".length);
1068
+ if (!import_node_path9.default.isAbsolute(filePath)) {
1069
+ resolvedUrl = import_node_path9.default.join(outputPath, filePath);
1070
+ }
1071
+ }
1072
+ console.log(import_colors9.default.gray(`Connecting to SQLite database at: ${resolvedUrl}`));
1073
+ return new import_sqlite.SqliteDialect({
1074
+ database: new import_better_sqlite3.default(resolvedUrl)
1075
+ });
1076
+ }
1077
+ case "postgresql":
1078
+ console.log(import_colors9.default.gray(`Connecting to PostgreSQL database at: ${databaseUrl}`));
1079
+ return new import_postgres.PostgresDialect({
1080
+ pool: new import_pg.Pool({
1081
+ connectionString: databaseUrl
1082
+ })
1083
+ });
1084
+ case "mysql":
1085
+ console.log(import_colors9.default.gray(`Connecting to MySQL database at: ${databaseUrl}`));
1086
+ return new import_mysql.MysqlDialect({
1087
+ pool: (0, import_mysql2.createPool)(databaseUrl)
1088
+ });
1089
+ default:
1090
+ throw new CliError(`Unsupported database provider: ${provider}`);
1091
+ }
1092
+ }
1093
+ __name(createDialect, "createDialect");
1094
+ function startServer(client, schema, options) {
1095
+ const app = (0, import_express2.default)();
1096
+ app.use((0, import_cors.default)());
1097
+ app.use(import_express2.default.json({
1098
+ limit: "5mb"
1099
+ }));
1100
+ app.use(import_express2.default.urlencoded({
1101
+ extended: true,
1102
+ limit: "5mb"
1103
+ }));
1104
+ app.use("/api/model", (0, import_express.ZenStackMiddleware)({
1105
+ apiHandler: new import_api.RPCApiHandler({
1106
+ schema
1107
+ }),
1108
+ getClient: /* @__PURE__ */ __name(() => client, "getClient")
1109
+ }));
1110
+ app.get("/api/schema", (_req, res) => {
1111
+ res.json({
1112
+ ...schema,
1113
+ zenstackVersion: getVersion()
1114
+ });
1115
+ });
1116
+ const server = app.listen(options.port, () => {
1117
+ console.log(`ZenStack proxy server is running on port: ${options.port}`);
1118
+ console.log(`You can visit ZenStack Studio at: ${import_colors9.default.blue("https://studio.zenstack.dev")}`);
1119
+ });
1120
+ process.on("SIGTERM", async () => {
1121
+ server.close(() => {
1122
+ console.log("\nZenStack proxy server closed");
1123
+ });
1124
+ await client.$disconnect();
1125
+ process.exit(0);
1126
+ });
1127
+ process.on("SIGINT", async () => {
1128
+ server.close(() => {
1129
+ console.log("\nZenStack proxy server closed");
1130
+ });
1131
+ await client.$disconnect();
1132
+ process.exit(0);
1133
+ });
1134
+ }
1135
+ __name(startServer, "startServer");
1136
+
932
1137
  // src/telemetry.ts
933
1138
  var import_mixpanel = require("mixpanel");
934
1139
  var import_node_crypto2 = require("crypto");
@@ -943,14 +1148,14 @@ var import_node_process = require("process");
943
1148
  var isInCi = import_node_process.env["CI"] !== "0" && import_node_process.env["CI"] !== "false" && ("CI" in import_node_process.env || "CONTINUOUS_INTEGRATION" in import_node_process.env || Object.keys(import_node_process.env).some((key) => key.startsWith("CI_")));
944
1149
 
945
1150
  // src/utils/is-container.ts
946
- var import_node_fs10 = __toESM(require("fs"), 1);
1151
+ var import_node_fs11 = __toESM(require("fs"), 1);
947
1152
 
948
1153
  // src/utils/is-docker.ts
949
- var import_node_fs9 = __toESM(require("fs"), 1);
1154
+ var import_node_fs10 = __toESM(require("fs"), 1);
950
1155
  var isDockerCached;
951
1156
  function hasDockerEnv() {
952
1157
  try {
953
- import_node_fs9.default.statSync("/.dockerenv");
1158
+ import_node_fs10.default.statSync("/.dockerenv");
954
1159
  return true;
955
1160
  } catch {
956
1161
  return false;
@@ -959,7 +1164,7 @@ function hasDockerEnv() {
959
1164
  __name(hasDockerEnv, "hasDockerEnv");
960
1165
  function hasDockerCGroup() {
961
1166
  try {
962
- return import_node_fs9.default.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
1167
+ return import_node_fs10.default.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
963
1168
  } catch {
964
1169
  return false;
965
1170
  }
@@ -977,7 +1182,7 @@ __name(isDocker, "isDocker");
977
1182
  var cachedResult;
978
1183
  var hasContainerEnv = /* @__PURE__ */ __name(() => {
979
1184
  try {
980
- import_node_fs10.default.statSync("/run/.containerenv");
1185
+ import_node_fs11.default.statSync("/run/.containerenv");
981
1186
  return true;
982
1187
  } catch {
983
1188
  return false;
@@ -994,7 +1199,7 @@ __name(isInContainer, "isInContainer");
994
1199
  // src/utils/is-wsl.ts
995
1200
  var import_node_process2 = __toESM(require("process"), 1);
996
1201
  var import_node_os = __toESM(require("os"), 1);
997
- var import_node_fs11 = __toESM(require("fs"), 1);
1202
+ var import_node_fs12 = __toESM(require("fs"), 1);
998
1203
  var isWsl = /* @__PURE__ */ __name(() => {
999
1204
  if (import_node_process2.default.platform !== "linux") {
1000
1205
  return false;
@@ -1003,7 +1208,7 @@ var isWsl = /* @__PURE__ */ __name(() => {
1003
1208
  return true;
1004
1209
  }
1005
1210
  try {
1006
- return import_node_fs11.default.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft");
1211
+ return import_node_fs12.default.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft");
1007
1212
  } catch {
1008
1213
  return false;
1009
1214
  }
@@ -1066,57 +1271,8 @@ function getMachineId() {
1066
1271
  }
1067
1272
  __name(getMachineId, "getMachineId");
1068
1273
 
1069
- // src/utils/version-utils.ts
1070
- var import_colors8 = __toESM(require("colors"), 1);
1071
- var import_node_fs12 = __toESM(require("fs"), 1);
1072
- var import_node_path8 = __toESM(require("path"), 1);
1073
- var import_node_url2 = require("url");
1074
- var import_semver = __toESM(require("semver"), 1);
1075
- var import_meta2 = {};
1076
- var CHECK_VERSION_TIMEOUT = 2e3;
1077
- var VERSION_CHECK_TAG = "next";
1078
- function getVersion() {
1079
- try {
1080
- const _dirname = typeof __dirname !== "undefined" ? __dirname : import_node_path8.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url));
1081
- return JSON.parse(import_node_fs12.default.readFileSync(import_node_path8.default.join(_dirname, "../package.json"), "utf8")).version;
1082
- } catch {
1083
- return void 0;
1084
- }
1085
- }
1086
- __name(getVersion, "getVersion");
1087
- async function checkNewVersion() {
1088
- const currVersion = getVersion();
1089
- let latestVersion;
1090
- try {
1091
- latestVersion = await getLatestVersion();
1092
- } catch {
1093
- return;
1094
- }
1095
- if (latestVersion && currVersion && import_semver.default.gt(latestVersion, currVersion)) {
1096
- console.log(`A newer version ${import_colors8.default.cyan(latestVersion)} is available.`);
1097
- }
1098
- }
1099
- __name(checkNewVersion, "checkNewVersion");
1100
- async function getLatestVersion() {
1101
- const fetchResult = await fetch(`https://registry.npmjs.org/@zenstackhq/cli/${VERSION_CHECK_TAG}`, {
1102
- headers: {
1103
- accept: "application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*"
1104
- },
1105
- signal: AbortSignal.timeout(CHECK_VERSION_TIMEOUT)
1106
- });
1107
- if (fetchResult.ok) {
1108
- const data = await fetchResult.json();
1109
- const latestVersion = data?.version;
1110
- if (typeof latestVersion === "string" && import_semver.default.valid(latestVersion)) {
1111
- return latestVersion;
1112
- }
1113
- }
1114
- throw new Error("invalid npm registry response");
1115
- }
1116
- __name(getLatestVersion, "getLatestVersion");
1117
-
1118
1274
  // src/telemetry.ts
1119
- var import_meta3 = {};
1275
+ var import_meta4 = {};
1120
1276
  var Telemetry = class {
1121
1277
  static {
1122
1278
  __name(this, "Telemetry");
@@ -1207,7 +1363,7 @@ var Telemetry = class {
1207
1363
  }
1208
1364
  getPrismaVersion() {
1209
1365
  try {
1210
- const packageJsonPath = import_meta3.resolve("prisma/package.json");
1366
+ const packageJsonPath = import_meta4.resolve("prisma/package.json");
1211
1367
  const packageJsonUrl = new URL(packageJsonPath);
1212
1368
  const packageJson = JSON.parse(import_node_fs13.default.readFileSync(packageJsonUrl, "utf8"));
1213
1369
  return packageJson.version;
@@ -1243,10 +1399,13 @@ var formatAction = /* @__PURE__ */ __name(async (options) => {
1243
1399
  var seedAction = /* @__PURE__ */ __name(async (options, args) => {
1244
1400
  await telemetry.trackCommand("db seed", () => run7(options, args));
1245
1401
  }, "seedAction");
1402
+ var proxyAction = /* @__PURE__ */ __name(async (options) => {
1403
+ await telemetry.trackCommand("proxy", () => run9(options));
1404
+ }, "proxyAction");
1246
1405
  function createProgram() {
1247
1406
  const program = new import_commander.Command("zen").alias("zenstack").helpOption("-h, --help", "Show this help message").version(getVersion(), "-v --version", "Show CLI version");
1248
- const schemaExtensions = import_language4.ZModelLanguageMetaData.fileExtensions.join(", ");
1249
- program.description(`${import_colors9.default.bold.blue("\u03B6")} ZenStack is the modern data layer for TypeScript apps.
1407
+ const schemaExtensions = import_language5.ZModelLanguageMetaData.fileExtensions.join(", ");
1408
+ program.description(`${import_colors10.default.bold.blue("\u03B6")} ZenStack is the modern data layer for TypeScript apps.
1250
1409
 
1251
1410
  Documentation: https://zenstack.dev/docs`).showHelpAfterError().showSuggestionAfterError();
1252
1411
  const schemaOption = new import_commander.Option("--schema <file>", `schema file (with extension ${schemaExtensions}). Defaults to "zenstack/schema.zmodel" unless specified in package.json.`);
@@ -1275,6 +1434,7 @@ Arguments following -- are passed to the seed script. E.g.: "zen db seed -- --us
1275
1434
  program.command("init").description("Initialize an existing project for ZenStack").argument("[path]", "project path", ".").addOption(noVersionCheckOption).action(initAction);
1276
1435
  program.command("check").description("Check a ZModel schema for syntax or semantic errors").addOption(schemaOption).addOption(noVersionCheckOption).action(checkAction);
1277
1436
  program.command("format").description("Format a ZModel schema file").addOption(schemaOption).addOption(noVersionCheckOption).action(formatAction);
1437
+ program.command("proxy").alias("studio").description("Start the ZenStack proxy server").addOption(schemaOption).addOption(new import_commander.Option("-p, --port <port>", "port to run the proxy server on").default(8008)).addOption(new import_commander.Option("-o, --output <path>", "output directory for `zen generate` command")).addOption(new import_commander.Option("-d, --databaseUrl <url>", "database connection URL")).addOption(new import_commander.Option("-l, --logLevel <level>", "Query log levels (e.g., query, error)")).addOption(noVersionCheckOption).action(proxyAction);
1278
1438
  program.addHelpCommand("help [command]", "Display help for a command");
1279
1439
  program.hook("preAction", async (_thisCommand, actionCommand) => {
1280
1440
  if (actionCommand.getOptionValue("versionCheck") !== false) {
@@ -1296,14 +1456,17 @@ async function main() {
1296
1456
  if (e instanceof import_commander.CommanderError) {
1297
1457
  exitCode = e.exitCode;
1298
1458
  } else if (e instanceof CliError) {
1299
- console.error(import_colors9.default.red(e.message));
1459
+ console.error(import_colors10.default.red(e.message));
1300
1460
  exitCode = 1;
1301
1461
  } else {
1302
- console.error(import_colors9.default.red(`Unhandled error: ${e}`));
1462
+ console.error(import_colors10.default.red(`Unhandled error: ${e}`));
1303
1463
  exitCode = 1;
1304
1464
  }
1305
1465
  }
1306
- if (program.args.includes("generate") && (program.args.includes("-w") || program.args.includes("--watch"))) {
1466
+ if (program.args.includes("generate") && (program.args.includes("-w") || program.args.includes("--watch")) || [
1467
+ "proxy",
1468
+ "studio"
1469
+ ].some((cmd) => program.args.includes(cmd))) {
1307
1470
  return;
1308
1471
  }
1309
1472
  if (telemetry.isTracking) {