wattpm 2.63.4 → 2.65.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/index.js CHANGED
@@ -1,25 +1,22 @@
1
1
  import { bold } from 'colorette'
2
+ import { adminCommand } from './lib/commands/admin.js'
2
3
  import { buildCommand, installCommand, updateCommand } from './lib/commands/build.js'
4
+ import { createCommand } from './lib/commands/create.js'
3
5
  import { devCommand, reloadCommand, restartCommand, startCommand, stopCommand } from './lib/commands/execution.js'
4
6
  import { importCommand, resolveCommand } from './lib/commands/external.js'
5
7
  import { helpCommand } from './lib/commands/help.js'
6
- import { initCommand } from './lib/commands/init.js'
7
8
  import { injectCommand } from './lib/commands/inject.js'
8
9
  import { logsCommand } from './lib/commands/logs.js'
9
10
  import { configCommand, envCommand, psCommand, servicesCommand } from './lib/commands/management.js'
10
11
  import { metricsCommand } from './lib/commands/metrics.js'
11
12
  import { patchConfigCommand } from './lib/commands/patch-config.js'
12
- import { adminCommand } from './lib/commands/admin.js'
13
13
  import { version } from './lib/schema.js'
14
- import { createLogger, overrideFatal, parseArgs, setVerbose } from './lib/utils.js'
14
+ import { createLogger, parseArgs, setVerbose } from './lib/utils.js'
15
15
 
