@saltcorn/cli 1.6.0-alpha.0 → 1.6.0-alpha.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.
@@ -264,6 +264,12 @@
264
264
  "allowNo": false,
265
265
  "type": "boolean"
266
266
  },
267
+ "syncOnAppResume": {
268
+ "description": "When offline mode is enabled, synchronize the synchedTables tables when the app is resumed.",
269
+ "name": "syncOnAppResume",
270
+ "allowNo": false,
271
+ "type": "boolean"
272
+ },
267
273
  "pushSync": {
268
274
  "description": "When offline mode is enabled, synchronize the synchedTables tables when a push notification is received.",
269
275
  "name": "pushSync",
@@ -277,6 +283,12 @@
277
283
  "multiple": false,
278
284
  "type": "option"
279
285
  },
286
+ "noProvisioningProfile": {
287
+ "description": "Do not use a provisioning profile, only for simulator builds (iOS only)",
288
+ "name": "noProvisioningProfile",
289
+ "allowNo": false,
290
+ "type": "boolean"
291
+ },
280
292
  "provisioningProfile": {
281
293
  "description": "This profile will be used to sign your app",
282
294
  "name": "provisioningProfile",
@@ -291,6 +303,13 @@
291
303
  "multiple": false,
292
304
  "type": "option"
293
305
  },
306
+ "appGroupId": {
307
+ "description": "An app group identifier to share data between the main app and the share extension on iOS, e.g. group.com.saltcorn.myapp",
308
+ "name": "appGroupId",
309
+ "hasDynamicHelp": false,
310
+ "multiple": false,
311
+ "type": "option"
312
+ },
294
313
  "buildType": {
295
314
  "description": "debug or release build",
296
315
  "name": "buildType",
@@ -298,6 +317,12 @@
298
317
  "multiple": false,
299
318
  "type": "option"
300
319
  },
320
+ "allowClearTextTraffic": {
321
+ "description": "Enable this to allow unsecure HTTP connections. Useful for local testing.",
322
+ "name": "allowClearTextTraffic",
323
+ "allowNo": false,
324
+ "type": "boolean"
325
+ },
301
326
  "androidKeystore": {
302
327
  "description": "A self-signed certificate that includes the private key used to sign your app.",
303
328
  "name": "androidKeystore",
@@ -2022,6 +2047,38 @@
2022
2047
  "transform-field.js"
2023
2048
  ]
2024
2049
  },
2050
+ "dev:build": {
2051
+ "aliases": [],
2052
+ "args": {
2053
+ "component": {
2054
+ "description": "Component to rebuild",
2055
+ "name": "component",
2056
+ "options": [
2057
+ "builder",
2058
+ "filemanager",
2059
+ "workflow-editor"
2060
+ ],
2061
+ "required": false
2062
+ }
2063
+ },
2064
+ "description": "Rebuild static assets",
2065
+ "flags": {},
2066
+ "hasDynamicHelp": false,
2067
+ "hiddenAliases": [],
2068
+ "id": "dev:build",
2069
+ "pluginAlias": "@saltcorn/cli",
2070
+ "pluginName": "@saltcorn/cli",
2071
+ "pluginType": "core",
2072
+ "strict": true,
2073
+ "enableJsonFlag": false,
2074
+ "isESM": false,
2075
+ "relativePath": [
2076
+ "src",
2077
+ "commands",
2078
+ "dev",
2079
+ "build.js"
2080
+ ]
2081
+ },
2025
2082
  "dev:localize-plugin": {
2026
2083
  "aliases": [],
2027
2084
  "args": {
@@ -2127,6 +2184,14 @@
2127
2184
  "hasDynamicHelp": false,
2128
2185
  "multiple": false,
2129
2186
  "type": "option"
2187
+ },
2188
+ "overwriteDependency": {
2189
+ "char": "o",
2190
+ "description": "Dependency to overwrite with a local plugin (can be used multiple times). Please specify the path to the local plugin, the module name will be taken from there.",
2191
+ "name": "overwriteDependency",
2192
+ "hasDynamicHelp": false,
2193
+ "multiple": true,
2194
+ "type": "option"
2130
2195
  }
2131
2196
  },
