@platformatic/runtime 3.15.0 → 3.17.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
@@ -143,6 +143,12 @@ export async function create (configOrRoot, sourceOrConfig, context) {
143
143
  if (context?.start) {
144
144
  let port = config.server?.port
145
145
 
146
+ await runtime.init()
147
+
148
+ if (context.reloaded) {
149
+ runtime.logger.info('The application has been successfully reloaded.')
150
+ }
151
+
146
152
  while (true) {
147
153
  try {
148
154
  await runtime.start()
package/lib/generator.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import createError from '@fastify/error'
2
2
  import {
3
+ createEnvFileTool,
3
4
  defaultPackageManager,
4
5
  findConfigurationFile,
5
6
  generateDashedName,
@@ -50,12 +51,6 @@ function getRuntimeBaseEnvVars (config) {
50
51
  }
51
52
  }
52
53
 
53
- // This is needed as dotenv-tool is not loading with ESM currently
54
- export function createDotenvTool (...args) {
55
- const { DotEnvTool } = createRequire(import.meta.url)('dotenv-tool')
56
- return new DotEnvTool(...args)
57
- }
58
-
59
54
  export class RuntimeGenerator extends BaseGenerator {
60
55
  constructor (opts) {
61
56
  super({
@@ -371,8 +366,8 @@ export class RuntimeGenerator extends BaseGenerator {
371
366
  // check all applications are present with the same template
372
367
  const allCurrentApplicationsNames = this.applications.map(s => s.name)
373
368
  const allNewApplicationsNames = newConfig.applications.map(s => s.name)
374
- // load dotenv tool
375
- const envTool = createDotenvTool({
369
+ // load env file tool
370
+ const envTool = createEnvFileTool({
376
371
  path: join(this.targetDirectory, '.env')
377
372
  })
378
373
 
@@ -1,11 +1,18 @@
1
1
  import fastifyAccepts from '@fastify/accepts'
2
2
  import fastifyWebsocket from '@fastify/websocket'
3
- import { createDirectory, safeRemove } from '@platformatic/foundation'
3
+ import {
4
+ applications as applicationSchema,
5
+ createDirectory,
6
+ kMetadata,
7
+ safeRemove,
8
+ validate
9
+ } from '@platformatic/foundation'
4
10
  import fastify from 'fastify'
5
11
  import { platform, tmpdir } from 'node:os'
6
12
  import { join } from 'node:path'
7
13
  import { setTimeout as sleep } from 'node:timers/promises'
8
14
  import { createWebSocketStream } from 'ws'
15
+ import { prepareApplication } from './config.js'
9
16
 
10
17
  const PLATFORMATIC_TMP_DIR = join(tmpdir(), 'platformatic', 'runtimes')
11
18
 
@@ -14,6 +21,26 @@ export async function managementApiPlugin (app, opts) {
14
21
 
15
22
  const runtime = opts.runtime
16
23
 
24
+ async function deleteApplications (ids, reply) {
25
+ const validIds = runtime.getApplicationsIds()
26
+
27
+ for (const id of ids) {
28
+ if (!validIds.includes(id)) {
29
+ reply.code(404)
30
+
31
+ return {
32
+ error: 'Not Found',
33
+ message: `Application with id "${id}" not found.`,
34
+ statusCode: 404
35
+ }
36
+ }
37
+ }
38
+
39
+ const removed = await runtime.removeApplications(ids)
40
+ reply.code(202)
41
+ return removed
42
+ }
43
+
17
44
  app.get('/status', async () => {
18
45
  const status = runtime.getRuntimeStatus()
19
46
  return { status }
@@ -23,8 +50,16 @@ export async function managementApiPlugin (app, opts) {
23
50
  return runtime.getRuntimeMetadata()
24
51
  })
25
52
 
26
- app.get('/config', async () => {
27
- return runtime.getRuntimeConfig()
53
+ app.get('/config', async request => {
54
+ const metadata = request.query.metadata === 'true'
55
+ const rawConfig = await runtime.getRuntimeConfig(metadata)
56
+
57
+ if (metadata) {
58
+ const { [kMetadata]: __metadata, ...config } = rawConfig
59
+ return { ...config, __metadata }
60
+ }
61
+
62
+ return rawConfig
28
63
  })
29
64
 
30
65
  app.get('/env', async () => {
@@ -46,12 +81,60 @@ export async function managementApiPlugin (app, opts) {
46
81
  return runtime.getApplications()
47
82
  })
48
83
 
84
+ app.post('/applications', async (request, reply) => {
85
+ let applications = request.body
86
+
87
+ if (!Array.isArray(applications)) {
88
+ applications = [applications]
89
+ }
90
+
91
+ const config = runtime.getRuntimeConfig(true)
92
+
93
+ try {
94
+ validate(applicationSchema, applications, {}, true, config[kMetadata].root)
95
+ } catch (err) {
96
+ reply.code(400)
97
+
98
+ return {
99
+ statusCode: 400,
100
+ error: 'Bad Request',
101
+ message: 'Invalid applications configuration.',
102
+ validationErrors: err.validationErrors
103
+ }
104
+ }
105
+
106
+ for (let i = 0; i < applications.length; i++) {
107
+ applications[i] = await prepareApplication(config, applications[i])
108
+ }
109
+
110
+ const created = await runtime.addApplications(applications, request.query.start !== 'false')
111
+ reply.code(201)
112
+ return created
113
+ })
114
+
115
+ app.delete('/applications', async (request, reply) => {
116
+ if (!Array.isArray(request.body)) {
117
+ reply.code(404)
118
+ return {
119
+ statusCode: 404,
120
+ error: 'Bad Request',
121
+ message: 'Invalid applications IDs.'
122
+ }
123
+ }
124
+
125
+ return deleteApplications(request.body, reply)
126
+ })
127
+
49
128
  app.get('/applications/:id', async request => {
50
129
  const { id } = request.params
51
130
  app.log.debug('get application details', { id })
52
131
  return runtime.getApplicationDetails(id)
53
132
  })
54
133
 
134
+ app.delete('/applications/:id', async (request, reply) => {
135
+ return deleteApplications([request.params.id], reply)
136
+ })
137
+
55
138
  app.get('/applications/:id/config', async request => {
56
139
  const { id } = request.params
57
140
  app.log.debug('get application config', { id })
@@ -195,7 +278,7 @@ export async function managementApiPlugin (app, opts) {
195
278
  })
196
279
  })
197
280
 
198
- app.get('/logs/live', { websocket: true }, async (socket, req) => {
281
+ app.get('/logs/live', { websocket: true }, async socket => {
199
282
  runtime.addLoggerDestination(createWebSocketStream(socket))
200
283
  })
201
284
  }
package/lib/runtime.js CHANGED
@@ -222,7 +222,7 @@ export class Runtime extends EventEmitter {
222
222
  await this.addApplications(this.#config.applications)
223
223
  await this.#setDispatcher(config.undici)
224
224
 
225
- if (config.scheduler) {
225
+ if (config.scheduler && !this.#context.build) {
226
226
  this.#scheduler = startScheduler(config.scheduler, this.#dispatcher, logger)
227
227
  }
228
228
 
@@ -477,7 +477,13 @@ export class Runtime extends EventEmitter {
477
477
  await this.startApplications(toStart)
478
478
  }
479
479
 
480
+ const created = []
481
+ for (const { id } of applications) {
482
+ created.push(await this.getApplicationDetails(id))
483
+ }
484
+
480
485
  this.#updateLoggingPrefixes()
486
+ return created
481
487
  }
482
488
 
483
489
  async removeApplications (applications, silent = false) {
@@ -485,6 +491,13 @@ export class Runtime extends EventEmitter {
485
491
  throw new CannotRemoveEntrypointError()
486
492
  }
487
493
 
494
+ const removed = []
495
+ for (const application of applications) {
496
+ const details = await this.getApplicationDetails(application)
497
+ details.status = 'removed'
498
+ removed.push(details)
499
+ }
500
+
488
501
  await this.stopApplications(applications, silent, true)
489
502
 
490
503
  for (const application of applications) {
@@ -498,6 +511,7 @@ export class Runtime extends EventEmitter {
498
511
  }
499
512
 
500
513
  this.#updateLoggingPrefixes()
514
+ return removed
501
515
  }
502
516
 
503
517
  async startApplications (applicationsToStart, silent = false) {
@@ -1191,7 +1205,7 @@ export class Runtime extends EventEmitter {
1191
1205
  throw e
1192
1206
  }
1193
1207
 
1194
- const { entrypoint, localUrl } = application[kConfig]
1208
+ const { entrypoint, localUrl, config, path } = application[kConfig]
1195
1209
 
1196
1210
  const status = await sendViaITC(application, 'getStatus')
1197
1211
  const { type, version, dependencies } = await sendViaITC(application, 'getApplicationInfo')
@@ -1199,6 +1213,8 @@ export class Runtime extends EventEmitter {
1199
1213
  const applicationDetails = {
1200
1214
  id,
1201
1215
  type,
1216
+ config,
1217
+ path,
1202
1218
  status,
1203
1219
  dependencies,
1204
1220
  version,
@@ -1596,7 +1612,7 @@ export class Runtime extends EventEmitter {
1596
1612
  await this.startApplication(applicationId)
1597
1613
  }
1598
1614
 
1599
- this.logger.info(`The application "${applicationId}" has been successfully reloaded ...`)
1615
+ this.logger.info(`The application "${applicationId}" has been successfully reloaded.`)
1600
1616
  this.emitAndNotify('application:worker:reloaded', eventPayload)
1601
1617
 
1602
1618
  if (applicationConfig.entrypoint) {
@@ -4,7 +4,6 @@ import {
4
4
  disablePinoDirectWrite,
5
5
  getPrivateSymbol
6
6
  } from '@platformatic/foundation'
7
- import dotenv from 'dotenv'
8
7
  import { subscribe } from 'node:diagnostics_channel'
9
8
  import { EventEmitter } from 'node:events'
10
9
  import { ServerResponse } from 'node:http'
@@ -110,9 +109,11 @@ async function main () {
110
109
 
111
110
  globalThis.platformatic.logger.debug({ envfile }, 'Loading envfile...')
112
111
 
113
- dotenv.config({
114
- path: envfile
115
- })
112
+ try {
113
+ process.loadEnvFile(envfile)
114
+ } catch {
115
+ // Ignore if the file doesn't exist, similar to dotenv behavior
116
+ }
116
117
 
117
118
  if (runtimeConfig.env) {
118
119
  Object.assign(process.env, runtimeConfig.env)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "3.15.0",
3
+ "version": "3.17.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.15.0",
39
- "@platformatic/db": "3.15.0",
40
- "@platformatic/gateway": "3.15.0",
41
- "@platformatic/node": "3.15.0",
42
- "@platformatic/sql-graphql": "3.15.0",
43
- "@platformatic/service": "3.15.0",
44
- "@platformatic/sql-mapper": "3.15.0",
45
- "@platformatic/wattpm-pprof-capture": "3.15.0"
38
+ "@platformatic/db": "3.17.0",
39
+ "@platformatic/composer": "3.17.0",
40
+ "@platformatic/gateway": "3.17.0",
41
+ "@platformatic/node": "3.17.0",
42
+ "@platformatic/service": "3.17.0",
43
+ "@platformatic/sql-graphql": "3.17.0",
44
+ "@platformatic/sql-mapper": "3.17.0",
45
+ "@platformatic/wattpm-pprof-capture": "3.17.0"
46
46
  },
47
47
  "dependencies": {
48
48
  "@fastify/accepts": "^5.0.0",
@@ -57,8 +57,6 @@
57
57
  "colorette": "^2.0.20",
58
58
  "cron": "^4.1.0",
59
59
  "debounce": "^2.0.0",
60
- "dotenv": "^16.4.5",
61
- "dotenv-tool": "^0.1.1",
62
60
  "fastest-levenshtein": "^1.0.16",
63
61
  "fastify": "^5.0.0",
64
62
  "graphql": "^16.8.1",
@@ -73,12 +71,12 @@
73
71
  "undici": "^7.0.0",
74
72
  "undici-thread-interceptor": "^0.15.0",
75
73
  "ws": "^8.16.0",
76
- "@platformatic/basic": "3.15.0",
77
- "@platformatic/foundation": "3.15.0",
78
- "@platformatic/metrics": "3.15.0",
79
- "@platformatic/generators": "3.15.0",
80
- "@platformatic/itc": "3.15.0",
81
- "@platformatic/telemetry": "3.15.0"
74
+ "@platformatic/basic": "3.17.0",
75
+ "@platformatic/itc": "3.17.0",
76
+ "@platformatic/generators": "3.17.0",
77
+ "@platformatic/foundation": "3.17.0",
78
+ "@platformatic/metrics": "3.17.0",
79
+ "@platformatic/telemetry": "3.17.0"
82
80
  },
83
81
  "engines": {
84
82
  "node": ">=22.19.0"
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.15.0.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.17.0.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "title": "Platformatic Runtime Config",
5
5
  "type": "object",