16
16
  export async function main () {
17
17
  globalThis.platformatic = { executable: 'watt' }
18
-
19
18
  const logger = createLogger('info')
20
19
 
21
- overrideFatal(logger)
22
-
23
20
  const options = {
24
21
  verbose: {
25
22
  short: 'v',
@@ -30,6 +27,7 @@ export async function main () {
30
27
  type: 'boolean'
31
28
  },
32
29
  help: {
30
+ short: 'h',
33
31
  type: 'boolean'
34
32
  }
35
33
  }
@@ -42,7 +40,10 @@ export async function main () {
42
40
  }
43
41
 
44
42
  if (values.help) {
45
- helpCommand([])
43
+ helpCommand(logger, [])
44
+ return
45
+ } else if (unparsed.includes('-h') || unparsed.includes('--help')) {
46
+ helpCommand(logger, unparsed)
46
47
  return
47
48
  }
48
49
 
@@ -52,9 +53,6 @@ export async function main () {
52
53
 
53
54
  let command
54
55
  switch (unparsed[0]) {
55
- case 'init':
56
- command = initCommand
57
- break
58
56
  case 'build':
59
57
  command = buildCommand
60
58
  break
@@ -112,14 +110,20 @@ export async function main () {
112
110
  case 'metrics':
113
111
  command = metricsCommand
114
112
  break
113
+ /* c8 ignore next - Just an alias */
114
+ case 'init':
115
+ case 'create':
116
+ command = createCommand
117
+ break
115
118
  case 'admin':
116
119
  command = adminCommand
117
120
  break
121
+ /* c8 ignore next 5 */
118
122
  default:
119
123
  logger.fatal(
120
124
  `Unknown command ${bold(unparsed[0])}. Please run ${bold("'wattpm help'")} to see available commands.`
121
125
  )
122
- break
126
+ return
123
127
  }
124
128
 
125
129
  await command(logger, unparsed.slice(1))
@@ -1,10 +1,9 @@
1
1
  import { spawn } from 'node:child_process'
2
- import { parseArgs } from '../utils.js'
2
+ import { getPackageManager, parseArgs } from '../utils.js'
3
3
 
4
4
  export function adminCommand (logger, args) {
5
- logger.info('Running watt-admin via npx')
6
- const {
7
- values: { latest },
5
+ let {
6
+ values: { latest, 'package-manager': packageManager }
8
7
  } = parseArgs(
9
8
  args,
10
9
  {
@@ -12,13 +11,33 @@ export function adminCommand (logger, args) {
12
11
  type: 'boolean',
13
12
  short: 'l'
14
13
  },
14
+ 'package-manager': {
15
+ type: 'string',
16
+ short: 'P'
17
+ }
15
18
  },
16
19
  false
17
20
  )
21
+
22
+ if (!packageManager) {
23
+ packageManager = getPackageManager(process.cwd())
24
+ }
25
+
18
26
  const modifier = latest ? '@latest' : ''
19
- const proc = spawn('npx', ['-y', '@platformatic/watt-admin' + modifier], { stdio: 'inherit' })
20
27
 
21
- proc.on('exit', (code) => {
28
+ let command = 'npx'
29
+ const commandArgs = ['@platformatic/watt-admin' + modifier]
30
+
31
+ if (packageManager === 'pnpm') {
32
+ command = 'pnpx'
33
+ } else {
34
+ commandArgs.unshift('-y')
35
+ }
36
+
37
+ logger.info(`Running watt-admin via ${command} ...`)
38
+ const proc = spawn(command, commandArgs, { stdio: 'inherit' })
39
+
40
+ proc.on('exit', code => {
22
41
  process.exit(code)
23
42
  })
24
43
  }
@@ -30,8 +49,12 @@ export const help = {
30
49
  options: [
31
50
  {
32
51
  usage: '-l --latest',
33
- description: 'Use the latest version of @platformatic/watt-admin from',
52
+ description: 'Use the latest version of @platformatic/watt-admin from'
34
53
  },
54
+ {
55
+ usage: 'P, --package-manager <executable>',
56
+ description: 'Use an alternative package manager (the default is to autodetect it)'
57
+ }
35
58
  ]
36
- },
59
+ }
37
60
  }
@@ -14,7 +14,7 @@ import {
14
14
  getPackageManager,
15
15
  getRoot,
16
16
  loadConfigurationFile,
17
- overrideFatal,
17
+ logFatalError,
18
18
  parseArgs
19
19
  } from '../utils.js'
20
20
 
@@ -34,7 +34,7 @@ async function executeCommand (root, ...args) {
34
34
  }
35
35
  }
36
36
 
37
- /* c8 ignore next */
37
+ /* c8 ignore next - Mistakenly reported as uncovered by C8 */
38
38
  return execa(...args)
39
39
  }
40
40
 
@@ -57,9 +57,13 @@ export async function installDependencies (logger, root, services, production, p
57
57
  )
58
58
 
59
59
  await executeCommand(root, packageManager, args, { cwd: root, stdio: 'inherit' })
60
- /* c8 ignore next 3 */
60
+ /* c8 ignore next 7 */
61
61
  } catch (error) {
62
- logger.fatal({ error: ensureLoggableError(error) }, 'Unable to install dependencies of the application.')
62
+ return logFatalError(
63
+ logger,
64
+ { error: ensureLoggableError(error) },
65
+ 'Unable to install dependencies of the application.'
66
+ )
63
67
  }
64
68
 
65
69
  for (const service of services) {
@@ -69,21 +73,26 @@ export async function installDependencies (logger, root, services, production, p
69
73
 
70
74
  try {
71
75
  logger.info(
72
- `Installing ${production ? 'production ' : ''}dependencies for the service ${bold(service.id)} using ${servicePackageManager} ...`
76
+ `Installing ${production ? 'production ' : ''}dependencies for the service ${bold(
77
+ service.id
78
+ )} using ${servicePackageManager} ...`
73
79
  )
74
80
 
75
81
  await executeCommand(root, servicePackageManager, servicePackageArgs, {
76
82
  cwd: resolve(root, service.path),
77
83
  stdio: 'inherit'
78
84
  })
79
- /* c8 ignore next 6 */
85
+ /* c8 ignore next 7 */
80
86
  } catch (error) {
81
- logger.fatal(
87
+ return logFatalError(
88
+ logger,
82
89
  { error: ensureLoggableError(error) },
83
90
  `Unable to install dependencies of the service ${bold(service.id)}.`
84
91
  )
85
92
  }
86
93
  }
94
+
95
+ return true
87
96
  }
88
97
 
89
98
  async function updateDependencies (logger, latest, availableVersions, path, target, force) {
@@ -91,7 +100,7 @@ async function updateDependencies (logger, latest, availableVersions, path, targ
91
100
  const packageJsonPath = resolve(path, 'package.json')
92
101
 
93
102
  if (!existsSync(packageJsonPath)) {
94
- return
103
+ return false
95
104
  }
96
105
 
97
106
  let updated = false
@@ -109,8 +118,11 @@ async function updateDependencies (logger, latest, availableVersions, path, targ
109
118
  let newRange
110
119
  if (specifier !== '^' && specifier !== '~') {
111
120
  if (!force) {
112
- logger.fatal(
113
- `Dependency ${bold(pkg)} of ${target}${sectionLabel} requires a non-updatable range ${bold(range)}. Try again with ${bold('-f/--force')} to update to the latest version.`
121
+ return logFatalError(
122
+ logger,
123
+ `Dependency ${bold(pkg)} of ${target}${sectionLabel} requires a non-updatable range ${bold(
124
+ range
125
+ )}. Try again with ${bold('-f/--force')} to update to the latest version.`
114
126
  )
115
127
  } else {
116
128
  specifier = ''
@@ -141,14 +153,32 @@ async function updateDependencies (logger, latest, availableVersions, path, targ
141
153
  if (updated) {
142
154
  await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2))
143
155
  }
156
+
157
+ return true
144
158
  }
145
159
 
146
160
  export async function buildCommand (logger, args) {
147
- const { positionals } = parseArgs(args, {}, false)
148
- /* c8 ignore next */
161
+ const {
162
+ values: { config },
163
+ positionals
164
+ } = parseArgs(
165
+ args,
166
+ {
167
+ config: {
168
+ type: 'string',
169
+ short: 'c'
170
+ }
171
+ },
172
+ false
173
+ )
149
174
  const root = getRoot(positionals)
150
175
 
151
- const configurationFile = await findConfigurationFile(logger, root)
176
+ const configurationFile = await findConfigurationFile(logger, root, config)
177
+
178
+ /* c8 ignore next 3 - Hard to test */
179
+ if (!configurationFile) {
180
+ return
181
+ }
152
182
 
153
183
  const runtime = await buildRuntime(logger, configurationFile)
154
184
  // Gather informations for all services before starting
@@ -157,7 +187,6 @@ export async function buildCommand (logger, args) {
157
187
  for (const { id } of services) {
158
188
  const currentLogger = logger.child({ name: id })
159
189
  currentLogger.debug(`Building service ${bold(id)} ...`)
160
- overrideFatal(currentLogger)
161
190
 
162
191
  try {
163
192
  await runtime.buildService(id)
@@ -182,11 +211,15 @@ export async function buildCommand (logger, args) {
182
211
 
183
212
  export async function installCommand (logger, args) {
184
213
  const {
185
- values: { production, 'package-manager': packageManager },
214
+ values: { config, production, 'package-manager': packageManager },
186
215
  positionals
187
216
  } = parseArgs(
188
217
  args,
189
218
  {
219
+ config: {
220
+ type: 'string',
221
+ short: 'c'
222
+ },
190
223
  production: {
191
224
  type: 'boolean',
192
225
  short: 'p',
@@ -200,21 +233,32 @@ export async function installCommand (logger, args) {
200
233
  false
201
234
  )
202
235
 
203
- /* c8 ignore next */
204
236
  const root = getRoot(positionals)
205
- const configurationFile = await findConfigurationFile(logger, root)
237
+ const configurationFile = await findConfigurationFile(logger, root, config)
206
238
 
207
- await installDependencies(logger, root, configurationFile, production, packageManager)
208
- logger.done('All services have been resolved.')
239
+ /* c8 ignore next 3 - Hard to test */
240
+ if (!configurationFile) {
241
+ return
242
+ }
243
+
244
+ const installed = await installDependencies(logger, root, configurationFile, production, packageManager)
245
+
246
+ if (installed) {
247
+ logger.done('All services have been resolved.')
248
+ }
209
249
  }
210
250
 
211
251
  export async function updateCommand (logger, args) {
212
252
  const {
213
253
  positionals,
214
- values: { force }
254
+ values: { config, force }
215
255
  } = parseArgs(
216
256
  args,
217
257
  {
258
+ config: {
259
+ type: 'string',
260
+ short: 'c'
261
+ },
218
262
  force: {
219
263
  type: 'boolean',
220
264
  short: 'f'
@@ -223,16 +267,22 @@ export async function updateCommand (logger, args) {
223
267
  false
224
268
  )
225
269
 
226
- /* c8 ignore next */
227
270
  const root = getRoot(positionals)
228
- const configurationFile = await findConfigurationFile(logger, root)
271
+ const configurationFile = await findConfigurationFile(logger, root, config)
272
+
273
+ /* c8 ignore next 3 - Hard to test */
274
+ if (!configurationFile) {
275
+ return
276
+ }
277
+
229
278
  const { services } = await loadConfigurationFile(logger, configurationFile)
230
279
 
231
280
  // First of all, get all version from NPM for the runtime
232
281
  const selfInfoResponse = await fetch('https://registry.npmjs.org/@platformatic/runtime')
233
282
 
234
283
  if (!selfInfoResponse.ok) {
235
- logger.fatal(
284
+ return logFatalError(
285
+ logger,
236
286
  { response: selfInfoResponse.status, body: await selfInfoResponse.text() },
237
287
  'Unable to fetch version information.'
238
288
  )
@@ -266,6 +316,12 @@ export const help = {
266
316
  name: 'root',
267
317
  description: 'The directory containing the application (the default is the current directory)'
268
318
  }
319
+ ],
320
+ options: [
321
+ {
322
+ usage: '-c, --config <config>',
323
+ description: 'Name of the configuration file to use (the default is to autodetect it)'
324
+ }
269
325
  ]
270
326
  },
271
327
  install: {
@@ -278,6 +334,10 @@ export const help = {
278
334
  }
279
335
  ],
280
336
  options: [
337
+ {
338
+ usage: '-c, --config <config>',
339
+ description: 'Name of the configuration file to use (the default is to autodetect it)'
340
+ },
281
341
  {
282
342
  usage: '-p --production',
283
343
  description: 'Only install production dependencies'
@@ -298,6 +358,10 @@ export const help = {
298
358
  }
299
359
  ],
300
360
  options: [
361
+ {
362
+ usage: '-c, --config <config>',
363
+ description: 'Name of the configuration file to use (the default is watt.json)'
364
+ },
301
365
  {
302
366
  usage: '-f --force',
303
367
  description: 'Force dependencies update even if it violates the package.json version range'
@@ -0,0 +1,110 @@
1
+ import { createApplication, getUsername, getVersion, say } from 'create-platformatic'
2
+ import { resolve } from 'node:path'
3
+ import { getPackageManager, parseArgs } from '../utils.js'
4
+ import { installDependencies } from './build.js'
5
+
6
+ export async function createCommand (logger, args) {
7
+ let {
8
+ values: {
9
+ config,
10
+ marketplace,
11
+ 'package-manager': packageManager,
12
+ 'skip-dependencies': skipDependencies,
13
+ module: modules
14
+ }
15
+ } = parseArgs(
16
+ args,
17
+ {
18
+ config: {
19
+ type: 'string',
20
+ short: 'c',
21
+ default: 'watt.json'
22
+ },
23
+ marketplace: {
24
+ type: 'string',
25
+ short: 'm',
26
+ default: 'https://marketplace.platformatic.dev'
27
+ },
28
+ 'package-manager': {
29
+ type: 'string',
30
+ short: 'P'
31
+ },
32
+ 'skip-dependencies': {
33
+ type: 'boolean',
34
+ short: 's',
35
+ default: false
36
+ },
37
+ module: {
38
+ short: 'M',
39
+ type: 'string',
40
+ multiple: true,
41
+ default: []
42
+ }
43
+ },
44
+ false
45
+ )
46
+
47
+ if (!packageManager) {
48
+ packageManager = getPackageManager(process.cwd())
49
+ }
50
+
51
+ const username = await getUsername()
52
+ const version = await getVersion()
53
+ /* c8 ignore next 2 - Ignoring else branches */
54
+ const greeting = username ? `Hello ${username},` : 'Hello,'
55
+ await say(`${greeting} welcome to ${version ? `Watt ${version}!` : 'Watt!'}`)
56
+
57
+ await createApplication(
58
+ logger,
59
+ packageManager,
60
+ modules.map(m => m.split(/\s*,\s*/).map(m => m.trim())).flat(),
61
+ marketplace,
62
+ skipDependencies
63
+ ? false
64
+ : (root, configurationFile, packageManager) => {
65
+ return installDependencies(logger, root, resolve(root, configurationFile), false, packageManager)
66
+ },
67
+ {
68
+ runtimeConfig: config,
69
+ servicesFolder: 'web'
70
+ }
71
+ )
72
+ }
73
+
74
+ const createHelp = {
75
+ description: 'Creates a new Watt project',
76
+ options: [
77
+ {
78
+ usage: '-c, --config <config>',
79
+ description: 'Name of the configuration file to use (the default is watt.json)'
80
+ },
81
+ {
82
+ usage: '-m, --marketplace <url>',
83
+ description: 'Platformatic Marketplace host (the default is https://marketplace.platformatic.dev)'
84
+ },
85
+ {
86
+ usage: '-s, --skip-dependencies',
87
+ description: 'Do not install dependencies after creating the files'
88
+ },
89
+ {
90
+ usage: '-P, --package-manager <executable>',
91
+ description: 'Use an alternative package manager (the default is to autodetect it)'
92
+ },
93
+ {
94
+ usage: '-M, --module <name>',
95
+ description:
96
+ 'An additional module (or a comma separated list of modules) to use as service generator (it can be used multiple times)'
97
+ }
98
+ ]
99
+ }
100
+
101
+ export const help = {
102
+ init: {
103
+ usage: 'init',
104
+ ...createHelp
105
+ },
106
+ create: {
107
+ usage: 'create',
108
+ ...createHelp
109
+ }
110
+ }
@@ -4,14 +4,31 @@ import { ensureLoggableError } from '@platformatic/utils'
4
4
  import { bold } from 'colorette'
5
5
  import { spawn } from 'node:child_process'
6
6
  import { watch } from 'node:fs/promises'
7
- import { findConfigurationFile, getMatchingRuntime, getRoot, parseArgs } from '../utils.js'
7
+ import { findConfigurationFile, getMatchingRuntime, getRoot, logFatalError, parseArgs } from '../utils.js'
8
8
 
9
9
  export async function devCommand (logger, args) {
10
- const { positionals } = parseArgs(args, {}, false)
11
- /* c8 ignore next */
10
+ const {
11
+ values: { config },
12
+ positionals
13
+ } = parseArgs(
14
+ args,
15
+ {
16
+ config: {
17
+ type: 'string',
18
+ short: 'c'
19
+ }
20
+ },
21
+ false
22
+ )
12
23
  const root = getRoot(positionals)
13
24
 
14
- const configurationFile = await findConfigurationFile(logger, root)
25
+ const configurationFile = await findConfigurationFile(logger, root, config)
26
+
27
+ /* c8 ignore next 3 - Hard to test */
28
+ if (!configurationFile) {
29
+ return
30
+ }
31
+
15
32
  let runtime = await pltStartCommand(['-c', configurationFile], true, true)
16
33
 
17
34
  // Add a watcher on the configurationFile so that we can eventually restart the runtime
@@ -22,30 +39,38 @@ export async function devCommand (logger, args) {
22
39
  await runtime.close()
23
40
  runtime = await pltStartCommand(['-c', configurationFile], true, true)
24
41
  }
25
- /* c8 ignore next */
42
+ /* c8 ignore next - Mistakenly reported as uncovered by C8 */
26
43
  }
27
44
 
28
45
  export async function startCommand (logger, args) {
29
- const { positionals, values } = parseArgs(
46
+ const {
47
+ positionals,
48
+ values: { inspect, config }
49
+ } = parseArgs(
30
50
  args,
31
51
  {
32
- inspect: {
33
- type: 'boolean',
34
- short: 'i'
35
- },
36
52
  config: {
37
53
  type: 'string',
38
54
  short: 'c'
55
+ },
56
+ inspect: {
57
+ type: 'boolean',
58
+ short: 'i'
39
59
  }
40
60
  },
41
61
  false
42
62
  )
43
- /* c8 ignore next */
63
+
44
64
  const root = getRoot(positionals)
65
+ const configurationFile = await findConfigurationFile(logger, root, config)
66
+
67
+ /* c8 ignore next 3 - Hard to test */
68
+ if (!configurationFile) {
69
+ return
70
+ }
45
71
 
46
- const configurationFile = await findConfigurationFile(logger, root, values.config)
47
72
  const cmd = ['--production', '-c', configurationFile]
48
- if (values.inspect) {
73
+ if (inspect) {
49
74
  cmd.push('--inspect')
50
75
  }
51
76
  await pltStartCommand(cmd, true)
@@ -64,10 +89,10 @@ export async function stopCommand (logger, args) {
64
89
  logger.done(`Runtime ${bold(runtime.packageName)} have been stopped.`)
65
90
  } catch (error) {
66
91
  if (error.code === 'PLT_CTR_RUNTIME_NOT_FOUND') {
67
- logger.fatal('Cannot find a matching runtime.')
68
- /* c8 ignore next 3 */
92
+ return logFatalError(logger, 'Cannot find a matching runtime.')
93
+ /* c8 ignore next 3 - Hard to test */
69
94
  } else {
70
- logger.fatal({ error: ensureLoggableError(error) }, `Cannot stop the runtime: ${error.message}`)
95
+ return logFatalError(logger, { error: ensureLoggableError(error) }, `Cannot stop the runtime: ${error.message}`)
71
96
  }
72
97
  }
73
98
  }
@@ -85,10 +110,14 @@ export async function restartCommand (logger, args) {
85
110
  logger.done(`Runtime ${bold(runtime.packageName)} has been restarted.`)
86
111
  } catch (error) {
87
112
  if (error.code === 'PLT_CTR_RUNTIME_NOT_FOUND') {
88
- logger.fatal('Cannot find a matching runtime.')
89
- /* c8 ignore next 3 */
113
+ return logFatalError(logger, 'Cannot find a matching runtime.')
114
+ /* c8 ignore next 7 - Hard to test */
90
115
  } else {
91
- logger.fatal({ error: ensureLoggableError(error) }, `Cannot restart the runtime: ${error.message}`)
116
+ return logFatalError(
117
+ logger,
118
+ { error: ensureLoggableError(error) },
119
+ `Cannot restart the runtime: ${error.message}`
120
+ )
92
121
  }
93
122
  }
94
123
  }
@@ -119,10 +148,10 @@ export async function reloadCommand (logger, args) {
119
148
  logger.done(`Runtime ${bold(runtime.packageName)} have been reloaded and it is now running as PID ${child.pid}.`)
120
149
  } catch (error) {
121
150
  if (error.code === 'PLT_CTR_RUNTIME_NOT_FOUND') {
122
- logger.fatal('Cannot find a matching runtime.')
123
- /* c8 ignore next 3 */
151
+ return logFatalError(logger, 'Cannot find a matching runtime.')
152
+ /* c8 ignore next 3 - Hard to test */
124
153
  } else {
125
- logger.fatal({ error: ensureLoggableError(error) }, `Cannot reload the runtime: ${error.message}`)
154
+ return logFatalError(logger, { error: ensureLoggableError(error) }, `Cannot reload the runtime: ${error.message}`)
126
155
  }
127
156
  }
128
157
  }
@@ -136,6 +165,12 @@ export const help = {
136
165
  name: 'root',
137
166
  description: 'The directory containing the application (the default is the current directory)'
138
167
  }
168
+ ],
169
+ options: [
170
+ {
171
+ usage: '-c, --config <config>',
172
+ description: 'Name of the configuration file to use (the default to autodetect it)'
173
+ }
139
174
  ]
140
175
  },
141
176
  start: {
@@ -148,6 +183,10 @@ export const help = {
148
183
  }
149
184
  ],
150
185
  options: [
186
+ {
187
+ usage: '-c, --config <config>',
188
+ description: 'Name of the configuration file to use (the default to autodetect it)'
189
+ },
151
190
  {
152
191
  usage: '-i --inspect',
153
192
  description: 'Enables the inspector for each service'