2132
2197
  "hasDynamicHelp": false,
@@ -2251,6 +2316,46 @@
2251
2316
  "release.js"
2252
2317
  ]
2253
2318
  },
2319
+ "dev:serve": {
2320
+ "aliases": [],
2321
+ "args": {},
2322
+ "description": "Development server. Serve on port 3000, restart when source files change",
2323
+ "flags": {
2324
+ "port": {
2325
+ "char": "p",
2326
+ "description": "port",
2327
+ "name": "port",
2328
+ "default": 3000,
2329
+ "hasDynamicHelp": false,
2330
+ "multiple": false,
2331
+ "type": "option"
2332
+ },
2333
+ "workers": {
2334
+ "char": "w",
2335
+ "description": "workers",
2336
+ "name": "workers",
2337
+ "default": 1,
2338
+ "hasDynamicHelp": false,
2339
+ "multiple": false,
2340
+ "type": "option"
2341
+ }
2342
+ },
2343
+ "hasDynamicHelp": false,
2344
+ "hiddenAliases": [],
2345
+ "id": "dev:serve",
2346
+ "pluginAlias": "@saltcorn/cli",
2347
+ "pluginName": "@saltcorn/cli",
2348
+ "pluginType": "core",
2349
+ "strict": true,
2350
+ "enableJsonFlag": false,
2351
+ "isESM": false,
2352
+ "relativePath": [
2353
+ "src",
2354
+ "commands",
2355
+ "dev",
2356
+ "serve.js"
2357
+ ]
2358
+ },
2254
2359
  "dev:test-plugin": {
2255
2360
  "aliases": [],
2256
2361
  "args": {
@@ -2315,5 +2420,5 @@
2315
2420
  ]
2316
2421
  }
2317
2422
  },
2318
- "version": "1.6.0-alpha.0"
2423
+ "version": "1.6.0-alpha.10"
2319
2424
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@saltcorn/cli",
3
3
  "description": "Command-line interface for Saltcorn, open-source no-code platform",
4
4
  "homepage": "https://saltcorn.com",
5
- "version": "1.6.0-alpha.0",
5
+ "version": "1.6.0-alpha.10",
6
6
  "author": "Tom Nielsen @glutamate",
