@platformatic/control 2.0.0-alpha.2 → 2.0.0-alpha.21

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/control.js CHANGED
@@ -17,7 +17,7 @@ const streamRuntimeLogsCommand = require('./lib/logs')
17
17
 
18
18
  const help = helpMe({
19
19
  dir: join(__dirname, 'help'),
20
- ext: '.txt'
20
+ ext: '.txt',
21
21
  })
22
22
 
23
23
  const program = commist({ maxDistance: 2 })
@@ -42,9 +42,9 @@ async function runControl (argv) {
42
42
  const args = parseArgs({
43
43
  args: argv,
44
44
  options: {
45
- version: { type: 'boolean', short: 'v' }
45
+ version: { type: 'boolean', short: 'v' },
46
46
  },
47
- strict: false
47
+ strict: false,
48
48
  }).values
49
49
 
50
50
  if (args.version && argv[0] !== 'inject') {
@@ -79,5 +79,5 @@ module.exports = {
79
79
  stopRuntimeCommand,
80
80
  restartRuntimeCommand,
81
81
  injectRuntimeCommand,
82
- streamRuntimeLogsCommand
82
+ streamRuntimeLogsCommand,
83
83
  }
@@ -0,0 +1,3 @@
1
+ 'use strict'
2
+
3
+ module.exports = require('neostandard')({})
package/index.js CHANGED
@@ -3,5 +3,5 @@
3
3
  const RuntimeApiClient = require('./lib/runtime-api-client')
4
4
 
5
5
  module.exports = {
6
- RuntimeApiClient
6
+ RuntimeApiClient,
7
7
  }
package/lib/config.js CHANGED
@@ -9,9 +9,9 @@ async function getRuntimeConfigCommand (argv) {
9
9
  options: {
10
10
  pid: { type: 'string', short: 'p' },
11
11
  name: { type: 'string', short: 'n' },
12
- service: { type: 'string', short: 's' }
12
+ service: { type: 'string', short: 's' },
13
13
  },
14
- strict: false
14
+ strict: false,
15
15
  }).values
16
16
 
17
17
  const client = new RuntimeApiClient()
package/lib/env.js CHANGED
@@ -8,9 +8,9 @@ async function getRuntimeEnvCommand (argv) {
8
8
  args: argv,
9
9
  options: {
10
10
  pid: { type: 'string', short: 'p' },
11
- name: { type: 'string', short: 'n' }
11
+ name: { type: 'string', short: 'n' },
12
12
  },
13
- strict: false
13
+ strict: false,
14
14
  }).values
15
15
 
16
16
  const client = new RuntimeApiClient()
package/lib/errors.js CHANGED
@@ -6,6 +6,7 @@ const ERROR_PREFIX = 'PLT_CTR'
6
6
 
