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

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) {
@@ -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,204 @@ function handleSubProcessError2(err) {
929
929
  }
930
930
  __name(handleSubProcessError2, "handleSubProcessError");
931
931
 
932
+ // src/actions/proxy.ts
933
+ var import_ast3 = require("@zenstackhq/language/ast");
934
+ var import_language4 = require("@zenstackhq/language");
935
+ var import_utils2 = require("@zenstackhq/language/utils");
936
+ var import_sqlite = require("@zenstackhq/orm/dialects/sqlite");
937
+ var import_postgres = require("@zenstackhq/orm/dialects/postgres");
938
+ var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
939
+ var import_pg = require("pg");
940
+ var import_node_path9 = __toESM(require("path"), 1);
941
+ var import_orm = require("@zenstackhq/orm");
942
+ var import_api = require("@zenstackhq/server/api");
943
+ var import_express = require("@zenstackhq/server/express");
944
+ var import_express2 = __toESM(require("express"), 1);
945
+ var import_colors9 = __toESM(require("colors"), 1);
946
+ var import_jiti2 = require("jiti");
947
+
948
+ // src/utils/version-utils.ts
949
+ var import_colors8 = __toESM(require("colors"), 1);
950
+ var import_node_fs9 = __toESM(require("fs"), 1);
951
+ var import_node_path8 = __toESM(require("path"), 1);
952
+ var import_node_url2 = require("url");
953
+ var import_semver = __toESM(require("semver"), 1);
954
+ var import_meta2 = {};
955
+ var CHECK_VERSION_TIMEOUT = 2e3;
956
+ var VERSION_CHECK_TAG = "next";
957
+ function getVersion() {
958
+ try {
959
+ const _dirname = typeof __dirname !== "undefined" ? __dirname : import_node_path8.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url));
960
+ return JSON.parse(import_node_fs9.default.readFileSync(import_node_path8.default.join(_dirname, "../package.json"), "utf8")).version;
961
+ } catch {
962
+ return void 0;
963
+ }
964
+ }
965
+ __name(getVersion, "getVersion");
966
+ async function checkNewVersion() {
967
+ const currVersion = getVersion();
968
+ let latestVersion;
969
+ try {
970
+ latestVersion = await getLatestVersion();
971
+ } catch {
972
+ return;
973
+ }
974
+ if (latestVersion && currVersion && import_semver.default.gt(latestVersion, currVersion)) {
975
+ console.log(`A newer version ${import_colors8.default.cyan(latestVersion)} is available.`);
976
+ }
977
+ }
978
+ __name(checkNewVersion, "checkNewVersion");
979
+ async function getLatestVersion() {
980
+ const fetchResult = await fetch(`https://registry.npmjs.org/@zenstackhq/cli/${VERSION_CHECK_TAG}`, {
981
+ headers: {
982
+ accept: "application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*"
983
+ },
984
+ signal: AbortSignal.timeout(CHECK_VERSION_TIMEOUT)
985
+ });
986
+ if (fetchResult.ok) {
987
+ const data = await fetchResult.json();
988
+ const latestVersion = data?.version;
989
+ if (typeof latestVersion === "string" && import_semver.default.valid(latestVersion)) {
990
+ return latestVersion;
991
+ }
992
+ }
993
+ throw new Error("invalid npm registry response");
994
+ }
995
+ __name(getLatestVersion, "getLatestVersion");
996
+
997
+ // src/actions/proxy.ts
998
+ var import_cors = __toESM(require("cors"), 1);
999
+ var import_meta3 = {};
1000
+ async function run9(options) {
1001
+ const schemaFile = getSchemaFile(options.schema);
1002
+ console.log(import_colors9.default.gray(`Loading ZModel schema from: ${schemaFile}`));
1003
+ let outputPath = getOutputPath(options, schemaFile);
1004
+ if (!import_node_path9.default.isAbsolute(outputPath)) {
1005
+ outputPath = import_node_path9.default.resolve(process.cwd(), outputPath);
1006
+ }
1007
+ const model = await loadSchemaDocument(schemaFile);
1008
+ const dataSource = model.declarations.find(import_ast3.isDataSource);
1009
+ let databaseUrl = options.databaseUrl;
1010
+ if (!databaseUrl) {
1011
+ const schemaUrl = dataSource?.fields.find((f) => f.name === "url")?.value;
1012
+ if (!schemaUrl) {
1013
+ throw new CliError(`The schema's "datasource" does not have a "url" field, please provide it with -d option.`);
1014
+ }
1015
+ const zModelGenerator = new import_language4.ZModelCodeGenerator();
1016
+ const url = zModelGenerator.generate(schemaUrl);
1017
+ databaseUrl = evaluateUrl(url);
1018
+ }
1019
+ const provider = (0, import_utils2.getStringLiteral)(dataSource?.fields.find((f) => f.name === "provider")?.value);
1020
+ const dialect = createDialect(provider, databaseUrl, outputPath);
1021
+ const jiti = (0, import_jiti2.createJiti)(import_meta3.url);
1022
+ const schemaModule = await jiti.import(import_node_path9.default.join(outputPath, "schema"));
1023
+ const allowedLogLevels = [
1024
+ "error",
1025
+ "query"
1026
+ ];
1027
+ const log = options.logLevel?.filter((level) => allowedLogLevels.includes(level));
1028
+ const db = new import_orm.ZenStackClient(schemaModule.schema, {
1029
+ dialect,
1030
+ log: log && log.length > 0 ? log : void 0
1031
+ });
1032
+ try {
1033
+ await db.$connect();
1034
+ } catch (err) {
1035
+ throw new CliError(`Failed to connect to the database: ${err instanceof Error ? err.message : String(err)}`);
1036
+ }
1037
+ startServer(db, schemaModule.schema, options);
1038
+ }
1039
+ __name(run9, "run");
1040
+ function evaluateUrl(value) {
1041
+ const env2 = /* @__PURE__ */ __name((varName) => {
1042
+ const envValue = process.env[varName];
1043
+ if (!envValue) {
1044
+ throw new CliError(`Environment variable ${varName} is not set`);
1045
+ }
1046
+ return envValue;
1047
+ }, "env");
1048
+ try {
1049
+ const urlFn = new Function("env", `return ${value}`);
1050
+ const url = urlFn(env2);
1051
+ return url;
1052
+ } catch (err) {
1053
+ if (err instanceof CliError) {
1054
+ throw err;
1055
+ }
1056
+ throw new CliError("Could not evaluate datasource url from schema, you could provide it via -d option.");
1057
+ }
1058
+ }
1059
+ __name(evaluateUrl, "evaluateUrl");
1060
+ function createDialect(provider, databaseUrl, outputPath) {
1061
+ switch (provider) {
1062
+ case "sqlite": {
1063
+ let resolvedUrl = databaseUrl.trim();
1064
+ if (resolvedUrl.startsWith("file:")) {
1065
+ const filePath = resolvedUrl.substring("file:".length);
1066
+ if (!import_node_path9.default.isAbsolute(filePath)) {
1067
+ resolvedUrl = import_node_path9.default.join(outputPath, filePath);
1068
+ }
1069
+ }
1070
+ console.log(import_colors9.default.gray(`Connecting to SQLite database at: ${resolvedUrl}`));
1071
+ return new import_sqlite.SqliteDialect({
1072
+ database: new import_better_sqlite3.default(resolvedUrl)
1073
+ });
1074
+ }
1075
+ case "postgresql":
1076
+ console.log(import_colors9.default.gray(`Connecting to PostgreSQL database at: ${databaseUrl}`));
1077
+ return new import_postgres.PostgresDialect({
1078
+ pool: new import_pg.Pool({
1079
+ connectionString: databaseUrl
1080
+ })
1081
+ });
1082
+ default:
1083
+ throw new CliError(`Unsupported database provider: ${provider}`);
1084
+ }
1085
+ }
1086
+ __name(createDialect, "createDialect");
1087
+ function startServer(client, schema, options) {
1088
+ const app = (0, import_express2.default)();
1089
+ app.use((0, import_cors.default)());
1090
+ app.use(import_express2.default.json({
1091
+ limit: "5mb"
1092
+ }));
1093
+ app.use(import_express2.default.urlencoded({
1094
+ extended: true,
1095
+ limit: "5mb"
1096
+ }));
1097
+ app.use("/api/model", (0, import_express.ZenStackMiddleware)({
1098
+ apiHandler: new import_api.RPCApiHandler({
1099
+ schema
1100
+ }),
1101
+ getClient: /* @__PURE__ */ __name(() => client, "getClient")
1102
+ }));
1103
+ app.get("/api/schema", (_req, res) => {
1104
+ res.json({
1105
+ ...schema,
1106
+ zenstackVersion: getVersion()
1107
+ });
1108
+ });
1109
+ const server = app.listen(options.port, () => {
1110
+ console.log(`ZenStack proxy server is running on port: ${options.port}`);
1111
+ console.log(`You can visit ZenStack Studio at: ${import_colors9.default.blue("https://studio.zenstack.dev")}`);
1112
+ });
1113
+ process.on("SIGTERM", async () => {
1114
+ server.close(() => {
1115
+ console.log("\nZenStack proxy server closed");
1116
+ });
1117
+ await client.$disconnect();
1118
+ process.exit(0);
1119
+ });
1120
+ process.on("SIGINT", async () => {
1121
+ server.close(() => {
1122
+ console.log("\nZenStack proxy server closed");
1123
+ });
1124
+ await client.$disconnect();
1125
+ process.exit(0);
1126
+ });
1127
+ }
1128
+ __name(startServer, "startServer");
1129
+
932
1130
  // src/telemetry.ts