7
7
  "bin": {
8
8
  "saltcorn": "./bin/saltcorn"
@@ -11,13 +11,13 @@
11
11
  "dependencies": {
12
12
  "@oclif/core": "4.4.0",
13
13
  "@oclif/plugin-plugins": "^5.4.26",
14
- "@saltcorn/admin-models": "1.6.0-alpha.0",
15
- "@saltcorn/common-code": "1.6.0-alpha.0",
16
- "@saltcorn/data": "1.6.0-alpha.0",
17
- "@saltcorn/mobile-app": "1.6.0-alpha.0",
18
- "@saltcorn/mobile-builder": "1.6.0-alpha.0",
19
- "@saltcorn/plugins-loader": "1.6.0-alpha.0",
20
- "@saltcorn/server": "1.6.0-alpha.0",
14
+ "@saltcorn/admin-models": "1.6.0-alpha.10",
15
+ "@saltcorn/common-code": "1.6.0-alpha.10",
16
+ "@saltcorn/data": "1.6.0-alpha.10",
17
+ "@saltcorn/mobile-app": "1.6.0-alpha.10",
18
+ "@saltcorn/mobile-builder": "1.6.0-alpha.10",
19
+ "@saltcorn/plugins-loader": "1.6.0-alpha.10",
20
+ "@saltcorn/server": "1.6.0-alpha.10",
21
21
  "contractis": "^0.1.0",
22
22
  "dateformat": "^4.6.3",
23
23
  "inquirer": "^12.3.3",
@@ -2,9 +2,7 @@ const { Command, Flags } = require("@oclif/core");
2
2
  const path = require("path");
3
3
  const Plugin = require("@saltcorn/data/models/plugin");
4
4
  const { MobileBuilder } = require("@saltcorn/mobile-builder/mobile-builder");
5
- const {
6
- decodeProvisioningProfile,
7
- } = require("@saltcorn/mobile-builder/utils/common-build-utils");
5
+ const { decodeProvisioningProfile } = require("@saltcorn/data/utils");
8
6
  const { init_multi_tenant, getState } = require("@saltcorn/data/db/state");
9
7
  const { loadAllPlugins } = require("@saltcorn/server/load_plugins");
10
8
  const User = require("@saltcorn/data/models/user");
@@ -44,7 +42,7 @@ class BuildAppCommand extends Command {
44
42
  );
45
43
  }
46
44
 
47
- if (flags.platforms.includes("ios")) {
45
+ if (flags.platforms.includes("ios") && !flags.noProvisioningProfile) {
48
46
  if (!flags.provisioningProfile)
49
47
  throw new Error("Please specify a provisioning profile");
50
48
  if (flags.allowShareTo && !flags.shareExtensionProvisioningProfile)
@@ -73,26 +71,31 @@ class BuildAppCommand extends Command {
73
71
  async buildIosParams(flags) {
74
72
  let result = undefined;
75
73
  if (flags.platforms.includes("ios")) {
76
- const mainProfileVals = await decodeProvisioningProfile(
77
- flags.buildDirectory,
78
- flags.provisioningProfile
79
- );
80
- result = {
81
- appleTeamId: mainProfileVals.teamId,
82
- mainProvisioningProfile: {
83
- guuid: mainProfileVals.guuid,
84
- },
85
- };
86
- if (flags.allowShareTo) {
87
- const shareExtProfileVals = await decodeProvisioningProfile(
88
- flags.buildDirectory,
89
- flags.shareExtensionProvisioningProfile
74
+ if (flags.noProvisioningProfile)
75
+ result = {
76
+ noProvisioningProfile: true,
77
+ };
78
+ else {
79
+ const mainProfileVals = await decodeProvisioningProfile(
80
+ flags.provisioningProfile
90
81
  );
91
- result.shareExtensionProvisioningProfile = {
92
- guuid: shareExtProfileVals.guuid,
93
- specifier: shareExtProfileVals.specifier,
94
- identifier: shareExtProfileVals.identifier,
82
+ result = {
83
+ appleTeamId: mainProfileVals.teamId,
84
+ mainProvisioningProfile: {
85
+ guuid: mainProfileVals.guuid,
86
+ },
95
87
  };
88
+ if (flags.allowShareTo) {
89
+ const shareExtProfileVals = await decodeProvisioningProfile(
90
+ flags.shareExtensionProvisioningProfile
91
+ );
92
+ result.shareExtensionProvisioningProfile = {
93
+ guuid: shareExtProfileVals.guuid,
94
+ specifier: shareExtProfileVals.specifier,
95
+ identifier: shareExtProfileVals.identifier,
96
+ ...(flags.appGroupId ? { appGroupId: flags.appGroupId } : {}),
97
+ };
98
+ }
96
99
  }
97
100
  }
98
101
  return result;
@@ -138,6 +141,7 @@ class BuildAppCommand extends Command {
138
141
  showContinueAsPublicUser: flags.showContinueAsPublicUser,
139
142
  allowOfflineMode: flags.allowOfflineMode,
140
143
  syncOnReconnect: flags.syncOnReconnect,
144
+ syncOnAppResume: flags.syncOnAppResume,
141
145
  pushSync: flags.pushSync,
142
146
  syncInterval: flags.syncInterval,
143
147
  allowShareTo: flags.allowShareTo,
@@ -147,6 +151,7 @@ class BuildAppCommand extends Command {
147
151
  iosParams: iosParams,
148
152
  tenantAppName: flags.tenantAppName,
149
153
  buildType: flags.buildType,
154
+ allowClearTextTraffic: flags.allowClearTextTraffic,
150
155
  keyStorePath: flags.androidKeystore,
151
156
  keyStoreAlias: flags.androidKeyStoreAlias,
152
157
  keyStorePassword: flags.androidKeystorePassword,
@@ -324,6 +329,12 @@ BuildAppCommand.flags = {
324
329
  "Run Synchronizations and return into online mode when the network connection is restored. " +
325
330
  "When disabled, you still can do this manually.",
326
331
  }),
332
+ syncOnAppResume: Flags.boolean({
333
+ name: "Sync on app resume",
334
+ string: "syncOnAppResume",
335
+ description:
336
+ "When offline mode is enabled, synchronize the synchedTables tables when the app is resumed.",
337
+ }),
327
338
  pushSync: Flags.boolean({
328
339
  name: "Push sync",
329
340
  string: "pushSync",
@@ -337,6 +348,13 @@ BuildAppCommand.flags = {
337
348
  "Perdiodic interval (in minutes) to run synchronizations in the background. " +
338
349
  "This is just a min interval, depending on system conditions, the actual time may be longer.",
339
350
  }),
351
+ noProvisioningProfile: Flags.boolean({
352
+ name: "no provisioning profile",
353
+ string: "noProvisioningProfile",
354
+ description:
355
+ "Do not use a provisioning profile, only for simulator builds (iOS only)",
356
+ default: false,
357
+ }),
340
358
  provisioningProfile: Flags.string({
341
359
  name: "provisioning profile",
342
360
  string: "provisioningProfile",
@@ -348,11 +366,24 @@ BuildAppCommand.flags = {
348
366
  description:
349
367
  "This profile will be used to sign your share extension on iOS",
350
368
  }),
369
+ appGroupId: Flags.string({
370
+ name: "app group id",
371
+ string: "appGroupId",
372
+ description:
373
+ "An app group identifier to share data between the main app and the share extension on iOS, e.g. group.com.saltcorn.myapp",
374
+ }),
351
375
  buildType: Flags.string({
352
376
  name: "build type",
353
377
  string: "buildType",
354
378
  description: "debug or release build",
355
379
  }),
380
+ allowClearTextTraffic: Flags.boolean({
381
+ name: "allow clear text traffic",
382
+ string: "allowClearTextTraffic",
383
+ description:
384
+ "Enable this to allow unsecure HTTP connections. Useful for local testing.",
385
+ default: false,
386
+ }),
356
387
  androidKeystore: Flags.string({
357
388
  name: "android key store",
358
389
  string: "androidKeyStore",
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @category saltcorn-cli
3
+ * @module commands/dev/build
4
+ */
5
+ const { Command, Flags, Args } = require("@oclif/core");
6
+ const { spawnSync } = require("child_process");
7
+ const { sleep } = require("../../common");
8
+ /**
9
+ * DevBuildCommand Class
10
+ * @extends oclif.Command
11
+ * @category saltcorn-cli
12
+ */
13
+ class DevBuildCommand extends Command {
14
+ /**
15
+ * @returns {Promise<void>}
16
+ */
17
+ async run() {
18
+ const { args } = await this.parse(DevBuildCommand);
19
+
20
+ const { reactPackages } = require("@saltcorn/server/restart_watcher");
21
+
22
+ for (const { buildDir } of reactPackages) {
23
+ if (args.component && !buildDir.includes(args.component)) continue;
24
+
25
+ const { status, signal } = spawnSync("npm", ["run", "build"], {
26
+ stdio: "inherit",
27
+ cwd: buildDir,
28
+ });
29
+ if (status) process.exit(status);
30
+ if (signal) process.exit();
31
+ }
32
+ }
33
+ }
34
+
35
+ /**
36
+ * @type {string}
37
+ */
38
+ DevBuildCommand.description = `Rebuild static assets`;
39
+
40
+ DevBuildCommand.args = {
41
+ component: Args.string({
42
+ required: false,
43
+ description: "Component to rebuild",
44
+ options: ["builder", "filemanager", "workflow-editor"],
45
+ }),
46
+ };
47
+ module.exports = DevBuildCommand;
@@ -15,7 +15,10 @@ const removePluginsDir = () => {
15
15
  fs.rmSync(pluginsPath, { force: true, recursive: true });
16
16
  };
17
17
 
18
- const writeJestConfigIntoPluginDir = (location) => {
18
+ const writeJestConfigIntoPluginDir = (location, plugin) => {
19
+ const state = getState();
20
+ const modName = state.plugin_module_names[plugin.name];
21
+ const module = state.plugins[modName];
19
22
  fs.writeFileSync(
20
23
  path.join(location, "jest.config.js"),
21
24
  `const sqliteDir = process.env.JEST_SC_SQLITE_DIR;
@@ -35,6 +38,17 @@ const config = {
35
38
  "@saltcorn/markup$": markupDir,
36
39
  "@saltcorn/markup/(.*)": markupDir + "/$1",
37
40
  "@saltcorn/admin-models/(.*)": adminModelsDir + "/$1",
41
+ ${(module?.dependencies || [])
42
+ .map((dep) => {
43
+ let pluginLocation = state.plugin_locations[dep];
44
+ if (!pluginLocation) {
45
+ // try without org
46
+ const orgRemoved = dep.replace(/^@[^/]+\//, "");
47
+ pluginLocation = state.plugin_locations[orgRemoved];
48
+ }
49
+ return pluginLocation ? `"${dep}": "${pluginLocation}",` : "";
50
+ })
51
+ .join("\n ")}
38
52
  },
39
53
  modulePaths: [modulePath],
40
54
  };
@@ -77,42 +91,48 @@ const spawnTest = async (installDir, env) => {
77
91
  return ret.status;
78
92
  };
79
93
 
80
- const installPlugin = async (plugin) => {
94
+ const preparePlugin = async (plugin, overwrites) => {
81
95
  await removeOldPlugin(plugin);
82
96
  removePluginsDir();
83
- await loadAndSaveNewPlugin(plugin, false, false);
97
+ await loadAndSaveNewPlugin(
98
+ plugin,
99
+ false,
100
+ false,
101
+ (str) => str,
102
+ false,
103
+ overwrites
104
+ );
84
105
  const location = getPluginLocation(plugin.name);
85
106
  writeMockFilesIntoPluginDir(location);
86
- writeJestConfigIntoPluginDir(location);
107
+ writeJestConfigIntoPluginDir(location, plugin);
87
108
  return location;
88
109
  };
89
110
 
90
- const removeOldPlugin = async (plugin) => {
91
- const byName = await Plugin.findOne({ name: plugin.name });
111
+ const removeOldPlugin = async (newPlugin) => {
112
+ const byName = await Plugin.findOne({ name: newPlugin.name });
92
113
  if (byName) {
93
114
  await byName.delete();
94
115
  await new PluginInstaller(byName).remove();
95
116
  }
96
- let oldPlugin = null;
97
- if (!plugin.name.startsWith("@saltcorn/")) {
98
- const withOrg = await Plugin.findOne({ name: `@saltcorn/${plugin.name}` });
117
+ let oldDbPlugin = null;
118
+ if (!newPlugin.name.startsWith("@saltcorn/")) {
119
+ const withOrg = await Plugin.findOne({
120
+ name: `@saltcorn/${newPlugin.name}`,
121
+ });
99
122
  if (withOrg) {
100
123
  await withOrg.delete();
101
- oldPlugin = withOrg;
124
+ oldDbPlugin = withOrg;
102
125
  }
103
126
  } else {
104
127
  const withoutOrg = await Plugin.findOne({
105
- name: plugin.name.replace(/^@saltcorn\//, ""),
128
+ name: newPlugin.name.replace(/^@saltcorn\//, ""),
106
129
  });
107
130
  if (withoutOrg) {
108
131
  await withoutOrg.delete();
109
- oldPlugin = withoutOrg;
132
+ oldDbPlugin = withoutOrg;
110
133
  }
111
134
  }
112
- if (oldPlugin) {
113
- const installer = new PluginInstaller(oldPlugin);
114
- await installer.remove();
115
- }
135
+ await new PluginInstaller(oldDbPlugin || newPlugin).remove();
116
136
  };
117
137
 
118
138
  const getPluginLocation = (pluginName) => {
@@ -123,7 +143,7 @@ const getPluginLocation = (pluginName) => {
123
143
  );
124
144
  };
125
145
 
126
- const testLocalPlugin = async (dir, env, backupFile) => {
146
+ const testLocalPlugin = async (dir, env, backupFile, overwrites) => {
127
147
  if (backupFile) {
128
148
  await prep_test_db(path.join(dir, "tests", backupFile));
129
149
  } else await require("@saltcorn/data/db/reset_schema")();
@@ -135,27 +155,49 @@ const testLocalPlugin = async (dir, env, backupFile) => {
135
155
  source: "local",
136
156
  location: path.resolve(dir),
137
157
  });
138
- const installDir = await installPlugin(plugin);
158
+ const installDir = await preparePlugin(plugin, overwrites);
139
159
  return await spawnTest(installDir, env);
140
160
  };
141
161
 
142
- const testReleasedPlugin = async (pluginName, env, backupFile) => {
162
+ const testReleasedPlugin = async (pluginName, env, backupFile, overwrites) => {
143
163
  await require("@saltcorn/data/db/reset_schema")();
144
164
  const plugin = await Plugin.store_by_name(pluginName);
145
165
  delete plugin.id;
146
- const installDir = await installPlugin(plugin);
166
+ const installDir = await preparePlugin(plugin, overwrites);
147
167
  if (backupFile) {
148
168
  await prep_test_db(path.join(installDir, "tests", backupFile));
149
169
  }
150
170
  return await spawnTest(installDir, env);
151
171
  };
152
172
 
173
+ /**
174
+ *
175
+ * @param {string[]} overwrites paths to local plugins
176
+ * @returns an object mapping module names to paths
177
+ */
178
+ const prepOverwritesCfg = (overwrites) => {
179
+ const result = {};
180
+ if (overwrites) {
181
+ for (const flag of overwrites) {
182
+ const pkgpath = path.join(flag, "package.json");
183
+ if (!fs.existsSync(pkgpath))
184
+ throw new Error(
185
+ `Overwrite dependency package.json not found in ${flag}`
186
+ );
187
+ const pkg = require(pkgpath);
188
+ result[pkg.name] = flag;
189
+ }
190
+ }
191
+ return result;
192
+ };
193
+
153
194
  /**
154
195
  * Install a plugin, spawn 'npm run test' in the install dir and check the return code
155
196
  */
156
197
  class PluginTestCommand extends Command {
157
198
  async run() {
158
199
  const { flags } = await this.parse(PluginTestCommand);
200
+ const overwrites = prepOverwritesCfg(flags.overwriteDependency);
159
201
  const dbname = flags.database ? flags.database : "saltcorn_test";
160
202
  let env = null;
161
203
  const db = require("@saltcorn/data/db");
@@ -174,14 +216,16 @@ class PluginTestCommand extends Command {
174
216
  jestStatus = await testLocalPlugin(
175
217
  flags.directory,
176
218
  env,
177
- flags.backupFile
219
+ flags.backupFile,
220
+ overwrites
178
221
  );
179
222
  } else if (flags.name) {
180
223
  console.log(`Testing released plugin '${flags.name}'`);
181
224
  jestStatus = await testReleasedPlugin(
182
225
  flags.name,
183
226
  env,
184
- flags.backupFile
227
+ flags.backupFile,
228
+ overwrites
185
229
  );
186
230
  }
187
231
  } catch (error) {
@@ -218,6 +262,13 @@ PluginTestCommand.flags = {
218
262
  string: "database",
219
263
  description: "Run on specified database. Default is 'saltcorn_test''",
220
264
  }),
265
+ overwriteDependency: Flags.string({
266
+ char: "o",
267
+ description:
268
+ "Dependency to overwrite with a local plugin (can be used multiple times). " +
269
+ "Please specify the path to the local plugin, the module name will be taken from there.",
270
+ multiple: true,
271
+ }),
221
272
  };
222
273
 
223
274
  PluginTestCommand.description =
@@ -71,6 +71,7 @@ class ReleaseCommand extends Command {
71
71
  "@saltcorn/postgres": { dir: "postgres", publish: true },
72
72
  "@saltcorn/types": { dir: "saltcorn-types", publish: true },
73
73
  "@saltcorn/builder": { dir: "saltcorn-builder", publish: true },
74
+ "@saltcorn/workflow-editor": { dir: "workflow-editor", publish: true },
74
75
  "@saltcorn/filemanager": { dir: "filemanager", publish: true },
75
76
  "@saltcorn/data": { dir: "saltcorn-data", publish: true },
76
77
  "@saltcorn/admin-models": {
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @category saltcorn-cli
3
+ * @module commands/dev/serve
4
+ */
5
+ const { Command, Flags } = require("@oclif/core");
6
+ const { execSync, spawnSync } = require("child_process");
7
+ const { sleep } = require("../../common");
8
+ /**
9
+ * DevServeCommand Class
10
+ * @extends oclif.Command
11
+ * @category saltcorn-cli
12
+ */
13
+ class DevServeCommand extends Command {
14
+ /**
15
+ * @returns {Promise<void>}
16
+ */
17
+ async run() {
18
+ const { flags } = await this.parse(DevServeCommand);
19
+
20
+ await this.tryTsc();
21
+ for (;;) {
22
+ const scResult = spawnSync(
23
+ "saltcorn",
24
+ [
25
+ "serve",
26
+ "--dev",
27
+ "--addschema",
28
+ ...(flags.port ? ["-p", flags.port] : []),
29
+ ],
30
+ {
31
+ env: {
32
+ ...process.env,
33
+ SALTCORN_NWORKERS:
34
+ flags.workers || process.env.SALTCORN_NWORKERS || 1,
35
+ },
36
+ stdio: "inherit",
37
+ }
38
+ );
39
+ if (scResult.signal) process.exit();
40
+ switch (scResult.status) {
41
+ case 3:
42
+ //root tsc error
43
+ await this.tryTsc();
44
+ break;
45
+
46
+ // todo builder error
47
+ default:
48
+ break;
49
+ }
50
+ }
51
+ }
52
+
53
+ async tryTsc() {
54
+ const tscResult = spawnSync("npm", ["run", "tsc"], {
55
+ stdio: "inherit",
56
+ });
57
+ if (tscResult.status) {
58
+ //todo watch instead
59
+ await sleep(3000);
60
+ await this.tryTsc();
61
+ }
62
+ }
63
+ }
64
+
65
+ /**
66
+ * @type {string}
67
+ */
68
+ DevServeCommand.description = `Development server. Serve on port 3000, restart when source files change`;
69
+
70
+ DevServeCommand.flags = {
71
+ port: Flags.integer({ char: "p", description: "port", default: 3000 }),
72
+ workers: Flags.integer({ char: "w", description: "workers", default: 1 }),
73
+ };
74
+
75
+ module.exports = DevServeCommand;
@@ -5,7 +5,7 @@
5
5
  const { Command, Flags, Args } = require("@oclif/core");
6
6
  const { spawnSync } = require("child_process");
7
7
  const path = require("path");
8
- const { maybe_as_tenant } = require("../common");
8
+ const { maybe_as_tenant, init_some_tenants } = require("../common");
9
9
  const fs = require("fs");
10
10
 
11
11
  /**
@@ -45,6 +45,8 @@ class RestoreCommand extends Command {
45
45
  const { restore } = require("@saltcorn/admin-models/models/backup");
46
46
  const User = require("@saltcorn/data/models/user");
47
47
  const load_plugins = require("@saltcorn/server/load_plugins");
48
+ await init_some_tenants(tenant);
49
+
48
50
  await maybe_as_tenant(tenant, async () => {
49
51
  await load_plugins.loadAllPlugins();
50
52
  const hasUsers = await User.nonEmpty();