@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.
package/lib/config.js
CHANGED
package/lib/management-api.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
app.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
app.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
app.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
77
|
-
const
|
|
78
|
-
|
|
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
|
-
|
|
113
|
+
runtime.on('metrics', eventHandler)
|
|
94
114
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
.headers(res.headers)
|
|
98
|
-
.send(res.body)
|
|
115
|
+
socket.on('error', () => {
|
|
116
|
+
runtime.off('metrics', eventHandler)
|
|
99
117
|
})
|
|
100
118
|
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
127
|
-
|
|
124
|
+
app.get('/logs/live', { websocket: true }, async (socket, req) => {
|
|
125
|
+
const startLogId = req.query.start ? parseInt(req.query.start) : null
|
|
128
126
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
137
|
-
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
return runtimesLogsIds
|
|
146
|
-
}
|
|
138
|
+
app.get('/logs/indexes', async (req) => {
|
|
139
|
+
const returnAllIds = req.query.all === 'true'
|
|
147
140
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
141
|
+
if (returnAllIds) {
|
|
142
|
+
const runtimesLogsIds = await runtime.getAllLogIds()
|
|
143
|
+
return runtimesLogsIds
|
|
144
|
+
}
|
|
151
145
|
|
|
152
|
-
|
|
153
|
-
|
|
146
|
+
const runtimeLogsIds = await runtime.getLogIds()
|
|
147
|
+
return { indexes: runtimeLogsIds }
|
|
148
|
+
})
|
|
154
149
|
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
153
|
+
const logsIds = await runtime.getLogIds(runtimePID)
|
|
154
|
+
const startLogId = logsIds.at(0)
|
|
155
|
+
const endLogId = logsIds.at(-1)
|
|
160
156
|
|
|
161
|
-
|
|
162
|
-
reply.raw,
|
|
163
|
-
req.log,
|
|
164
|
-
startLogId,
|
|
165
|
-
endLogId,
|
|
166
|
-
runtimePID
|
|
167
|
-
)
|
|
168
|
-
})
|
|
157
|
+
reply.hijack()
|
|
169
158
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
159
|
+
runtime.pipeLogsStream(
|
|
160
|
+
reply.raw,
|
|
161
|
+
req.log,
|
|
162
|
+
startLogId,
|
|
163
|
+
endLogId,
|
|
164
|
+
runtimePID
|
|
165
|
+
)
|
|
166
|
+
})
|
|
173
167
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
-
|
|
177
|
+
const logFileStream = await runtime.getLogFileStream(
|
|
178
|
+
logId,
|
|
179
|
+
runtimePID
|
|
180
|
+
)
|
|
181
|
+
return logFileStream
|
|
182
|
+
})
|
|
188
183
|
}
|
|
189
184
|
|
|
190
|
-
async function startManagementApi (
|
|
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 =
|
|
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,
|
|
225
|
+
module.exports = { startManagementApi, managementApiPlugin }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "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.
|
|
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": "^
|
|
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.
|
|
38
|
-
"@platformatic/sql-mapper": "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": "^
|
|
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.
|
|
67
|
-
"@platformatic/config": "1.
|
|
68
|
-
"@platformatic/db": "1.
|
|
69
|
-
"@platformatic/generators": "1.
|
|
70
|
-
"@platformatic/service": "1.
|
|
71
|
-
"@platformatic/telemetry": "1.
|
|
72
|
-
"@platformatic/utils": "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": [
|