933
1131
  var import_mixpanel = require("mixpanel");
934
1132
  var import_node_crypto2 = require("crypto");
@@ -943,14 +1141,14 @@ var import_node_process = require("process");
943
1141
  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
1142
 
945
1143
  // src/utils/is-container.ts
946
- var import_node_fs10 = __toESM(require("fs"), 1);
1144
+ var import_node_fs11 = __toESM(require("fs"), 1);
947
1145
 
948
1146
  // src/utils/is-docker.ts
949
- var import_node_fs9 = __toESM(require("fs"), 1);
1147
+ var import_node_fs10 = __toESM(require("fs"), 1);
950
1148
  var isDockerCached;
951
1149
  function hasDockerEnv() {
952
1150
  try {
953
- import_node_fs9.default.statSync("/.dockerenv");
1151
+ import_node_fs10.default.statSync("/.dockerenv");
954
1152
  return true;
955
1153
  } catch {
956
1154
  return false;
@@ -959,7 +1157,7 @@ function hasDockerEnv() {
959
1157
  __name(hasDockerEnv, "hasDockerEnv");
960
1158
  function hasDockerCGroup() {
961
1159
  try {
962
- return import_node_fs9.default.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
1160
+ return import_node_fs10.default.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
963
1161
  } catch {
964
1162
  return false;
965
1163
  }
@@ -977,7 +1175,7 @@ __name(isDocker, "isDocker");
977
1175
  var cachedResult;
978
1176
  var hasContainerEnv = /* @__PURE__ */ __name(() => {
979
1177
  try {
980
- import_node_fs10.default.statSync("/run/.containerenv");
1178
+ import_node_fs11.default.statSync("/run/.containerenv");
981
1179
  return true;
982
1180
  } catch {
983
1181
  return false;
@@ -994,7 +1192,7 @@ __name(isInContainer, "isInContainer");
994
1192
  // src/utils/is-wsl.ts
995
1193
  var import_node_process2 = __toESM(require("process"), 1);
996
1194
  var import_node_os = __toESM(require("os"), 1);
997
- var import_node_fs11 = __toESM(require("fs"), 1);
1195
+ var import_node_fs12 = __toESM(require("fs"), 1);
998
1196
  var isWsl = /* @__PURE__ */ __name(() => {
999
1197
  if (import_node_process2.default.platform !== "linux") {
1000
1198
  return false;
@@ -1003,7 +1201,7 @@ var isWsl = /* @__PURE__ */ __name(() => {
1003
1201
  return true;
1004
1202
  }
1005
1203
  try {
1006
- return import_node_fs11.default.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft");
1204
+ return import_node_fs12.default.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft");
1007
1205
  } catch {
1008
1206
  return false;
1009
1207
  }
@@ -1066,57 +1264,8 @@ function getMachineId() {
1066
1264
  }
1067
1265
  __name(getMachineId, "getMachineId");
1068
1266
 
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
1267
  // src/telemetry.ts
1119
- var import_meta3 = {};
1268
+ var import_meta4 = {};
1120
1269
  var Telemetry = class {
1121
1270
  static {
1122
1271
  __name(this, "Telemetry");
@@ -1207,7 +1356,7 @@ var Telemetry = class {
1207
1356
  }
1208
1357
  getPrismaVersion() {
1209
1358
  try {
1210
- const packageJsonPath = import_meta3.resolve("prisma/package.json");
1359
+ const packageJsonPath = import_meta4.resolve("prisma/package.json");
1211
1360
  const packageJsonUrl = new URL(packageJsonPath);
1212
1361
  const packageJson = JSON.parse(import_node_fs13.default.readFileSync(packageJsonUrl, "utf8"));
1213
1362
  return packageJson.version;
@@ -1243,10 +1392,13 @@ var formatAction = /* @__PURE__ */ __name(async (options) => {
1243
1392
  var seedAction = /* @__PURE__ */ __name(async (options, args) => {
1244
1393
  await telemetry.trackCommand("db seed", () => run7(options, args));
1245
1394
  }, "seedAction");
1395
+ var proxyAction = /* @__PURE__ */ __name(async (options) => {
1396
+ await telemetry.trackCommand("proxy", () => run9(options));
1397
+ }, "proxyAction");
1246
1398
  function createProgram() {
1247
1399
  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.
1400
+ const schemaExtensions = import_language5.ZModelLanguageMetaData.fileExtensions.join(", ");
1401
+ program.description(`${import_colors10.default.bold.blue("\u03B6")} ZenStack is the modern data layer for TypeScript apps.
1250
1402
 
1251
1403
  Documentation: https://zenstack.dev/docs`).showHelpAfterError().showSuggestionAfterError();
1252
1404
  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 +1427,7 @@ Arguments following -- are passed to the seed script. E.g.: "zen db seed -- --us
1275
1427
  program.command("init").description("Initialize an existing project for ZenStack").argument("[path]", "project path", ".").addOption(noVersionCheckOption).action(initAction);
1276
1428
  program.command("check").description("Check a ZModel schema for syntax or semantic errors").addOption(schemaOption).addOption(noVersionCheckOption).action(checkAction);
1277
1429
  program.command("format").description("Format a ZModel schema file").addOption(schemaOption).addOption(noVersionCheckOption).action(formatAction);
1430
+ 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
1431
  program.addHelpCommand("help [command]", "Display help for a command");
1279
1432
  program.hook("preAction", async (_thisCommand, actionCommand) => {
1280
1433
  if (actionCommand.getOptionValue("versionCheck") !== false) {
@@ -1296,14 +1449,17 @@ async function main() {
1296
1449
  if (e instanceof import_commander.CommanderError) {
1297
1450
  exitCode = e.exitCode;
1298
1451
  } else if (e instanceof CliError) {
1299
- console.error(import_colors9.default.red(e.message));
1452
+ console.error(import_colors10.default.red(e.message));
1300
1453
  exitCode = 1;
1301
1454
  } else {
1302
- console.error(import_colors9.default.red(`Unhandled error: ${e}`));
1455
+ console.error(import_colors10.default.red(`Unhandled error: ${e}`));
1303
1456
  exitCode = 1;
1304
1457
  }
1305
1458
  }
1306
- if (program.args.includes("generate") && (program.args.includes("-w") || program.args.includes("--watch"))) {
1459
+ if (program.args.includes("generate") && (program.args.includes("-w") || program.args.includes("--watch")) || [
1460
+ "proxy",
1461
+ "studio"
1462
+ ].some((cmd) => program.args.includes(cmd))) {
1307
1463
  return;
1308
1464
  }
1309
1465
  if (telemetry.isTracking) {