@platformatic/runtime 3.26.0 → 3.28.0-alpha.1

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.
@@ -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
 
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.26.0",
3
+ "version": "3.28.0-alpha.1",
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.26.0",
39
- "@platformatic/db": "3.26.0",
40
- "@platformatic/gateway": "3.26.0",
41
- "@platformatic/node": "3.26.0",
42
- "@platformatic/service": "3.26.0",
43
- "@platformatic/sql-graphql": "3.26.0",
44
- "@platformatic/sql-mapper": "3.26.0",
45
- "@platformatic/wattpm-pprof-capture": "3.26.0"
38
+ "@platformatic/composer": "3.28.0-alpha.1",
39
+ "@platformatic/db": "3.28.0-alpha.1",
40
+ "@platformatic/gateway": "3.28.0-alpha.1",
41
+ "@platformatic/node": "3.28.0-alpha.1",
42
+ "@platformatic/service": "3.28.0-alpha.1",
43
+ "@platformatic/sql-graphql": "3.28.0-alpha.1",
44
+ "@platformatic/sql-mapper": "3.28.0-alpha.1",
45
+ "@platformatic/wattpm-pprof-capture": "3.28.0-alpha.1"
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/foundation": "3.26.0",
75
- "@platformatic/basic": "3.26.0",
76
- "@platformatic/itc": "3.26.0",
77
- "@platformatic/metrics": "3.26.0",
78
- "@platformatic/generators": "3.26.0",
79
- "@platformatic/telemetry": "3.26.0"
74
+ "@platformatic/basic": "3.28.0-alpha.1",
75
+ "@platformatic/foundation": "3.28.0-alpha.1",
76
+ "@platformatic/itc": "3.28.0-alpha.1",
77
+ "@platformatic/generators": "3.28.0-alpha.1",
78
+ "@platformatic/telemetry": "3.28.0-alpha.1",
79
+ "@platformatic/metrics": "3.28.0-alpha.1"
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.26.0.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.28.0-alpha.1.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "title": "Platformatic Runtime Config",
5
5
  "type": "object",