7
7
  module.exports = {
8
8
  RuntimeNotFound: createError(`${ERROR_PREFIX}_RUNTIME_NOT_FOUND`, 'Runtime not found.'),
9
+ ServiceNotFound: createError(`${ERROR_PREFIX}_SERVICE_NOT_FOUND`, 'Service not found.'),
9
10
  MissingRuntimeIdentifier: createError(`${ERROR_PREFIX}_MISSING_RUNTIME_IDENTIFIER`, 'Runtime name or PID is required.'),
10
11
  MissingRequestURL: createError(`${ERROR_PREFIX}_MISSING_REQUEST_URL`, 'Request URL is required.'),
11
12
  FailedToGetRuntimeMetadata: createError(`${ERROR_PREFIX}_FAILED_TO_GET_RUNTIME_METADATA`, 'Failed to get runtime metadata %s.'),
@@ -17,8 +18,9 @@ module.exports = {
17
18
  FailedToStopRuntime: createError(`${ERROR_PREFIX}_FAILED_TO_STOP_RUNTIME`, 'Failed to stop the runtime %s.'),
18
19
  FailedToReloadRuntime: createError(`${ERROR_PREFIX}_FAILED_TO_RELOAD_RUNTIME`, 'Failed to reload the runtime %s.'),
19
20
  FailedToGetRuntimeConfig: createError(`${ERROR_PREFIX}_FAILED_TO_GET_RUNTIME_CONFIG`, 'Failed to get runtime config %s.'),
21
+ FailedToGetRuntimeServiceEnv: createError(`${ERROR_PREFIX}_FAILED_TO_GET_RUNTIME_SERVICE_ENV`, 'Failed to get runtime service environment variables %s.'),
20
22
  FailedToGetRuntimeServiceConfig: createError(`${ERROR_PREFIX}_FAILED_TO_GET_RUNTIME_SERVICE_CONFIG`, 'Failed to get runtime service config %s.'),
21
23
  FailedToGetRuntimeHistoryLogs: createError(`${ERROR_PREFIX}_FAILED_TO_GET_HISTORY_LOGS`, 'Failed to get history logs %s.'),
22
24
  FailedToGetRuntimeAllLogs: createError(`${ERROR_PREFIX}_FAILED_TO_GET_RUNTIME_ALL_LOGS`, 'Failed to get runtime all logs %s.'),
23
- FailedToGetRuntimeLogIndexes: createError(`${ERROR_PREFIX}_FAILED_TO_GET_HISTORY_LOGS_COUNT`, 'Failed to get history logs count %s.')
25
+ FailedToGetRuntimeLogIndexes: createError(`${ERROR_PREFIX}_FAILED_TO_GET_HISTORY_LOGS_COUNT`, 'Failed to get history logs count %s.'),
24
26
  }
package/lib/inject.js CHANGED
@@ -17,9 +17,9 @@ async function injectRuntimeCommand (argv) {
17
17
  data: { type: 'string', short: 'd' },
18
18
  include: { type: 'boolean', short: 'i', default: false },
19
19
  verbose: { type: 'boolean', short: 'v', default: false },
20
- output: { type: 'string', short: 'o' }
20
+ output: { type: 'string', short: 'o' },
21
21
  },
22
- strict: false
22
+ strict: false,
23
23
  })
24
24
 
25
25
  const client = new RuntimeApiClient()
package/lib/logs.js CHANGED
@@ -10,7 +10,7 @@ const pinoLogLevels = {
10
10
  warn: 40,
11
11
  info: 30,
12
12
  debug: 20,
13
- trace: 10
13
+ trace: 10,
14
14
  }
15
15
 
16
16
  async function streamRuntimeLogsCommand (argv) {
@@ -21,9 +21,9 @@ async function streamRuntimeLogsCommand (argv) {
21
21
  name: { type: 'string', short: 'n' },
22
22
  level: { type: 'string', short: 'l', default: 'info' },
23
23
  pretty: { type: 'string', default: 'true' },
24
- service: { type: 'string', short: 's' }
24
+ service: { type: 'string', short: 's' },
25
25
  },
26
- strict: false
26
+ strict: false,
27
27
  }).values
28
28
 
29
29
  const client = new RuntimeApiClient()
package/lib/ps.js CHANGED
@@ -6,29 +6,29 @@ const RuntimeApiClient = require('./runtime-api-client')
6
6
  const tableColumns = [
7
7
  {
8
8
  value: 'pid',
9
- alias: 'PID'
9
+ alias: 'PID',
10
10
  },
11
11
  {
12
12
  value: 'packageName',
13
- alias: 'NAME'
13
+ alias: 'NAME',
14
14
  },
15
15
  {
16
16
  value: 'platformaticVersion',
17
- alias: 'PLT'
17
+ alias: 'PLT',
18
18
  },
19
19
  {
20
20
  value: 'uptimeSeconds',
21
21
  alias: 'TIME',
22
- formatter: formatRuntimeTime
22
+ formatter: formatRuntimeTime,
23
23
  },
24
24
  {
25
25
  value: 'url',
26
- alias: 'URL'
26
+ alias: 'URL',
27
27
  },
28
28
  {
29
29
  value: 'projectDir',
30
- alias: 'PWD'
31
- }
30
+ alias: 'PWD',
31
+ },
32
32
  ]
