wattpm 2.31.0 → 2.33.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
@@ -6,8 +6,9 @@ import { helpCommand } from './lib/commands/help.js'
6
6
  import { initCommand } from './lib/commands/init.js'
7
7
  import { injectCommand } from './lib/commands/inject.js'
8
8
  import { logsCommand } from './lib/commands/logs.js'
9
- import { metricsCommand } from './lib/commands/metrics.js'
10
9
  import { configCommand, envCommand, psCommand, servicesCommand } from './lib/commands/management.js'
10
+ import { metricsCommand } from './lib/commands/metrics.js'
11
+ import { patchConfigCommand } from './lib/commands/patch-config.js'
11
12
  import { version } from './lib/schema.js'
12
13
  import { createLogger, overrideFatal, parseArgs, setVerbose } from './lib/utils.js'
13
14
 
@@ -95,6 +96,9 @@ export async function main () {
95
96
  case 'resolve':
96
97
  command = resolveCommand
97
98
  break
99
+ case 'patch-config':
100
+ command = patchConfigCommand
101
+ break
98
102
  case 'install':
99
103
  command = installCommand
100
104
  break
@@ -117,3 +121,4 @@ export async function main () {
117
121
  export * from './lib/schema.js'
118
122
 
119
123
  export { resolveServices } from './lib/commands/external.js'
124
+ export { patchConfig } from './lib/commands/patch-config.js'
@@ -4,7 +4,17 @@ import { logo } from '../logo.js'
4
4
  async function loadCommands () {
5
5
  const commands = {}
6
6
 
7
- for (const file of ['init', 'build', 'execution', 'management', 'logs', 'inject', 'external', 'metrics']) {
7
+ for (const file of [
8
+ 'init',
9
+ 'build',
10
+ 'execution',
11
+ 'management',
12
+ 'logs',
13
+ 'inject',
14
+ 'external',
15
+ 'patch-config',
16
+ 'metrics'
17
+ ]) {
8
18
  const category = await import(`./${file}.js`)
9
19
  Object.assign(commands, category.help)
10
20
  }
@@ -0,0 +1,133 @@
1
+ import { ConfigManager, getParser, getStringifier } from '@platformatic/config'
2
+ import { ensureLoggableError, loadModule } from '@platformatic/utils'
3
+ import jsonPatch from 'fast-json-patch'
4
+ import { existsSync } from 'node:fs'
5
+ import { readFile, writeFile } from 'node:fs/promises'
6
+ import { createRequire } from 'node:module'
7
+ import { resolve } from 'node:path'
8
+ import { buildRuntime, findConfigurationFile, getRoot, parseArgs } from '../utils.js'
9
+
10
+ async function patchFile (path, patch) {
11
+ let config = getParser(path)(await readFile(path, 'utf-8'))
12
+ config = jsonPatch.applyPatch(config, patch).newDocument
13
+ await writeFile(path, getStringifier(path)(config))
14
+ }
15
+
16
+ export async function patchConfig (logger, configurationFile, patchPath) {
17
+ let runtime
18
+ try {
19
+ const patchFunction = await loadModule(createRequire(import.meta.url), patchPath)
20
+
21
+ if (typeof patchFunction !== 'function') {
22
+ throw new Error('Patch file must export a function.')
23
+ }
24
+
25
+ // Create the runtime
26
+ runtime = await buildRuntime(logger, configurationFile)
27
+
28
+ // Prepare the structure for original and modified configurations files
29
+ const original = {
30
+ runtime: getParser(configurationFile)(await readFile(configurationFile, 'utf-8')),
31
+ services: {}
32
+ }
33
+
34
+ const loaded = {
35
+ runtime: runtime.getRuntimeConfig(),
36
+ services: {}
37
+ }
38
+
39
+ const services = Object.fromEntries(loaded.runtime.services.map(service => [service.id, service]))
40
+
41
+ // Load configuration for all services
42
+ for (const service of loaded.runtime.services) {
43
+ if (!service.config) {
44
+ const candidate = ConfigManager.listConfigFiles().find(f => existsSync(resolve(service.path, f)))
45
+
46
+ if (candidate) {
47
+ service.config = resolve(service.path, candidate)
48
+ }
49
+ }
50
+
51
+ const { id, config } = service
52
+ const parser = getParser(config)
53
+
54
+ original.services[id] = parser(await readFile(configurationFile, 'utf-8'))
55
+ loaded.services[id] = await runtime.getServiceConfig(id, false)
56
+ }
57
+
58
+ // Execute the patch function
59
+ const patches = await patchFunction(runtime, services, loaded, original)
60
+
61
+ // Apply patches
62
+ if (typeof patches !== 'object') {
63
+ return
64
+ }
65
+
66
+ if (Array.isArray(patches.runtime)) {
67
+ await patchFile(configurationFile, patches.runtime)
68
+ }
69
+
70
+ if (typeof patches.services === 'object') {
71
+ for (const [id, patch] of Object.entries(patches.services)) {
72
+ const config = services[id].config
73
+
74
+ if (Array.isArray(patch)) {
75
+ await patchFile(config, patch)
76
+ }
77
+ }
78
+ }
79
+ } finally {
80
+ await runtime?.close?.(false, true)
81
+ }
82
+ }
83
+
84
+ export async function patchConfigCommand (logger, args) {
85
+ const { positionals } = parseArgs(args, {}, false)
86
+
87
+ let root
88
+ let patch
89
+
90
+ /*
91
+ One argument = patch file
92
+ Two arguments = root and patch file
93
+ */
94
+
95
+ /* c8 ignore next 7 */
96
+ if (positionals.length === 1) {
97
+ root = getRoot()
98
+ patch = positionals[0]
99
+ } else {
100
+ root = getRoot(positionals)
101
+ patch = positionals[1]
102
+ }
103
+
104
+ const configurationFile = await findConfigurationFile(logger, root)
105
+
106
+ try {
107
+ await patchConfig(logger, configurationFile, patch)
108
+ } catch (error) {
109
+ logger.error({ err: ensureLoggableError(error) }, `Patching configuration has throw an exception: ${error.message}`)
110
+
111
+ process.exit(1)
112
+ }
113
+
114
+ logger.done('Patch executed correctly.')
115
+ }
116
+
117
+ export const help = {
118
+ 'patch-config': {
119
+ usage: 'patch-config [root] [patch]',
120
+ description: 'Applies a patch file to the runtime and services configurations.',
121
+ args: [
122
+ {
123
+ name: 'root',
124
+ description:
125
+ 'The process ID of the application (it can be omitted only if there is a single application running)'
126
+ },
127
+ {
128
+ name: 'patch',
129
+ description: 'The file containing the patch to execute.'
130
+ }
131
+ ]
132
+ }
133
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wattpm",
3
- "version": "2.31.0",
3
+ "version": "2.33.0",
4
4
  "description": "The Node.js Application Server",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -35,11 +35,11 @@
35
35
  "pino-pretty": "^13.0.0",
36
36
  "split2": "^4.2.0",
37
37
  "table": "^6.8.2",
38
- "@platformatic/basic": "2.31.0",
39
- "@platformatic/control": "2.31.0",
40
- "@platformatic/config": "2.31.0",
41
- "@platformatic/utils": "2.31.0",
42
- "@platformatic/runtime": "2.31.0"
38
+ "@platformatic/basic": "2.33.0",
39
+ "@platformatic/control": "2.33.0",
40
+ "@platformatic/config": "2.33.0",
41
+ "@platformatic/runtime": "2.33.0",
42
+ "@platformatic/utils": "2.33.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "borp": "^0.19.0",
@@ -49,7 +49,7 @@
49
49
  "neostandard": "^0.12.0",
50
50
  "typescript": "^5.5.4",
51
51
  "undici": "^7.0.0",
52
- "@platformatic/node": "2.31.0"
52
+ "@platformatic/node": "2.33.0"
53
53
  },
54
54
  "scripts": {
55
55
  "test": "npm run lint && borp --concurrency=1 --timeout=300000",
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/wattpm/2.31.0.json",
2
+ "$id": "https://schemas.platformatic.dev/wattpm/2.33.0.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "type": "object",
5
5
  "properties": {