@saltcorn/cli 0.7.1-beta.3 → 0.7.2-beta.10

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.
@@ -0,0 +1,163 @@
1
+ /**
2
+ * @category saltcorn-cli
3
+ * @module commands/modify-user
4
+ */
5
+
6
+ // todo support for users without emails (using user.id)
7
+ const { Command, flags } = require("@oclif/command");
8
+ const { cli } = require("cli-ux");
9
+ const { maybe_as_tenant, init_some_tenants } = require("../common");
10
+
11
+
12
+ /**
13
+ * ModifyUserCommand Class
14
+ * @extends oclif.Command
15
+ * @category saltcorn-cli
16
+ */
17
+ class ModifyUserCommand extends Command {
18
+ /**
19
+ * @returns {Promise<void>}
20
+ */
21
+ async run() {
22
+
23
+ const User = require("@saltcorn/data/models/user");
24
+
25
+ const { args } = this.parse(ModifyUserCommand);
26
+ const { flags } = this.parse(ModifyUserCommand);
27
+
28
+ if (flags.admin && flags.role && flags.role !== "admin") {
29
+ console.error("Error: specify at most one of admin and role");
30
+ this.exit(1);
31
+ }
32
+
33
+ // init tenant
34
+ await init_some_tenants(flags.tenant);
35
+
36
+ // run function as specified tenant
37
+ await maybe_as_tenant(flags.tenant, async () => {
38
+ // role_id
39
+ let role_id; // = flags.admin ? 1 : 8;
40
+ if (flags.admin) role_id = 1;
41
+ else if (flags.role) {
42
+ const roles = await User.get_roles();
43
+ const role = roles.find((r) => r.role === flags.role);
44
+ if (!role) {
45
+ console.error(`Error: role ${flags.role} not found`);
46
+ this.exit(1);
47
+ }
48
+ role_id = role.id;
49
+ }
50
+ // email
51
+ let email;
52
+ if (flags.email) email = flags.email;
53
+ else if (flags.imode) email = await cli.prompt("New Email address", { default : args.user_email });
54
+ if(email === args.user_email) email = undefined; // little trick - we won't update email if it already same
55
+ if (email)
56
+ if (!User.valid_email(email)){
57
+ console.error(`Error: Email is invalid`);
58
+ this.exit(1);
59
+ }
60
+
61
+ // password
62
+ // todo check for repeated passwords
63
+ let password;
64
+ if (flags.password) password = flags.password;
65
+ else if (flags.imode) password = await cli.prompt("New Password", { type: "hide" });
66
+ if (password)
67
+ if (User.unacceptable_password_reason(password)){
68
+ console.error(`Error: ${User.unacceptable_password_reason(password)}`);
69
+ this.exit(1);
70
+ }
71
+ // check that user with new email does not exists
72
+ const u_new_email = await User.findOne({ email });
73
+ if(u_new_email !== null&&args.user_email!==email){
74
+ console.error(`Error: Cannot change email from ${args.user_email} to ${email}. User with email ${email} exists`);
75
+ this.exit(1);
76
+ }
77
+ // try to find user
78
+ const u = await User.findOne({ email: args.user_email });
79
+ if(u === null){
80
+ console.error(`Error: User ${args.user_email} is not found`);
81
+ this.exit(1);
82
+ }
83
+ if(!u instanceof User){
84
+ console.error(`Error: ${u.error}`);
85
+ this.exit(1);
86
+ }
87
+
88
+ // make changes
89
+ if (email && role_id)
90
+ await u.update({ email, role_id });
91
+ else if(email)
92
+ await u.update({ email });
93
+ else if(role_id)
94
+ await u.update({ role_id });
95
+
96
+ if (password)
97
+ await u.changePasswordTo(password, false);
98
+
99
+ console.log(`Success: User ${email?email:args.user_email} updated successfully ${
100
+ typeof flags.tenant !== "undefined" ? "in tenant " + flags.tenant : ""
101
+ }`);
102
+
103
+ });
104
+ this.exit(0);
105
+ }
106
+ }
107
+
108
+ /**
109
+ * @type {object}
110
+ */
111
+ ModifyUserCommand.args = [
112
+ { name: "user_email", required: true, description: "User to modify" },
113
+ ];
114
+
115
+ /**
116
+ * @type {string}
117
+ */
118
+ ModifyUserCommand.description = `Modify (update) user.
119
+
120
+ Command changes the user specified by USER_EMAIL.
121
+
122
+ You can change the user group, password and email.
123
+
124
+ NOTE that -a and -r role (--role=role) can give conflict.
125
+ `;
126
+
127
+ /**
128
+ * @type {string}
129
+ */
130
+ ModifyUserCommand.help = `Modify (update) user.
131
+
132
+ Command changes the user specified by USER_EMAIL.
133
+
134
+ You can change the user group, password and email.
135
+
136
+ NOTE that -a and -r role (--role=role) can give conflict.
137
+ `;
138
+
139
+ /**
140
+ * @type {object}
141
+ */
142
+ ModifyUserCommand.flags = {
143
+ admin: flags.boolean({ char: "a", description: "make user be Admin" }),
144
+ tenant: flags.string({
145
+ char: "t",
146
+ description: "tenant",
147
+ }),
148
+ email: flags.string({
149
+ char: "e",
150
+ description: "new email",
151
+ }),
152
+ role: flags.string({
153
+ char: "r",
154
+ description: "new role (can conflict with -a option)",
155
+ }),
156
+ password: flags.string({
157
+ char: "p",
158
+ description: "new password",
159
+ }),
160
+ imode: flags.boolean({ char: "i", description: "interactive mode" }),
161
+ };
162
+
163
+ module.exports = ModifyUserCommand;
@@ -24,6 +24,7 @@ class ReleaseCommand extends Command {
24
24
  "@saltcorn/e2e": { dir: "e2e" },
25
25
  "@saltcorn/db-common": { dir: "db-common", publish: true },
26
26
  "@saltcorn/sqlite": { dir: "sqlite", publish: true },
27
+ "@saltcorn/sqlite-mobile": { dir: "sqlite-mobile", publish: true },
27
28
  "@saltcorn/postgres": { dir: "postgres", publish: true },
28
29
  "@saltcorn/types": { dir: "saltcorn-types", publish: true },
29
30
  "@saltcorn/builder": { dir: "saltcorn-builder", publish: true },
@@ -37,28 +38,38 @@ class ReleaseCommand extends Command {
37
38
  "@saltcorn/base-plugin": { dir: "saltcorn-base-plugin", publish: true },
38
39
  //"saltcorn-cli", publish: true},
39
40
  "@saltcorn/markup": { dir: "saltcorn-markup", publish: true },
41
+ "@saltcorn/mobile-app": { dir: "saltcorn-mobile-app", publish: true },
42
+ "@saltcorn/mobile-builder": {
43
+ dir: "saltcorn-mobile-builder",
44
+ publish: true,
45
+ },
40
46
  "@saltcorn/sbadmin2": { dir: "saltcorn-sbadmin2", publish: true },
41
47
  };
42
48
 
49
+ const updateDependencies = (json, dpkgnm, version) => {
50
+ if (json.dependencies && json.dependencies[dpkgnm])
51
+ json.dependencies[dpkgnm] = version;
52
+ if (json.devDependencies && json.devDependencies[dpkgnm])
53
+ json.devDependencies[dpkgnm] = version;
54
+ if (json.optionalDependencies && json.optionalDependencies[dpkgnm])
55
+ json.optionalDependencies[dpkgnm] = version;
56
+ };
57
+
43
58
  const updatePkgJson = (dir) => {
44
59
  const json = require(`../../../${dir}/package.json`);
45
60
  json.version = version;
46
61
  if (json.dependencies || json.devDependencies)
47
62
  Object.keys(pkgs).forEach((dpkgnm) => {
48
- if (json.dependencies && json.dependencies[dpkgnm])
49
- json.dependencies[dpkgnm] = version;
50
- if (json.devDependencies && json.devDependencies[dpkgnm])
51
- json.devDependencies[dpkgnm] = version;
52
- if (json.optionalDependencies && json.optionalDependencies[dpkgnm])
53
- json.optionalDependencies[dpkgnm] = version;
63
+ updateDependencies(json, dpkgnm, version);
54
64
  });
65
+ updateDependencies(json, "@saltcorn/cli", version);
55
66
  fs.writeFileSync(
56
67
  `packages/${dir}/package.json`,
57
68
  JSON.stringify(json, null, 2)
58
69
  );
59
70
  };
60
71
  const compileTsFiles = () => {
61
- spawnSync("npm", ["install"], {
72
+ spawnSync("npm", ["install", "--legacy-peer-deps"], {
62
73
  stdio: "inherit",
63
74
  cwd: ".",
64
75
  });
@@ -78,7 +89,7 @@ class ReleaseCommand extends Command {
78
89
  // 1. update version
79
90
  // 2. update dependencies for other packages
80
91
  // 3. publish
81
- spawnSync("npm", ["install"], {
92
+ spawnSync("npm", ["install", "--legacy-peer-deps"], {
82
93
  stdio: "inherit",
83
94
  cwd: `packages/saltcorn-cli/`,
84
95
  });
@@ -93,7 +104,7 @@ class ReleaseCommand extends Command {
93
104
  // 3. run npm update
94
105
  // 3. publish
95
106
  updatePkgJson("saltcorn-cli");
96
- spawnSync("npm", ["update"], {
107
+ spawnSync("npm", ["update","--legacy-peer-deps"], {
97
108
  stdio: "inherit",
98
109
  cwd: `packages/saltcorn-cli/`,
99
110
  });
@@ -17,7 +17,7 @@ class ResetCommand extends Command {
17
17
  */
18
18
  async run() {
19
19
  const reset = require("@saltcorn/data/db/reset_schema");
20
- const db = require("@saltcorn/data/db/");
20
+ const db = require("@saltcorn/data/db");
21
21
  const { flags } = this.parse(ResetCommand);
22
22
  await maybe_as_tenant(flags.tenant, async () => {
23
23
  const schema = db.getTenantSchema();
@@ -32,6 +32,7 @@ class ResetCommand extends Command {
32
32
  if (ans) await reset(false, schema);
33
33
  }
34
34
  });
35
+ console.log(`Success: Command execution successfully`);
35
36
  this.exit(0);
36
37
  }
37
38
  }
@@ -44,11 +45,19 @@ ResetCommand.description = `Reset the database
44
45
  This will delete all existing information
45
46
  `;
46
47
 
48
+ /**
49
+ * @type {string}
50
+ */
51
+ ResetCommand.help = `Reset the database
52
+ ...
53
+ This will delete all existing information
54
+ `;
55
+
47
56
  /**
48
57
  * @type {object}
49
58
  */
50
59
  ResetCommand.flags = {
51
- force: flags.boolean({ char: "f", description: "force" }),
60
+ force: flags.boolean({ char: "f", description: "force command execution" }),
52
61
  tenant: flags.string({
53
62
  char: "t",
54
63
  description: "tenant",
@@ -91,6 +91,11 @@ RestoreCommand.args = [
91
91
  */
92
92
  RestoreCommand.description = `Restore a previously backed up database (zip or sqlc format)`;
93
93
 
94
+ /**
95
+ * @type {string}
96
+ */
97
+ RestoreCommand.help = `Restore a previously backed up database (zip or sqlc format)`;
98
+
94
99
  /**
95
100
  * @type {object}
96
101
  */
@@ -3,6 +3,7 @@
3
3
  * @module commands/rm-tenant
4
4
  */
5
5
  const { Command, flags } = require("@oclif/command");
6
+ const {cli} = require("cli-ux");
6
7
 
7
8
  /**
8
9
  * RmTenantCommand Class
@@ -14,9 +15,23 @@ class RmTenantCommand extends Command {
14
15
  * @returns {Promise<void>}
15
16
  */
16
17
  async run() {
17
- const { args } = this.parse(RmTenantCommand);
18
+
19
+
20
+ const { flags } = this.parse(RmTenantCommand);
21
+
18
22
  const { deleteTenant } = require("@saltcorn/admin-models/models/tenant");
19
- await deleteTenant(args.tenant);
23
+
24
+ if (!flags.force) {
25
+ const ans = await cli.confirm(
26
+ `This will delete tenant ${flags.tenant}. Attention! All tenant data will be lost!\nContinue (y/n)?`);
27
+ if (!ans) {
28
+ console.log(`Success: Command execution canceled`);
29
+ this.exit(1);
30
+ }
31
+ }
32
+ // make changes
33
+ await deleteTenant(flags.tenant);
34
+
20
35
  this.exit(0);
21
36
  }
22
37
  }
@@ -24,18 +39,36 @@ class RmTenantCommand extends Command {
24
39
  /**
25
40
  * @type {object}
26
41
  */
27
- RmTenantCommand.args = [
42
+ RmTenantCommand.args = []; /*[
28
43
  { name: "tenant", required: true, description: "Tenant to remove" },
29
44
  ];
30
-
45
+ */
31
46
  /**
32
47
  * @type {string}
33
48
  */
34
- RmTenantCommand.description = `Remove a tenant`;
49
+ RmTenantCommand.description = `Remove a tenant.
50
+ Attention! All tenant data will be lost!
51
+ It recommended to make backup of tenant before perform this command.
52
+ `;
53
+
54
+ /**
55
+ * @type {object}
56
+ */
57
+ RmTenantCommand.help = `Remove a tenant.
58
+ Attention! All tenant data will be lost!
59
+ It recommended to make backup of tenant before perform this command.
60
+ `;
35
61
 
36
62
  /**
37
63
  * @type {object}
38
64
  */
39
- RmTenantCommand.flags = {};
65
+ RmTenantCommand.flags = {
66
+ force: flags.boolean({ char: "f", description: "force command execution" }),
67
+ tenant: flags.string({
68
+ char: "t",
69
+ description: "tenant",
70
+ required: true,
71
+ }),
72
+ };
40
73
 
41
74
  module.exports = RmTenantCommand;
@@ -32,26 +32,34 @@ class RunTestsCommand extends Command {
32
32
  return res;
33
33
  }
34
34
 
35
- /**
36
- *
37
- * @param {*} env
38
- * @returns {Promise<void>}
39
- */
40
- async e2etest(env) {
35
+ async prepareTestServer(env, port) {
36
+ let serverEnv = JSON.parse(JSON.stringify(env));
37
+ serverEnv.SQLITE_FILEPATH = "/tmp/sctestdb_server";
41
38
  spawnSync("packages/saltcorn-cli/bin/saltcorn", ["fixtures", "-r"], {
42
39
  stdio: "inherit",
43
- env,
40
+ env: serverEnv,
44
41
  });
45
42
 
46
43
  const server = spawn(
47
44
  "packages/saltcorn-cli/bin/saltcorn",
48
- ["serve", "-p", "2987"],
45
+ ["serve", "-p", port],
49
46
  {
50
47
  stdio: "inherit",
51
- env,
48
+ env: serverEnv,
52
49
  }
53
50
  );
54
51
  await sleep(2000);
52
+ return server;
53
+ }
54
+
55
+ /**
56
+ *
57
+ * @param {*} env
58
+ * @returns {Promise<void>}
59
+ */
60
+ async e2etest(env) {
61
+ const port = 2987;
62
+ const server = await this.prepareTestServer(env, port);
55
63
  const res = await this.do_test(
56
64
  "npm",
57
65
  ["run", "gotest"],
@@ -63,6 +71,23 @@ class RunTestsCommand extends Command {
63
71
  if (res.status !== 0) this.exit(res.status);
64
72
  }
65
73
 
74
+ /**
75
+ *
76
+ * @param {*} env
77
+ */
78
+ async remoteQueryTest(env, jestParams) {
79
+ const port = 3000;
80
+ env.jwt_secret = require("@saltcorn/data/db").connectObj.jwt_secret;
81
+ const server = await this.prepareTestServer(env, port);
82
+ const res = await this.do_test(
83
+ "npm",
84
+ ["run", "remote-queries-test", ...jestParams],
85
+ env,
86
+ "packages/saltcorn-data"
87
+ );
88
+ server.kill();
89
+ if (res.status !== 0) this.exit(res.status);
90
+ }
66
91
  /**
67
92
  *
68
93
  * @param {object} args
@@ -91,9 +116,6 @@ class RunTestsCommand extends Command {
91
116
  this.validateCall(args, flags);
92
117
  var env;
93
118
 
94
- spawnSync("npm", ["run", "tsc"], {
95
- stdio: "inherit",
96
- });
97
119
  const db = require("@saltcorn/data/db");
98
120
  if (db.isSQLite) {
99
121
  const testdbpath = "/tmp/sctestdb";
@@ -103,6 +125,9 @@ class RunTestsCommand extends Command {
103
125
  await db.changeConnection({ database: "saltcorn_test" });
104
126
  env = { ...process.env, PGDATABASE: "saltcorn_test" };
105
127
  }
128
+ spawnSync("npm", ["run", "tsc"], {
129
+ stdio: "inherit",
130
+ });
106
131
  const fixtures = require("@saltcorn/data/db/fixtures");
107
132
  const reset = require("@saltcorn/data/db/reset_schema");
108
133
  await reset();
@@ -123,17 +148,20 @@ class RunTestsCommand extends Command {
123
148
  }
124
149
  if (args.package === "core") {
125
150
  await this.do_test("npm", ["run", "test", ...jestParams], env);
151
+ } else if (args.package === "view-queries") {
152
+ await this.remoteQueryTest(env, jestParams);
126
153
  } else if (args.package === "e2e") {
127
154
  await this.e2etest(env);
128
155
  } else if (args.package) {
129
156
  const cwd = "packages/" + args.package;
130
157
  await this.do_test("npm", ["run", "test", ...jestParams], env, cwd);
131
158
  } else {
132
- const lerna = process.platform === "win32" ? "lerna.cmd" : "lerna";
159
+ const cwd = ".";
133
160
  await this.do_test(
134
- lerna,
135
- ["run", "test", "--stream", ...jestParams],
136
- env
161
+ "npm",
162
+ ["--workspaces", "run", "test", ...jestParams],
163
+ env,
164
+ cwd
137
165
  );
138
166
  //await this.e2etest(env);
139
167
  }
@@ -1,4 +1,5 @@
1
1
  /**
2
+ * Set up new saltcorn configuration
2
3
  * @category saltcorn-cli
3
4
  * @module commands/setup
4
5
  */
@@ -14,22 +15,32 @@ const { is } = require("contractis");
14
15
  const path = require("path");
15
16
  const fs = require("fs");
16
17
  const inquirer = require("inquirer");
17
- var tcpPortUsed = require("tcp-port-used");
18
+ const tcpPortUsed = require("tcp-port-used");
18
19
  const { spawnSync } = require("child_process");
19
- var sudo = require("sudo");
20
+ const sudo = require("sudo");
21
+ const crypto = require("crypto");
20
22
 
21
23
  /**
22
- *
24
+ * Generate password for user
23
25
  * @returns {string}
24
26
  */
27
+ // todo deduplicate code - the same function in User
25
28
  const gen_password = () => {
26
29
  const s = is.str.generate().replace(" ", "");
27
30
  if (s.length > 7) return s;
28
31
  else return gen_password();
29
32
  };
33
+ /**
34
+ * Generate jwt secret
35
+ * @returns {string}
36
+ */
37
+ const genJwtSecret = () => {
38
+ return crypto.randomBytes(64).toString("hex");
39
+ };
30
40
 
31
41
  /**
32
- *
42
+ * Ask for platform run mode (dev - run manually, server - run as system service)
43
+ *
33
44
  * @returns {Promise<object>}
34
45
  */
35
46
  const askDevServer = async () => {
@@ -58,8 +69,8 @@ const askDevServer = async () => {
58
69
  };
59
70
 
60
71
  /**
61
- *
62
- * @param {*} mod
72
+ * Unload module
73
+ * @param {*} mod
63
74
  */
64
75
  const unloadModule = (mod) => {
65
76
  var name = require.resolve(mod);
@@ -67,13 +78,19 @@ const unloadModule = (mod) => {
67
78
  };
68
79
 
69
80
  /**
81
+ * Set up platform run mode (dev - run manually, server - run as system service)
70
82
  * @returns {Promise<void>}
71
83
  */
72
84
  const setupDevMode = async () => {
73
85
  const dbPath = path.join(defaultDataPath, "scdb.sqlite");
74
86
  fs.promises.mkdir(defaultDataPath, { recursive: true });
75
87
  const session_secret = gen_password();
76
- await write_connection_config({ sqlite_path: dbPath, session_secret });
88
+ const jwt_secret = genJwtSecret();
89
+ await write_connection_config({
90
+ sqlite_path: dbPath,
91
+ session_secret,
92
+ jwt_secret,
93
+ });
77
94
 
78
95
  if (!fs.existsSync(dbPath)) {
79
96
  unloadModule("@saltcorn/data/db");
@@ -85,6 +102,8 @@ const setupDevMode = async () => {
85
102
  };
86
103
 
87
104
  /**
105
+ * Check for locally running database (ip 127.0.0.1, port 5432)
106
+ *
88
107
  * @returns {Promise<void>}
89
108
  */
90
109
  const check_db = async () => {
@@ -115,8 +134,8 @@ const check_db = async () => {
115
134
  };
116
135
 
117
136
  /**
118
- *
119
- * @param {*} args
137
+ * Execute Linux commands
138
+ * @param {*} args
120
139
  * @returns {Promise<void>}
121
140
  */
122
141
  const asyncSudo = (args) => {
@@ -136,8 +155,8 @@ const asyncSudo = (args) => {
136
155
  };
137
156
 
138
157
  /**
139
- *
140
- * @param {*} args
158
+ * Execute Postgres commands
159
+ * @param {*} args
141
160
  * @returns {Promise<void>}
142
161
  */
143
162
  const asyncSudoPostgres = (args) => {
@@ -145,8 +164,8 @@ const asyncSudoPostgres = (args) => {
145
164
  };
146
165
 
147
166
  /**
148
- *
149
- * @param {string} for_who
167
+ * Ask for passworf
168
+ * @param {string} for_who
150
169
  * @returns {Promise<string>}
151
170
  */
152
171
  const get_password = async (for_who) => {
@@ -163,6 +182,7 @@ const get_password = async (for_who) => {
163
182
  };
164
183
 
165
184
  /**
185
+ * Install Database
166
186
  * @returns {Promise<void>}
167
187
  */
168
188
  const install_db = async () => {
@@ -204,6 +224,7 @@ const install_db = async () => {
204
224
  `ALTER SCHEMA public OWNER TO ${user};`,
205
225
  ]);
206
226
  const session_secret = await get_password("session secret");
227
+ const jwt_secret = genJwtSecret();
207
228
  await write_connection_config({
208
229
  host: "localhost",
209
230
  port: 5432,
@@ -211,12 +232,13 @@ const install_db = async () => {
211
232
  user,
212
233
  password: scpass,
213
234
  session_secret,
235
+ jwt_secret,
214
236
  multi_tenant: false,
215
237
  });
216
238
  };
217
239
 
218
240
  /**
219
- *
241
+ * Ask for Database parameters
220
242
  * @returns {Promise<object>}
221
243
  */
222
244
  const prompt_connection = async () => {
@@ -236,6 +258,7 @@ const prompt_connection = async () => {
236
258
  required: true,
237
259
  });
238
260
  const session_secret = await get_password("session secret");
261
+ const jwt_secret = genJwtSecret();
239
262
  return {
240
263
  host: host || "localhost",
241
264
  port: port || 5432,
@@ -243,11 +266,13 @@ const prompt_connection = async () => {
243
266
  user: user || "saltcorn",
244
267
  password: password,
245
268
  session_secret,
269
+ jwt_secret,
246
270
  multi_tenant: false,
247
271
  };
248
272
  };
249
273
 
250
274
  /**
275
+ * Write platform config
251
276
  * @returns {Promise<void>}
252
277
  */
253
278
  const setup_connection_config = async () => {
@@ -256,8 +281,8 @@ const setup_connection_config = async () => {
256
281
  };
257
282
 
258
283
  /**
259
- *
260
- * @param {object} connobj
284
+ *
285
+ * @param {object} connobj
261
286
  * @returns {Promise<void>}
262
287
  */
263
288
  const write_connection_config = async (connobj) => {
@@ -290,16 +315,16 @@ const setup_connection = async () => {
290
315
  };
291
316
 
292
317
  /**
293
- *
294
- * @param {object} db
295
- * @param {string} tblname
318
+ *
319
+ * @param {object} db
320
+ * @param {string} tblname
296
321
  * @returns {Promise<boolean>}
297
322
  */
298
323
  const table_exists = async (db, tblname) => {
299
- const { rows } = await db.query(`SELECT EXISTS
324
+ const { rows } = await db.query(`SELECT EXISTS
300
325
  (
301
326
  SELECT 1
302
- FROM information_schema.tables
327
+ FROM information_schema.tables
303
328
  WHERE table_schema = 'public'
304
329
  AND table_name = '${tblname}'
305
330
  );`);
@@ -346,7 +371,7 @@ class SetupCommand extends Command {
346
371
  * @returns {Promise<void>}
347
372
  */
348
373
  async run() {
349
- console.log("Run setip");
374
+ console.log("Run setup");
350
375
  const mode = await askDevServer();
351
376
  if (mode == "server") {
352
377
  // check if i already know how to connect
@@ -367,7 +392,7 @@ class SetupCommand extends Command {
367
392
  */
368
393
  SetupCommand.description = `Set up a new system
369
394
  ...
370
- This will attempt to install or connect a database, and set up a
395
+ This will attempt to install or connect a database, and set up a
371
396
  configuration file
372
397
  `;
373
398