33
33
 
34
34
  function formatRuntimeTime (timeSeconds) {
@@ -56,9 +56,9 @@ const tableConfig = {
56
56
  border: getBorderCharacters('void'),
57
57
  columnDefault: {
58
58
  paddingLeft: 0,
59
- paddingRight: 1
59
+ paddingRight: 1,
60
60
  },
61
- drawHorizontalLine: () => false
61
+ drawHorizontalLine: () => false,
62
62
  }
63
63
 
64
64
  async function printRuntimes (runtimes) {
package/lib/reload.js CHANGED
@@ -16,8 +16,8 @@ async function reloadRuntimeCommand (argv) {
16
16
  const client = new RuntimeApiClient()
17
17
  const runtime = await client.getMatchingRuntime(args)
18
18
 
19
- await client.reloadRuntime(runtime.pid)
20
- console.log(`Reloaded runtime "${runtime.packageName}".`)
19
+ const child = await client.reloadRuntime(runtime.pid)
20
+ console.log(`Reloaded runtime "${runtime.packageName}". The new PID is ${child.pid}.`)
21
21
 
22
22
  await client.close()
23
23
  }
package/lib/restart.js CHANGED
@@ -8,9 +8,9 @@ async function restartRuntimeCommand (argv) {
8
8
  args: argv,
9
9
  options: {
10
10
  pid: { type: 'string', short: 'p' },
11
- name: { type: 'string', short: 'n' }
11
+ name: { type: 'string', short: 'n' },
12
12
  },
13
- strict: false
13
+ strict: false,
14
14
  }).values
15
15
 
16
16
  const client = new RuntimeApiClient()
@@ -3,11 +3,12 @@
3
3
  const { tmpdir, platform, EOL } = require('node:os')
4
4
  const { join } = require('node:path')
5
5
  const { exec, spawn } = require('node:child_process')
6
- const { readdir, rm, access } = require('node:fs/promises')
6
+ const { readdir, access } = require('node:fs/promises')
7
7
  const { Readable } = require('node:stream')
8
8
  const { Client } = require('undici')
9
9
  const WebSocket = require('ws')
10
10
  const errors = require('./errors.js')
11
+ const { safeRemove } = require('@platformatic/utils')
11
12
 
12
13
  const PLATFORMATIC_TMP_DIR = join(tmpdir(), 'platformatic', 'runtimes')
13
14
  const PLATFORMATIC_PIPE_PREFIX = '\\\\.\\pipe\\platformatic-'
@@ -34,12 +35,10 @@ class RuntimeApiClient {
34
35
  }
35
36
 
36
37
  async getRuntimes () {
37
- const runtimePIDs = platform() === 'win32'
38
- ? await this.#getWindowsRuntimePIDs()
39
- : await this.#getUnixRuntimePIDs()
38
+ const runtimePIDs = platform() === 'win32' ? await this.#getWindowsRuntimePIDs() : await this.#getUnixRuntimePIDs()
40
39
 
41
40
  const getMetadataRequests = await Promise.allSettled(
42
- runtimePIDs.map(async (runtimePID) => {
41
+ runtimePIDs.map(async runtimePID => {
43
42
  return this.getRuntimeMetadata(runtimePID)
44
43
  })
45
44
  )
@@ -92,38 +91,49 @@ class RuntimeApiClient {
92
91
  return runtimeServices
93
92
  }
94
93
 
95
- async getRuntimeServiceConfig (pid, serviceId) {
94
+ async getRuntimeConfig (pid) {
96
95
  const client = this.#getUndiciClient(pid)
97
96
 
98
97
  const { statusCode, body } = await client.request({
99
- path: `/api/v1/services/${serviceId}/config`,
98
+ path: '/api/v1/config',
100
99
  method: 'GET'
101
100
  })
102
101
 
103
102
  if (statusCode !== 200) {
104
103
  const error = await body.text()
105
- throw new errors.FailedToGetRuntimeServiceConfig(error)
104
+ throw new errors.FailedToGetRuntimeConfig(error)
106
105
  }
107
106
 
108
- const serviceConfig = await body.json()
109
- return serviceConfig
107
+ const runtimeConfig = await body.json()
108
+ return runtimeConfig
110
109
  }
111
110
 
112
- async getRuntimeConfig (pid) {
111
+ async getRuntimeServiceConfig (pid, serviceId) {
113
112
  const client = this.#getUndiciClient(pid)
114
113
 
115
114
  const { statusCode, body } = await client.request({
116
- path: '/api/v1/config',
115
+ path: `/api/v1/services/${serviceId}/config`,
117
116
  method: 'GET'
118
117
  })
119
118
 
120
119
  if (statusCode !== 200) {
121
120
  const error = await body.text()
122
- throw new errors.FailedToGetRuntimeConfig(error)
121
+ let jsonError
122
+ try {
123
+ jsonError = JSON.parse(error)
124
+ } catch {
125
+ // No-op
126
+ }
127
+
128
+ if (jsonError?.code === 'PLT_RUNTIME_SERVICE_NOT_FOUND') {
129
+ throw new errors.ServiceNotFound(error)
130
+ }
131
+
132
+ throw new errors.FailedToGetRuntimeServiceConfig(error)
123
133
  }
124
134
 
125
- const runtimeConfig = await body.json()
126
- return runtimeConfig
135
+ const serviceConfig = await body.json()
136
+ return serviceConfig
127
137
  }
128
138
 
129
139
  async getRuntimeEnv (pid) {
@@ -143,21 +153,56 @@ class RuntimeApiClient {
143
153
  return runtimeEnv
144
154
  }
145
155
 
146
- async restartRuntime (pid, options = {}) {
156
+ async getRuntimeServiceEnv (pid, serviceId) {
157
+ const client = this.#getUndiciClient(pid)
158
+
159
+ const { statusCode, body } = await client.request({
160
+ path: `/api/v1/services/${serviceId}/env`,
161
+ method: 'GET'
162
+ })
163
+
164
+ if (statusCode !== 200) {
165
+ const error = await body.text()
166
+ let jsonError
167
+ try {
168
+ jsonError = JSON.parse(error)
169
+ } catch {
170
+ // No-op
171
+ }
172
+
173
+ if (jsonError?.code === 'PLT_RUNTIME_SERVICE_NOT_FOUND') {
174
+ throw new errors.ServiceNotFound(error)
175
+ }
176
+
177
+ throw new errors.FailedToGetRuntimeServiceEnv(error)
178
+ }
179
+
180
+ const serviceConfig = await body.json()
181
+ return serviceConfig
182
+ }
183
+
184
+ async reloadRuntime (pid, options = {}) {
147
185
  const runtime = await this.getMatchingRuntime({ pid })
148
186
 
149
187
  await this.stopRuntime(pid)
150
188
 
151
189
  const [startCommand, ...startArgs] = runtime.argv
152
- const child = spawn(startCommand, startArgs, { cwd: runtime.cwd, ...options })
190
+ const child = spawn(startCommand, startArgs, { cwd: runtime.cwd, ...options, stdio: 'ignore', detached: true })
191
+
192
+ await new Promise((resolve, reject) => {
193
+ child.on('spawn', resolve)
194
+ child.on('error', reject)
195
+ })
196
+
197
+ child.unref()
153
198
  return child
154
199
  }
155
200
 
156
- async reloadRuntime (pid) {
201
+ async restartRuntime (pid) {
157
202
  const client = this.#getUndiciClient(pid)
158
203
 
159
204
  const { statusCode, body } = await client.request({
160
- path: '/api/v1/reload',
205
+ path: '/api/v1/restart',
161
206
  method: 'POST'
162
207
  })
163
208
 
@@ -287,10 +332,13 @@ class RuntimeApiClient {
287
332
  let undiciClient = this.#undiciClients.get(pid)
288
333
  if (!undiciClient) {
289
334
  const socketPath = this.#getSocketPathFromPid(pid)
290
- undiciClient = new Client({
291
- hostname: 'localhost',
292
- protocol: 'http:'
293
- }, { socketPath })
335
+ undiciClient = new Client(
336
+ {
337
+ hostname: 'localhost',
338
+ protocol: 'http:'
339
+ },
340
+ { socketPath }
341
+ )
294
342
 
295
343
  this.#undiciClients.set(pid, undiciClient)
296
344
  }
@@ -310,10 +358,15 @@ class RuntimeApiClient {
310
358
  } catch {
311
359
  return []
312
360
  }
313
- const runtimeDirs = await readdir(PLATFORMATIC_TMP_DIR)
361
+
362
+ const runtimeDirs = await readdir(PLATFORMATIC_TMP_DIR, { withFileTypes: true })
314
363
  const runtimePIDs = []
315
- for (const runtimeDirName of runtimeDirs) {
316
- runtimePIDs.push(parseInt(runtimeDirName))
364
+
365
+ for (const runtimeDir of runtimeDirs) {
366
+ // Only consider directory that can be a PID
367
+ if (runtimeDir.isDirectory() && runtimeDir.name.match(/^\d+$/)) {
368
+ runtimePIDs.push(parseInt(runtimeDir.name))
369
+ }
317
370
  }
318
371
  return runtimePIDs
319
372
  }
@@ -332,24 +385,20 @@ class RuntimeApiClient {
332
385
 
333
386
  async #getWindowsNamedPipes () {
334
387
  return new Promise((resolve, reject) => {
335
- exec(
336
- '[System.IO.Directory]::GetFiles("\\\\.\\pipe\\")',
337
- { shell: 'powershell.exe' },
338
- (err, stdout) => {
339
- if (err) {
340
- reject(err)
341
- return
342
- }
343
- const namedPipes = stdout.split(EOL)
344
- resolve(namedPipes)
388
+ exec('[System.IO.Directory]::GetFiles("\\\\.\\pipe\\")', { shell: 'powershell.exe' }, (err, stdout) => {
389
+ if (err) {
390
+ reject(err)
391
+ return
345
392
  }
346
- )
393
+ const namedPipes = stdout.split(EOL)
394
+ resolve(namedPipes)
395
+ })
347
396
  })
348
397
  }
349
398
 
350
399
  async #removeRuntimeTmpDir (pid) {
351
400
  const runtimeDir = join(PLATFORMATIC_TMP_DIR, pid.toString())
352
- await rm(runtimeDir, { recursive: true, force: true })
401
+ await safeRemove(runtimeDir)
353
402
  }
354
403
  }
355
404
 
@@ -358,13 +407,13 @@ class WebSocketStream extends Readable {
358
407
  super()
359
408
  this.ws = new WebSocket(url)
360
409
 
361
- this.ws.on('message', (data) => {
410
+ this.ws.on('message', data => {
362
411
  this.push(data)
363
412
  })
364
413
  this.ws.on('close', () => {
365
414
  this.push(null)
366
415
  })
367
- this.ws.on('error', (err) => {
416
+ this.ws.on('error', err => {
368
417
  this.emit('error', new errors.FailedToStreamRuntimeLogs(err.message))
369
418
  })
370
419
  this.on('close', () => {
package/lib/services.js CHANGED
@@ -7,28 +7,28 @@ const RuntimeApiClient = require('./runtime-api-client')
7
7
  const tableColumns = [
8
8
  {
9
9
  value: 'id',
10
- alias: 'NAME'
10
+ alias: 'NAME',
11
11
  },
12
12
  {
13
13
  value: 'type',
14
- alias: 'TYPE'
14
+ alias: 'TYPE',
15
15
  },
16
16
  {
17
17
  value: 'entrypoint',
18
18
  alias: 'ENTRYPOINT',
19
19
  formatter: (entrypoint) => {
20
20
  return entrypoint ? 'yes' : 'no'
21
- }
22
- }
21
+ },
22
+ },
23
23
  ]
24
24
 
25
25
  const tableConfig = {
26
26
  border: getBorderCharacters('void'),
27
27
  columnDefault: {
28
28
  paddingLeft: 0,
29
- paddingRight: 1
29
+ paddingRight: 1,
30
30
  },
31
- drawHorizontalLine: () => false
31
+ drawHorizontalLine: () => false,
32
32
  }
33
33
 
34
34
  async function printRuntimeServices (services) {
@@ -56,9 +56,9 @@ async function getRuntimeServicesCommand (argv) {
56
56
  args: argv,
57
57
  options: {
58
58
  pid: { type: 'string', short: 'p' },
59
- name: { type: 'string', short: 'n' }
59
+ name: { type: 'string', short: 'n' },
60
60
  },
61
- strict: false
61
+ strict: false,
62
62
  }).values
63
63
 
64
64
  const client = new RuntimeApiClient()
package/lib/stop.js CHANGED
@@ -8,9 +8,9 @@ async function stopRuntimeCommand (argv) {
8
8
  args: argv,
9
9
  options: {
10
10
  pid: { type: 'string', short: 'p' },
11
- name: { type: 'string', short: 'n' }
11
+ name: { type: 'string', short: 'n' },
12
12
  },
13
- strict: false
13
+ strict: false,
14
14
  }).values
15
15
 
16
16
  const client = new RuntimeApiClient()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/control",
3
- "version": "2.0.0-alpha.2",
3
+ "version": "2.0.0-alpha.21",
4
4
  "description": "Platformatic Control",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -17,29 +17,31 @@
17
17
  },
18
18
  "homepage": "https://github.com/platformatic/platformatic#readme",
19
19
  "devDependencies": {
20
- "borp": "^0.16.0",
20
+ "borp": "^0.17.0",
21
21
  "desm": "^1.3.1",
22
+ "eslint": "9",
22
23
  "execa": "^8.0.1",
23
- "snazzy": "^9.0.0",
24
+ "neostandard": "^0.11.1",
24
25
  "split2": "^4.2.0",
25
- "standard": "^17.1.0",
26
26
  "tsd": "^0.31.0",
27
- "@platformatic/runtime": "2.0.0-alpha.2"
27
+ "typescript": "^5.5.4",
28
+ "@platformatic/service": "2.0.0-alpha.21",
29
+ "@platformatic/runtime": "2.0.0-alpha.21"
28
30
  },
29
31
  "dependencies": {
30
- "@fastify/error": "^3.4.1",
32
+ "@fastify/error": "^4.0.0",
31
33
  "commist": "^3.2.0",
32
34
  "help-me": "^5.0.0",
33
- "pino": "^8.19.0",
35
+ "pino": "^9.0.0",
34
36
  "pino-pretty": "^11.0.0",
35
37
  "table": "^6.8.1",
36
38
  "undici": "^6.9.0",
37
- "ws": "^8.16.0"
39
+ "ws": "^8.16.0",
40
+ "@platformatic/utils": "2.0.0-alpha.21"
38
41
  },
39
42
  "scripts": {
40
43
  "test": "pnpm run lint && pnpm run unit",
41
- "unit": "borp --concurrency=1 --timeout 60000",
42
- "build": "node lib/schema.js | json2ts > config.d.ts",
43
- "lint": "standard | snazzy"
44
+ "unit": "borp --concurrency=1 --timeout=180000",
45
+ "lint": "eslint"
44
46
  }
45
47
  }