@platformatic/runtime 3.27.0 → 3.28.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/config.d.ts +2 -0
- package/lib/management-api.js +38 -0
- package/lib/runtime.js +36 -3
- package/lib/worker/itc.js +51 -0
- package/package.json +15 -15
- package/schema.json +32 -1
package/config.d.ts
CHANGED
|
@@ -48,6 +48,7 @@ export type PlatformaticRuntimeConfig = {
|
|
|
48
48
|
};
|
|
49
49
|
envfile?: string;
|
|
50
50
|
sourceMaps?: boolean;
|
|
51
|
+
nodeModulesSourceMaps?: string[];
|
|
51
52
|
packageManager?: "npm" | "pnpm" | "yarn";
|
|
52
53
|
preload?: string | string[];
|
|
53
54
|
nodeOptions?: string;
|
|
@@ -473,6 +474,7 @@ export type PlatformaticRuntimeConfig = {
|
|
|
473
474
|
[k: string]: string;
|
|
474
475
|
};
|
|
475
476
|
sourceMaps?: boolean;
|
|
477
|
+
nodeModulesSourceMaps?: string[];
|
|
476
478
|
scheduler?: {
|
|
477
479
|
enabled?: boolean | string;
|
|
478
480
|
name: string;
|
package/lib/management-api.js
CHANGED
|
@@ -288,6 +288,44 @@ export async function managementApiPlugin (app, opts) {
|
|
|
288
288
|
app.get('/logs/live', { websocket: true }, async socket => {
|
|
289
289
|
runtime.addLoggerDestination(createWebSocketStream(socket))
|
|
290
290
|
})
|
|
291
|
+
|
|
292
|
+
app.get('/applications/:id/repl', { websocket: true }, async (socket, request) => {
|
|
293
|
+
const { id } = request.params
|
|
294
|
+
|
|
295
|
+
try {
|
|
296
|
+
// Start REPL and get the communication port
|
|
297
|
+
const port = await runtime.startApplicationRepl(id)
|
|
298
|
+
|
|
299
|
+
// Forward messages between WebSocket and MessagePort
|
|
300
|
+
port.on('message', (message) => {
|
|
301
|
+
if (message.type === 'output') {
|
|
302
|
+
socket.send(message.data)
|
|
303
|
+
} else if (message.type === 'exit') {
|
|
304
|
+
socket.close()
|
|
305
|
+
}
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
socket.on('message', (data) => {
|
|
309
|
+
port.postMessage({ type: 'input', data: data.toString() })
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
socket.on('close', () => {
|
|
313
|
+
port.postMessage({ type: 'close' })
|
|
314
|
+
port.close()
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
socket.on('error', () => {
|
|
318
|
+
port.postMessage({ type: 'close' })
|
|
319
|
+
port.close()
|
|
320
|
+
})
|
|
321
|
+
} catch (error) {
|
|
322
|
+
socket.send(JSON.stringify({
|
|
323
|
+
error: error.message,
|
|
324
|
+
code: error.code
|
|
325
|
+
}))
|
|
326
|
+
socket.close()
|
|
327
|
+
}
|
|
328
|
+
})
|
|
291
329
|
}
|
|
292
330
|
|
|
293
331
|
export async function startManagementApi (runtime) {
|
package/lib/runtime.js
CHANGED
|
@@ -679,6 +679,19 @@ export class Runtime extends EventEmitter {
|
|
|
679
679
|
return sendViaITC(service, 'stopProfiling', options)
|
|
680
680
|
}
|
|
681
681
|
|
|
682
|
+
async startApplicationRepl (id, ensureStarted = true) {
|
|
683
|
+
const service = await this.#getApplicationById(id, ensureStarted)
|
|
684
|
+
|
|
685
|
+
// Create a MessageChannel for REPL communication
|
|
686
|
+
const { port1, port2 } = new MessageChannel()
|
|
687
|
+
|
|
688
|
+
// Send port1 to the worker to start the REPL
|
|
689
|
+
await sendViaITC(service, 'startRepl', port1, [port1])
|
|
690
|
+
|
|
691
|
+
// Return port2 for the caller to use
|
|
692
|
+
return port2
|
|
693
|
+
}
|
|
694
|
+
|
|
682
695
|
async updateUndiciInterceptors (undiciConfig) {
|
|
683
696
|
this.#config.undici = undiciConfig
|
|
684
697
|
|
|
@@ -885,6 +898,10 @@ export class Runtime extends EventEmitter {
|
|
|
885
898
|
this.#concurrency = concurrency
|
|
886
899
|
}
|
|
887
900
|
|
|
901
|
+
getRoot () {
|
|
902
|
+
return this.#root
|
|
903
|
+
}
|
|
904
|
+
|
|
888
905
|
getUrl () {
|
|
889
906
|
return this.#url
|
|
890
907
|
}
|
|
@@ -2081,6 +2098,14 @@ export class Runtime extends EventEmitter {
|
|
|
2081
2098
|
const label = this.#workerExtendedLabel(applicationId, index, workersCount)
|
|
2082
2099
|
let newWorker
|
|
2083
2100
|
|
|
2101
|
+
const stopBeforeStart =
|
|
2102
|
+
applicationConfig.entrypoint &&
|
|
2103
|
+
(config.reuseTcpPorts === false || applicationConfig.reuseTcpPorts === false || !features.node.reusePort)
|
|
2104
|
+
|
|
2105
|
+
if (stopBeforeStart) {
|
|
2106
|
+
await this.#removeWorker(workersCount, applicationId, index, worker, silent, label)
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2084
2109
|
try {
|
|
2085
2110
|
if (!silent) {
|
|
2086
2111
|
this.logger.debug(`Preparing to start a replacement for ${label} ...`)
|
|
@@ -2104,17 +2129,25 @@ export class Runtime extends EventEmitter {
|
|
|
2104
2129
|
|
|
2105
2130
|
this.#workers.set(workerId, newWorker)
|
|
2106
2131
|
this.#meshInterceptor.route(applicationId, newWorker)
|
|
2107
|
-
|
|
2108
|
-
// Remove the old worker and then kill it
|
|
2109
|
-
await sendViaITC(worker, 'removeFromMesh')
|
|
2110
2132
|
} catch (e) {
|
|
2111
2133
|
newWorker?.terminate?.()
|
|
2112
2134
|
throw e
|
|
2113
2135
|
}
|
|
2114
2136
|
|
|
2137
|
+
if (!stopBeforeStart) {
|
|
2138
|
+
await this.#removeWorker(workersCount, applicationId, index, worker, silent, label)
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
async #removeWorker (workersCount, applicationId, index, worker, silent, label) {
|
|
2115
2143
|
if (!silent) {
|
|
2116
2144
|
this.logger.debug(`Preparing to stop the old version of ${label} ...`)
|
|
2117
2145
|
}
|
|
2146
|
+
|
|
2147
|
+
// Remove the old worker and then kill it
|
|
2148
|
+
await sendViaITC(worker, 'removeFromMesh')
|
|
2149
|
+
|
|
2150
|
+
// Stop the old worker to free the port
|
|
2118
2151
|
await this.#stopWorker(workersCount, applicationId, index, false, worker, [])
|
|
2119
2152
|
}
|
|
2120
2153
|
|
package/lib/worker/itc.js
CHANGED
|
@@ -2,6 +2,8 @@ import { ensureLoggableError, executeInParallel, executeWithTimeout, kTimeout }
|
|
|
2
2
|
import { ITC } from '@platformatic/itc'
|
|
3
3
|
import { Unpromise } from '@watchable/unpromise'
|
|
4
4
|
import { once } from 'node:events'
|
|
5
|
+
import repl from 'node:repl'
|
|
6
|
+
import { Duplex } from 'node:stream'
|
|
5
7
|
import { parentPort, workerData } from 'node:worker_threads'
|
|
6
8
|
import {
|
|
7
9
|
ApplicationExitedError,
|
|
@@ -261,6 +263,55 @@ export function setupITC (controller, application, dispatcher, sharedContext) {
|
|
|
261
263
|
|
|
262
264
|
saveMessagingChannel (channel) {
|
|
263
265
|
messaging.addSource(channel)
|
|
266
|
+
},
|
|
267
|
+
|
|
268
|
+
startRepl (port) {
|
|
269
|
+
// Create a duplex stream that wraps the MessagePort
|
|
270
|
+
const replStream = new Duplex({
|
|
271
|
+
read () {},
|
|
272
|
+
write (chunk, encoding, callback) {
|
|
273
|
+
port.postMessage({ type: 'output', data: chunk.toString() })
|
|
274
|
+
callback()
|
|
275
|
+
}
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
port.on('message', (message) => {
|
|
279
|
+
if (message.type === 'input') {
|
|
280
|
+
replStream.push(message.data)
|
|
281
|
+
} else if (message.type === 'close') {
|
|
282
|
+
replStream.push(null)
|
|
283
|
+
}
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
port.on('close', () => {
|
|
287
|
+
replStream.push(null)
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
// Start the REPL with the stream
|
|
291
|
+
const replServer = repl.start({
|
|
292
|
+
prompt: `${controller.applicationConfig.id}> `,
|
|
293
|
+
input: replStream,
|
|
294
|
+
output: replStream,
|
|
295
|
+
terminal: false,
|
|
296
|
+
useColors: true,
|
|
297
|
+
ignoreUndefined: true,
|
|
298
|
+
preview: false
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
// Expose useful context
|
|
302
|
+
// For service-based capabilities, expose the Fastify app
|
|
303
|
+
replServer.context.app = controller.capability?.getApplication?.()
|
|
304
|
+
replServer.context.capability = controller.capability
|
|
305
|
+
replServer.context.platformatic = globalThis.platformatic
|
|
306
|
+
replServer.context.config = controller.applicationConfig
|
|
307
|
+
replServer.context.logger = globalThis.platformatic?.logger
|
|
308
|
+
|
|
309
|
+
replServer.on('exit', () => {
|
|
310
|
+
port.postMessage({ type: 'exit' })
|
|
311
|
+
port.close()
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
return { started: true }
|
|
264
315
|
}
|
|
265
316
|
}
|
|
266
317
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.28.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -35,14 +35,14 @@
|
|
|
35
35
|
"typescript": "^5.5.4",
|
|
36
36
|
"undici-oidc-interceptor": "^0.5.0",
|
|
37
37
|
"why-is-node-running": "^2.2.2",
|
|
38
|
-
"@platformatic/composer": "3.
|
|
39
|
-
"@platformatic/
|
|
40
|
-
"@platformatic/
|
|
41
|
-
"@platformatic/
|
|
42
|
-
"@platformatic/
|
|
43
|
-
"@platformatic/
|
|
44
|
-
"@platformatic/sql-mapper": "3.
|
|
45
|
-
"@platformatic/wattpm-pprof-capture": "3.
|
|
38
|
+
"@platformatic/composer": "3.28.0",
|
|
39
|
+
"@platformatic/db": "3.28.0",
|
|
40
|
+
"@platformatic/gateway": "3.28.0",
|
|
41
|
+
"@platformatic/node": "3.28.0",
|
|
42
|
+
"@platformatic/sql-graphql": "3.28.0",
|
|
43
|
+
"@platformatic/service": "3.28.0",
|
|
44
|
+
"@platformatic/sql-mapper": "3.28.0",
|
|
45
|
+
"@platformatic/wattpm-pprof-capture": "3.28.0"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@fastify/accepts": "^5.0.0",
|
|
@@ -71,12 +71,12 @@
|
|
|
71
71
|
"undici": "^7.0.0",
|
|
72
72
|
"undici-thread-interceptor": "^0.15.0",
|
|
73
73
|
"ws": "^8.16.0",
|
|
74
|
-
"@platformatic/basic": "3.
|
|
75
|
-
"@platformatic/
|
|
76
|
-
"@platformatic/
|
|
77
|
-
"@platformatic/
|
|
78
|
-
"@platformatic/
|
|
79
|
-
"@platformatic/telemetry": "3.
|
|
74
|
+
"@platformatic/basic": "3.28.0",
|
|
75
|
+
"@platformatic/generators": "3.28.0",
|
|
76
|
+
"@platformatic/foundation": "3.28.0",
|
|
77
|
+
"@platformatic/itc": "3.28.0",
|
|
78
|
+
"@platformatic/metrics": "3.28.0",
|
|
79
|
+
"@platformatic/telemetry": "3.28.0"
|
|
80
80
|
},
|
|
81
81
|
"engines": {
|
|
82
82
|
"node": ">=22.19.0"
|
package/schema.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.
|
|
2
|
+
"$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.28.0.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
4
|
"title": "Platformatic Runtime Config",
|
|
5
5
|
"type": "object",
|
|
@@ -227,6 +227,12 @@
|
|
|
227
227
|
"sourceMaps": {
|
|
228
228
|
"type": "boolean"
|
|
229
229
|
},
|
|
230
|
+
"nodeModulesSourceMaps": {
|
|
231
|
+
"type": "array",
|
|
232
|
+
"items": {
|
|
233
|
+
"type": "string"
|
|
234
|
+
}
|
|
235
|
+
},
|
|
230
236
|
"packageManager": {
|
|
231
237
|
"type": "string",
|
|
232
238
|
"enum": [
|
|
@@ -525,6 +531,12 @@
|
|
|
525
531
|
"sourceMaps": {
|
|
526
532
|
"type": "boolean"
|
|
527
533
|
},
|
|
534
|
+
"nodeModulesSourceMaps": {
|
|
535
|
+
"type": "array",
|
|
536
|
+
"items": {
|
|
537
|
+
"type": "string"
|
|
538
|
+
}
|
|
539
|
+
},
|
|
528
540
|
"packageManager": {
|
|
529
541
|
"type": "string",
|
|
530
542
|
"enum": [
|
|
@@ -821,6 +833,12 @@
|
|
|
821
833
|
"sourceMaps": {
|
|
822
834
|
"type": "boolean"
|
|
823
835
|
},
|
|
836
|
+
"nodeModulesSourceMaps": {
|
|
837
|
+
"type": "array",
|
|
838
|
+
"items": {
|
|
839
|
+
"type": "string"
|
|
840
|
+
}
|
|
841
|
+
},
|
|
824
842
|
"packageManager": {
|
|
825
843
|
"type": "string",
|
|
826
844
|
"enum": [
|
|
@@ -1117,6 +1135,12 @@
|
|
|
1117
1135
|
"sourceMaps": {
|
|
1118
1136
|
"type": "boolean"
|
|
1119
1137
|
},
|
|
1138
|
+
"nodeModulesSourceMaps": {
|
|
1139
|
+
"type": "array",
|
|
1140
|
+
"items": {
|
|
1141
|
+
"type": "string"
|
|
1142
|
+
}
|
|
1143
|
+
},
|
|
1120
1144
|
"packageManager": {
|
|
1121
1145
|
"type": "string",
|
|
1122
1146
|
"enum": [
|
|
@@ -2388,6 +2412,13 @@
|
|
|
2388
2412
|
"type": "boolean",
|
|
2389
2413
|
"default": false
|
|
2390
2414
|
},
|
|
2415
|
+
"nodeModulesSourceMaps": {
|
|
2416
|
+
"type": "array",
|
|
2417
|
+
"items": {
|
|
2418
|
+
"type": "string"
|
|
2419
|
+
},
|
|
2420
|
+
"default": []
|
|
2421
|
+
},
|
|
2391
2422
|
"scheduler": {
|
|
2392
2423
|
"type": "array",
|
|
2393
2424
|
"items": {
|