@platformatic/runtime 1.36.1 → 1.37.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.
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "platformatic": "^1.25.0",
11
- "@fastify/oauth2": "7.8.0"
11
+ "@fastify/oauth2": "7.8.1"
12
12
  },
13
13
  "engines": {
14
14
  "node": "^18.8.0 || >=20.6.0"
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "platformatic": "^1.25.0",
11
- "@fastify/oauth2": "7.8.0"
11
+ "@fastify/oauth2": "7.8.1"
12
12
  },
13
13
  "engines": {
14
14
  "node": "^18.8.0 || >=20.6.0"
package/lib/config.js CHANGED
@@ -267,7 +267,6 @@ platformaticRuntime.configManagerConfig = {
267
267
  allErrors: true,
268
268
  strict: false
269
269
  },
270
- envWhitelist: ['DATABASE_URL', 'PORT', 'HOSTNAME'],
271
270
  async transformConfig () {
272
271
  await _transformConfig(this)
273
272
  },
@@ -11,8 +11,7 @@ const errors = require('./errors')
11
11
 
12
12
  const PLATFORMATIC_TMP_DIR = join(tmpdir(), 'platformatic', 'runtimes')
13
13
 
14
- async function createManagementApi (runtimeApiClient) {
15
- const app = fastify()
14
+ async function managementApiPlugin (app, opts) {
16
15
  app.log.warn(
17
16
  'Runtime Management API is in the experimental stage. ' +
18
17
  'The feature is not subject to semantic versioning rules. ' +
@@ -20,174 +19,170 @@ async function createManagementApi (runtimeApiClient) {
20
19
  'Use of the feature is not recommended in production environments.'
21
20
  )
22
21
 
23
- app.register(require('@fastify/websocket'))
24
-
25
- app.register(async (app) => {
26
- app.get('/metadata', async () => {
27
- return runtimeApiClient.getRuntimeMetadata()
28
- })
29
-
30
- app.get('/config', async () => {
31
- return runtimeApiClient.getRuntimeConfig()
32
- })
33
-
34
- app.get('/env', async () => {
35
- return process.env
36
- })
37
-
38
- app.post('/stop', async () => {
39
- app.log.debug('stop services')
40
- await runtimeApiClient.close()
41
- })
42
-
43
- app.post('/reload', async () => {
44
- app.log.debug('reload services')
45
- await runtimeApiClient.restart()
46
- })
47
-
48
- app.get('/services', async () => {
49
- return runtimeApiClient.getServices()
50
- })
51
-
52
- app.get('/services/:id', async (request) => {
53
- const { id } = request.params
54
- app.log.debug('get service details', { id })
55
- return runtimeApiClient.getServiceDetails(id)
56
- })
57
-
58
- app.get('/services/:id/config', async (request) => {
59
- const { id } = request.params
60
- app.log.debug('get service config', { id })
61
- return runtimeApiClient.getServiceConfig(id)
62
- })
63
-
64
- app.post('/services/:id/start', async (request) => {
65
- const { id } = request.params
66
- app.log.debug('start service', { id })
67
- await runtimeApiClient.startService(id)
68
- })
22
+ const runtime = opts.runtime
23
+
24
+ app.get('/metadata', async () => {
25
+ return runtime.getRuntimeMetadata()
26
+ })
27
+
28
+ app.get('/config', async () => {
29
+ return runtime.getRuntimeConfig()
30
+ })
31
+
32
+ app.get('/env', async () => {
33
+ return process.env
34
+ })
35
+
36
+ app.post('/stop', async () => {
37
+ app.log.debug('stop services')
38
+ await runtime.close()
39
+ })
40
+
41
+ app.post('/reload', async () => {
42
+ app.log.debug('reload services')
43
+ await runtime.restart()
44
+ })
45
+
46
+ app.get('/services', async () => {
47
+ return runtime.getServices()
48
+ })
49
+
50
+ app.get('/services/:id', async (request) => {
51
+ const { id } = request.params
52
+ app.log.debug('get service details', { id })
53
+ return runtime.getServiceDetails(id)
54
+ })
55
+
56
+ app.get('/services/:id/config', async (request) => {
57
+ const { id } = request.params
58
+ app.log.debug('get service config', { id })
59
+ return runtime.getServiceConfig(id)
60
+ })
61
+
62
+ app.post('/services/:id/start', async (request) => {
63
+ const { id } = request.params
64
+ app.log.debug('start service', { id })
65
+ await runtime.startService(id)
66
+ })
67
+
68
+ app.post('/services/:id/stop', async (request) => {
69
+ const { id } = request.params
70
+ app.log.debug('stop service', { id })
71
+ await runtime.stopService(id)
72
+ })
73
+
74
+ app.all('/services/:id/proxy/*', async (request, reply) => {
75
+ const { id, '*': requestUrl } = request.params
76
+ app.log.debug('proxy request', { id, requestUrl })
77
+
78
+ delete request.headers.connection
79
+ delete request.headers['content-length']
80
+ delete request.headers['content-encoding']
81
+ delete request.headers['transfer-encoding']
82
+
83
+ const injectParams = {
84
+ method: request.method,
85
+ url: requestUrl || '/',
86
+ headers: request.headers,
87
+ query: request.query,
88
+ body: request.body
89
+ }
69
90
 
70
- app.post('/services/:id/stop', async (request) => {
71
- const { id } = request.params
72
- app.log.debug('stop service', { id })
73
- await runtimeApiClient.stopService(id)
74
- })
91
+ const res = await runtime.inject(id, injectParams)
92
+
93
+ reply
94
+ .code(res.statusCode)
95
+ .headers(res.headers)
96
+ .send(res.body)
97
+ })
98
+
99
+ app.get('/metrics/live', { websocket: true }, async (socket) => {
100
+ const cachedMetrics = runtime.getCachedMetrics()
101
+ if (cachedMetrics.length > 0) {
102
+ const serializedMetrics = cachedMetrics
103
+ .map((metric) => JSON.stringify(metric))
104
+ .join('\n')
105
+ socket.send(serializedMetrics + '\n')
106
+ }
75
107
 
76
- app.all('/services/:id/proxy/*', async (request, reply) => {
77
- const { id, '*': requestUrl } = request.params
78
- app.log.debug('proxy request', { id, requestUrl })
79
-
80
- delete request.headers.connection
81
- delete request.headers['content-length']
82
- delete request.headers['content-encoding']
83
- delete request.headers['transfer-encoding']
84
-
85
- const injectParams = {
86
- method: request.method,
87
- url: requestUrl || '/',
88
- headers: request.headers,
89
- query: request.query,
90
- body: request.body
91
- }
108
+ const eventHandler = (metrics) => {
109
+ const serializedMetrics = JSON.stringify(metrics)
110
+ socket.send(serializedMetrics + '\n')
111
+ }
92
112
 
93
- const res = await runtimeApiClient.inject(id, injectParams)
113
+ runtime.on('metrics', eventHandler)
94
114
 
95
- reply
96
- .code(res.statusCode)
97
- .headers(res.headers)
98
- .send(res.body)
115
+ socket.on('error', () => {
116
+ runtime.off('metrics', eventHandler)
99
117
  })
100
118
 
101
- app.get('/metrics/live', { websocket: true }, async (socket) => {
102
- const cachedMetrics = runtimeApiClient.getCachedMetrics()
103
- if (cachedMetrics.length > 0) {
104
- const serializedMetrics = cachedMetrics
105
- .map((metric) => JSON.stringify(metric))
106
- .join('\n')
107
- socket.send(serializedMetrics + '\n')
108
- }
109
-
110
- const eventHandler = (metrics) => {
111
- const serializedMetrics = JSON.stringify(metrics)
112
- socket.send(serializedMetrics + '\n')
113
- }
114
-
115
- runtimeApiClient.on('metrics', eventHandler)
116
-
117
- socket.on('error', () => {
118
- runtimeApiClient.off('metrics', eventHandler)
119
- })
120
-
121
- socket.on('close', () => {
122
- runtimeApiClient.off('metrics', eventHandler)
123
- })
119
+ socket.on('close', () => {
120
+ runtime.off('metrics', eventHandler)
124
121
  })
122
+ })
125
123
 
126
- app.get('/logs/live', { websocket: true }, async (socket, req) => {
127
- const startLogId = req.query.start ? parseInt(req.query.start) : null
124
+ app.get('/logs/live', { websocket: true }, async (socket, req) => {
125
+ const startLogId = req.query.start ? parseInt(req.query.start) : null
128
126
 
129
- if (startLogId) {
130
- const logIds = await runtimeApiClient.getLogIds()
131
- if (!logIds.includes(startLogId)) {
132
- throw new errors.LogFileNotFound(startLogId)
133
- }
127
+ if (startLogId) {
128
+ const logIds = await runtime.getLogIds()
129
+ if (!logIds.includes(startLogId)) {
130
+ throw new errors.LogFileNotFound(startLogId)
134
131
  }
132
+ }
135
133
 
136
- const stream = ws.createWebSocketStream(socket)
137
- runtimeApiClient.pipeLogsStream(stream, req.log, startLogId)
138
- })
139
-
140
- app.get('/logs/indexes', async (req) => {
141
- const returnAllIds = req.query.all === 'true'
134
+ const stream = ws.createWebSocketStream(socket)
135
+ runtime.pipeLogsStream(stream, req.log, startLogId)
136
+ })
142
137
 
143
- if (returnAllIds) {
144
- const runtimesLogsIds = await runtimeApiClient.getAllLogIds()
145
- return runtimesLogsIds
146
- }
138
+ app.get('/logs/indexes', async (req) => {
139
+ const returnAllIds = req.query.all === 'true'
147
140
 
148
- const runtimeLogsIds = await runtimeApiClient.getLogIds()
149
- return { indexes: runtimeLogsIds }
150
- })
141
+ if (returnAllIds) {
142
+ const runtimesLogsIds = await runtime.getAllLogIds()
143
+ return runtimesLogsIds
144
+ }
151
145
 
152
- app.get('/logs/all', async (req, reply) => {
153
- const runtimePID = parseInt(req.query.pid) || process.pid
146
+ const runtimeLogsIds = await runtime.getLogIds()
147
+ return { indexes: runtimeLogsIds }
148
+ })
154
149
 
155
- const logsIds = await runtimeApiClient.getLogIds(runtimePID)
156
- const startLogId = logsIds.at(0)
157
- const endLogId = logsIds.at(-1)
150
+ app.get('/logs/all', async (req, reply) => {
151
+ const runtimePID = parseInt(req.query.pid) || process.pid
158
152
 
159
- reply.hijack()
153
+ const logsIds = await runtime.getLogIds(runtimePID)
154
+ const startLogId = logsIds.at(0)
155
+ const endLogId = logsIds.at(-1)
160
156
 
161
- runtimeApiClient.pipeLogsStream(
162
- reply.raw,
163
- req.log,
164
- startLogId,
165
- endLogId,
166
- runtimePID
167
- )
168
- })
157
+ reply.hijack()
169
158
 
170
- app.get('/logs/:id', async (req) => {
171
- const logId = parseInt(req.params.id)
172
- const runtimePID = parseInt(req.query.pid) || process.pid
159
+ runtime.pipeLogsStream(
160
+ reply.raw,
161
+ req.log,
162
+ startLogId,
163
+ endLogId,
164
+ runtimePID
165
+ )
166
+ })
173
167
 
174
- const logIds = await runtimeApiClient.getLogIds(runtimePID)
175
- if (!logIds || !logIds.includes(logId)) {
176
- throw new errors.LogFileNotFound(logId)
177
- }
168
+ app.get('/logs/:id', async (req) => {
169
+ const logId = parseInt(req.params.id)
170
+ const runtimePID = parseInt(req.query.pid) || process.pid
178
171
 
179
- const logFileStream = await runtimeApiClient.getLogFileStream(
180
- logId,
181
- runtimePID
182
- )
183
- return logFileStream
184
- })
185
- }, { prefix: '/api/v1' })
172
+ const logIds = await runtime.getLogIds(runtimePID)
173
+ if (!logIds || !logIds.includes(logId)) {
174
+ throw new errors.LogFileNotFound(logId)
175
+ }
186
176
 
187
- return app
177
+ const logFileStream = await runtime.getLogFileStream(
178
+ logId,
179
+ runtimePID
180
+ )
181
+ return logFileStream
182
+ })
188
183
  }
189
184
 
190
- async function startManagementApi (runtimeApiClient, configManager) {
185
+ async function startManagementApi (runtime, configManager) {
191
186
  const runtimePID = process.pid
192
187
 
193
188
  try {
@@ -208,7 +203,9 @@ async function startManagementApi (runtimeApiClient, configManager) {
208
203
  socketPath = join(runtimePIDDir, 'socket')
209
204
  }
210
205
 
211
- const managementApi = await createManagementApi(runtimeApiClient)
206
+ const managementApi = fastify()
207
+ managementApi.register(require('@fastify/websocket'))
208
+ managementApi.register(managementApiPlugin, { runtime, prefix: '/api/v1' })
212
209
 
213
210
  managementApi.addHook('onClose', async () => {
214
211
  if (platform() !== 'win32') {
@@ -225,4 +222,4 @@ async function startManagementApi (runtimeApiClient, configManager) {
225
222
  }
226
223
  }
227
224
 
228
- module.exports = { startManagementApi, createManagementApi }
225
+ module.exports = { startManagementApi, managementApiPlugin }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "1.36.1",
3
+ "version": "1.37.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -20,11 +20,11 @@
20
20
  "@fastify/express": "^3.0.0",
21
21
  "@fastify/formbody": "^7.4.0",
22
22
  "@matteo.collina/tspl": "^0.1.1",
23
- "borp": "^0.11.0",
23
+ "borp": "^0.13.0",
24
24
  "c8": "^9.1.0",
25
25
  "execa": "^8.0.1",
26
26
  "express": "^4.18.3",
27
- "fast-jwt": "^3.3.3",
27
+ "fast-jwt": "^4.0.0",
28
28
  "get-port": "^7.1.0",
29
29
  "pino-abstract-transport": "^1.1.0",
30
30
  "snazzy": "^9.0.0",
@@ -34,8 +34,8 @@
34
34
  "typescript": "^5.4.2",
35
35
  "undici-oidc-interceptor": "^0.5.0",
36
36
  "why-is-node-running": "^2.2.2",
37
- "@platformatic/sql-graphql": "1.36.1",
38
- "@platformatic/sql-mapper": "1.36.1"
37
+ "@platformatic/sql-graphql": "1.37.0",
38
+ "@platformatic/sql-mapper": "1.37.0"
39
39
  },
40
40
  "dependencies": {
41
41
  "@fastify/error": "^3.4.1",
@@ -56,20 +56,20 @@
56
56
  "help-me": "^5.0.0",
57
57
  "minimist": "^1.2.8",
58
58
  "pino": "^8.19.0",
59
- "pino-pretty": "^10.3.1",
59
+ "pino-pretty": "^11.0.0",
60
60
  "pino-roll": "^1.0.0",
61
61
  "semgrator": "^0.3.0",
62
62
  "tail-file-stream": "^0.1.0",
63
63
  "undici": "^6.9.0",
64
64
  "why-is-node-running": "^2.2.2",
65
65
  "ws": "^8.16.0",
66
- "@platformatic/composer": "1.36.1",
67
- "@platformatic/config": "1.36.1",
68
- "@platformatic/db": "1.36.1",
69
- "@platformatic/generators": "1.36.1",
70
- "@platformatic/service": "1.36.1",
71
- "@platformatic/telemetry": "1.36.1",
72
- "@platformatic/utils": "1.36.1"
66
+ "@platformatic/composer": "1.37.0",
67
+ "@platformatic/config": "1.37.0",
68
+ "@platformatic/db": "1.37.0",
69
+ "@platformatic/generators": "1.37.0",
70
+ "@platformatic/service": "1.37.0",
71
+ "@platformatic/telemetry": "1.37.0",
72
+ "@platformatic/utils": "1.37.0"
73
73
  },
74
74
  "standard": {
75
75
  "ignore": [