@platformatic/runtime 1.53.3 → 2.0.0-alpha.10
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 +284 -0
- package/eslint.config.js +8 -0
- package/fixtures/botched-start/platformatic.runtime.json +1 -1
- package/fixtures/botched-start/services/a/platformatic.service.json +1 -1
- package/fixtures/composerApp/platformatic.composer.json +1 -1
- package/fixtures/configs/{monorepo-hotreload.json → invalid-autoload-with-services.json} +8 -8
- package/fixtures/configs/invalid-entrypoint.json +1 -1
- package/fixtures/configs/invalid-schema-type.config.json +1 -1
- package/fixtures/configs/missing-property.config.json +1 -1
- package/fixtures/configs/missing-service-config.json +1 -1
- package/fixtures/configs/monorepo-composer-no-autoload.json +32 -0
- package/fixtures/configs/monorepo-composer.json +2 -2
- package/fixtures/configs/monorepo-create-cycle.json +2 -3
- package/fixtures/configs/monorepo-missing-dependencies.json +9 -0
- package/fixtures/configs/monorepo-no-cycles.json +2 -3
- package/fixtures/configs/monorepo-openapi.json +2 -2
- package/fixtures/configs/{hotreload.json → monorepo-watch-env.json} +2 -3
- package/fixtures/configs/monorepo-watch-single.json +12 -0
- package/fixtures/configs/monorepo-watch.json +26 -9
- package/fixtures/configs/monorepo-with-dependencies.json +2 -2
- package/fixtures/configs/{monorepo-client-without-id.json → monorepo-with-management-api-without-metrics.json} +5 -8
- package/fixtures/configs/monorepo-with-management-api.json +2 -3
- package/fixtures/configs/monorepo-with-metrics.json +1 -2
- package/fixtures/configs/monorepo.json +2 -3
- package/fixtures/configs/no-services.config.json +1 -1
- package/fixtures/configs/no-sources.config.json +1 -1
- package/fixtures/configs/service-throws-on-start.json +1 -1
- package/fixtures/configs/service-with-env-port.json +2 -3
- package/fixtures/configs/service-with-stdio.json +12 -0
- package/fixtures/configs/{monorepo-hotreload-env.json → watch.json} +2 -3
- package/fixtures/crash-on-bootstrap/platformatic.runtime.json +15 -0
- package/fixtures/crash-on-bootstrap/services/service-1/platformatic.service.json +14 -0
- package/fixtures/crash-on-bootstrap/services/service-1/plugin.js +5 -0
- package/fixtures/crash-on-bootstrap/services/service-2/platformatic.service.json +14 -0
- package/fixtures/crash-on-bootstrap/services/service-2/plugin.js +5 -0
- package/fixtures/dbApp/platformatic.db.json +1 -1
- package/fixtures/dbAppNoName/platformatic.db.json +1 -1
- package/fixtures/dbAppNoPackageJson/platformatic.db.json +1 -1
- package/fixtures/dbAppWithMigrationError/platformatic.db.json +1 -1
- package/fixtures/do-not-reload-dependencies/platformatic.service.json +1 -1
- package/fixtures/do-not-restart-on-crash/platformatic.runtime.json +3 -2
- package/fixtures/do-not-restart-on-crash/services/a/platformatic.service.json +1 -1
- package/fixtures/express/platformatic.runtime.json +1 -1
- package/fixtures/express/services/a/platformatic.service.json +1 -1
- package/fixtures/express/services/b/platformatic.service.json +1 -1
- package/fixtures/external-client/platformatic.service.json +1 -1
- package/fixtures/interceptors/idp.js +2 -2
- package/fixtures/interceptors/platformatic.runtime.json +1 -1
- package/fixtures/interceptors/services/a/platformatic.service.json +1 -1
- package/fixtures/interceptors-2/platformatic.runtime.json +1 -1
- package/fixtures/interceptors-2/services/a/platformatic.service.json +1 -1
- package/fixtures/leven/platformatic.runtime.json +2 -3
- package/fixtures/leven/services/deeply-spittle/platformatic.service.json +1 -1
- package/fixtures/leven/services/rainy-empire/platformatic.composer.json +1 -1
- package/fixtures/management-api/platformatic.json +8 -4
- package/fixtures/management-api/services/service-1/platformatic.json +1 -1
- package/fixtures/management-api/services/service-1/plugin.js +4 -3
- package/fixtures/management-api/services/service-2/platformatic.json +1 -1
- package/fixtures/management-api/services/service-db/platformatic.db.json +1 -1
- package/fixtures/management-api-custom-labels/platformatic.json +2 -3
- package/fixtures/management-api-custom-labels/services/service-1/platformatic.json +1 -1
- package/fixtures/management-api-custom-labels/services/service-1/plugin.js +4 -3
- package/fixtures/management-api-custom-labels/services/service-2/platformatic.json +1 -1
- package/fixtures/management-api-custom-labels/services/service-db/platformatic.db.json +1 -1
- package/fixtures/management-api-without-metrics/platformatic.json +3 -3
- package/fixtures/management-api-without-metrics/services/service-1/platformatic.json +1 -1
- package/fixtures/monorepo/composerApp/platformatic.composer.json +1 -2
- package/fixtures/monorepo/dbApp/platformatic.db.json +1 -1
- package/fixtures/monorepo/serviceApp/platformatic.service.json +3 -2
- package/fixtures/monorepo/serviceApp/with-logger/with-logger.cjs +2 -2
- package/fixtures/monorepo/serviceApp/with-logger/with-logger.d.ts +7 -7
- package/fixtures/monorepo/serviceAppWithLogger/platformatic.service.json +1 -1
- package/fixtures/monorepo/serviceAppWithLogger/plugin.js +12 -0
- package/fixtures/monorepo/serviceAppWithMultiplePlugins/platformatic.service.json +3 -2
- package/fixtures/monorepo-missing-dependencies/composer/platformatic.json +24 -0
- package/fixtures/monorepo-openapi/serviceAppWithoutOpenapi/platformatic.service.json +1 -1
- package/fixtures/monorepo-watch/service1/platformatic.service.json +1 -1
- package/fixtures/monorepo-with-dependencies/main/platformatic.json +1 -1
- package/fixtures/monorepo-with-dependencies/service-1/platformatic.json +1 -1
- package/fixtures/monorepo-with-dependencies/service-2/platformatic.json +1 -1
- package/fixtures/no-env.service.json +1 -1
- package/fixtures/preload/platformatic.runtime.json +1 -1
- package/fixtures/preload/services/a/platformatic.service.json +1 -1
- package/fixtures/prom-server/platformatic.json +2 -3
- package/fixtures/prom-server/services/service-1/platformatic.json +1 -1
- package/fixtures/prom-server/services/service-2/platformatic.json +1 -1
- package/fixtures/restart-on-crash/platformatic.runtime.json +1 -1
- package/fixtures/restart-on-crash/services/a/platformatic.service.json +1 -1
- package/fixtures/sample-runtime/package.json +1 -1
- package/fixtures/sample-runtime/platformatic.json +2 -3
- package/fixtures/sample-runtime/services/rival/package.json +1 -1
- package/fixtures/sample-runtime/services/rival/platformatic.json +1 -1
- package/fixtures/sample-runtime-with-2-services/package.json +1 -1
- package/fixtures/sample-runtime-with-2-services/platformatic.json +2 -3
- package/fixtures/sample-runtime-with-2-services/services/foobar/package.json +1 -1
- package/fixtures/sample-runtime-with-2-services/services/foobar/platformatic.json +1 -1
- package/fixtures/sample-runtime-with-2-services/services/rival/package.json +1 -1
- package/fixtures/sample-runtime-with-2-services/services/rival/platformatic.json +1 -1
- package/fixtures/server/logger-transport/platformatic.runtime.json +2 -3
- package/fixtures/server/logger-transport/services/echo/platformatic.service.json +1 -1
- package/fixtures/server/overrides-service/platformatic.runtime.json +2 -3
- package/fixtures/server/overrides-service/services/echo/platformatic.service.json +1 -1
- package/fixtures/server/runtime-server/platformatic.runtime.json +2 -3
- package/fixtures/server/runtime-server/services/echo/platformatic.service.json +1 -1
- package/fixtures/serviceAppThrowsOnStart/platformatic.service.json +1 -1
- package/fixtures/stackables/node_modules/foo/foo.js +2 -1
- package/fixtures/start-command-in-runtime.js +1 -1
- package/fixtures/stdio/platformatic.service.json +6 -0
- package/fixtures/stdio/plugin.js +24 -0
- package/fixtures/telemetry/platformatic.runtime.json +2 -3
- package/fixtures/telemetry/services/echo/platformatic.service.json +1 -1
- package/fixtures/telemetry/services/echo/routes/span.js +16 -2
- package/fixtures/telemetry/services/service-1/platformatic.service.json +19 -0
- package/fixtures/telemetry/services/service-1/routes/echo.js +7 -0
- package/fixtures/typescript/platformatic.runtime.json +2 -3
- package/fixtures/typescript/services/composer/platformatic.composer.json +1 -1
- package/fixtures/typescript/services/movies/global.d.ts +2 -3
- package/fixtures/typescript/services/movies/platformatic.db.json +1 -1
- package/fixtures/typescript/services/movies/types/Movie.d.ts +3 -3
- package/fixtures/typescript/services/movies/types/index.d.ts +6 -6
- package/fixtures/typescript/services/titles/client/client.d.ts +35 -35
- package/fixtures/typescript/services/titles/platformatic.service.json +1 -1
- package/fixtures/typescript-custom-flags/platformatic.runtime.json +2 -3
- package/fixtures/typescript-custom-flags/services/composer/platformatic.composer.json +1 -1
- package/fixtures/typescript-custom-flags/services/movies/global.d.ts +2 -3
- package/fixtures/typescript-custom-flags/services/movies/platformatic.db.json +1 -1
- package/fixtures/typescript-custom-flags/services/movies/types/Movie.d.ts +3 -3
- package/fixtures/typescript-custom-flags/services/movies/types/index.d.ts +6 -6
- package/fixtures/typescript-custom-flags/services/titles/client/client.d.ts +35 -35
- package/fixtures/typescript-custom-flags/services/titles/platformatic.service.json +1 -1
- package/fixtures/typescript-no-env/platformatic.runtime.json +2 -3
- package/fixtures/typescript-no-env/services/composer/platformatic.composer.json +1 -1
- package/fixtures/typescript-no-env/services/movies/global.d.ts +2 -3
- package/fixtures/typescript-no-env/services/movies/platformatic.db.json +1 -1
- package/fixtures/typescript-no-env/services/movies/types/Movie.d.ts +3 -3
- package/fixtures/typescript-no-env/services/movies/types/index.d.ts +6 -6
- package/fixtures/typescript-no-env/services/titles/client/client.d.ts +35 -35
- package/fixtures/typescript-no-env/services/titles/platformatic.service.json +1 -1
- package/index.d.ts +7 -8
- package/index.js +15 -10
- package/index.test-d.ts +10 -12
- package/lib/build-server.js +23 -15
- package/lib/compile.js +56 -13
- package/lib/config.js +27 -139
- package/lib/dependencies.js +59 -0
- package/lib/errors.js +6 -2
- package/lib/generator/errors.js +1 -1
- package/lib/generator/runtime-generator.d.ts +15 -15
- package/lib/generator/runtime-generator.js +81 -66
- package/lib/logger.js +55 -0
- package/lib/management-api.js +29 -44
- package/lib/prom-server.js +5 -9
- package/lib/runtime.js +1005 -0
- package/lib/schema.js +46 -44
- package/lib/start.js +49 -117
- package/lib/upgrade.js +4 -3
- package/lib/utils.js +49 -1
- package/lib/versions/v1.36.0.js +1 -1
- package/lib/versions/v1.5.0.js +1 -1
- package/lib/versions/v2.0.0.js +17 -0
- package/lib/worker/app.js +266 -0
- package/lib/worker/default-stackable.js +32 -0
- package/lib/worker/itc.js +149 -0
- package/lib/worker/main.js +129 -0
- package/lib/worker/metrics.js +106 -0
- package/lib/worker/symbols.js +7 -0
- package/package.json +44 -44
- package/runtime.mjs +11 -6
- package/schema.json +25 -13
- package/fixtures/monorepo/serviceApp/platformatic.service-client-without-id.json +0 -21
- package/lib/api-client.js +0 -497
- package/lib/api.js +0 -397
- package/lib/app.js +0 -365
- package/lib/load-config.js +0 -20
- package/lib/loader.mjs +0 -103
- package/lib/message-port-writable.js +0 -50
- package/lib/worker.js +0 -182
- /package/lib/{interceptors.js → worker/interceptors.js} +0 -0
|
@@ -5,7 +5,7 @@ const { NoEntryPointError, NoServiceNamedError } = require('./errors')
|
|
|
5
5
|
const generateName = require('boring-name-generator')
|
|
6
6
|
const { join } = require('node:path')
|
|
7
7
|
const { envObjectToString } = require('@platformatic/generators/lib/utils')
|
|
8
|
-
const { readFile, readdir, stat
|
|
8
|
+
const { readFile, readdir, stat } = require('node:fs/promises')
|
|
9
9
|
const { ConfigManager } = require('@platformatic/config')
|
|
10
10
|
const { platformaticRuntime } = require('../config')
|
|
11
11
|
const { getServiceTemplateFromSchemaUrl } = require('@platformatic/generators/lib/utils')
|
|
@@ -13,12 +13,13 @@ const { DotEnvTool } = require('dotenv-tool')
|
|
|
13
13
|
const { getArrayDifference } = require('../utils')
|
|
14
14
|
const { createRequire } = require('node:module')
|
|
15
15
|
const { pathToFileURL } = require('node:url')
|
|
16
|
+
const { safeRemove } = require('@platformatic/utils')
|
|
16
17
|
|
|
17
18
|
class RuntimeGenerator extends BaseGenerator {
|
|
18
19
|
constructor (opts) {
|
|
19
20
|
super({
|
|
20
21
|
...opts,
|
|
21
|
-
module: '@platformatic/runtime'
|
|
22
|
+
module: '@platformatic/runtime',
|
|
22
23
|
})
|
|
23
24
|
this.runtimeName = opts.name
|
|
24
25
|
this.services = []
|
|
@@ -32,14 +33,14 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
32
33
|
const newConfig = {
|
|
33
34
|
...originalConfig,
|
|
34
35
|
isRuntimeContext: true,
|
|
35
|
-
serviceName
|
|
36
|
+
serviceName,
|
|
36
37
|
}
|
|
37
38
|
// reset all files previously generated by the service
|
|
38
39
|
service.reset()
|
|
39
40
|
service.setConfig(newConfig)
|
|
40
41
|
this.services.push({
|
|
41
42
|
name: serviceName,
|
|
42
|
-
service
|
|
43
|
+
service,
|
|
43
44
|
})
|
|
44
45
|
|
|
45
46
|
if (typeof service.setRuntime === 'function') {
|
|
@@ -48,7 +49,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
setEntryPoint (entryPoint) {
|
|
51
|
-
const service = this.services.find(
|
|
52
|
+
const service = this.services.find(svc => svc.name === entryPoint)
|
|
52
53
|
if (!service) {
|
|
53
54
|
throw new NoServiceNamedError(entryPoint)
|
|
54
55
|
}
|
|
@@ -60,23 +61,24 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
60
61
|
name: `${this.runtimeName}`,
|
|
61
62
|
workspaces: ['services/*'],
|
|
62
63
|
scripts: {
|
|
63
|
-
start: 'platformatic start'
|
|
64
|
+
start: 'platformatic start',
|
|
64
65
|
},
|
|
65
66
|
devDependencies: {
|
|
66
67
|
fastify: `^${this.fastifyVersion}`,
|
|
67
|
-
borp: `${this.pkgData.devDependencies.borp}
|
|
68
|
+
borp: `${this.pkgData.devDependencies.borp}`,
|
|
68
69
|
},
|
|
69
70
|
dependencies: {
|
|
70
71
|
'@platformatic/runtime': `^${this.platformaticVersion}`,
|
|
71
72
|
platformatic: `^${this.platformaticVersion}`,
|
|
72
|
-
...this.config.dependencies
|
|
73
|
+
...this.config.dependencies,
|
|
73
74
|
},
|
|
74
75
|
engines: {
|
|
75
|
-
node: '^18.8.0 || >=20.6.0'
|
|
76
|
-
}
|
|
76
|
+
node: '^18.8.0 || >=20.6.0',
|
|
77
|
+
},
|
|
77
78
|
}
|
|
78
79
|
if (this.config.typescript) {
|
|
79
|
-
const typescriptVersion = JSON.parse(await readFile(join(__dirname, '..', '..', 'package.json'), 'utf-8'))
|
|
80
|
+
const typescriptVersion = JSON.parse(await readFile(join(__dirname, '..', '..', 'package.json'), 'utf-8'))
|
|
81
|
+
.devDependencies.typescript
|
|
80
82
|
template.scripts.clean = 'rm -fr ./dist'
|
|
81
83
|
template.scripts.build = 'platformatic compile'
|
|
82
84
|
template.devDependencies.typescript = typescriptVersion
|
|
@@ -89,18 +91,21 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
89
91
|
this.setServicesConfigValues()
|
|
90
92
|
this.addServicesDependencies()
|
|
91
93
|
|
|
92
|
-
this.addEnvVars(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
this.addEnvVars(
|
|
95
|
+
{
|
|
96
|
+
PLT_SERVER_HOSTNAME: '127.0.0.1',
|
|
97
|
+
PORT: this.config.port || 3042,
|
|
98
|
+
PLT_SERVER_LOGGER_LEVEL: this.config.logLevel || 'info',
|
|
99
|
+
PLT_MANAGEMENT_API: true,
|
|
100
|
+
},
|
|
101
|
+
{ overwrite: false, default: true }
|
|
102
|
+
)
|
|
98
103
|
}
|
|
99
104
|
|
|
100
105
|
addServicesDependencies () {
|
|
101
106
|
this.services.forEach(({ service }) => {
|
|
102
107
|
if (service.config.dependencies) {
|
|
103
|
-
Object.entries(service.config.dependencies).forEach(
|
|
108
|
+
Object.entries(service.config.dependencies).forEach(kv => {
|
|
104
109
|
this.config.dependencies[kv[0]] = kv[1]
|
|
105
110
|
})
|
|
106
111
|
}
|
|
@@ -116,13 +121,13 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
116
121
|
if (existingConfigFile) {
|
|
117
122
|
const configManager = new ConfigManager({
|
|
118
123
|
...platformaticRuntime.configManagerConfig,
|
|
119
|
-
source: join(this.targetDirectory, existingConfigFile)
|
|
124
|
+
source: join(this.targetDirectory, existingConfigFile),
|
|
120
125
|
})
|
|
121
126
|
await configManager.parse()
|
|
122
127
|
this.existingConfig = configManager.current
|
|
123
128
|
this.config.env = configManager.env
|
|
124
129
|
this.config.port = configManager.env.PORT
|
|
125
|
-
this.entryPoint = configManager.current.services.find(
|
|
130
|
+
this.entryPoint = configManager.current.services.find(svc => svc.entrypoint)
|
|
126
131
|
}
|
|
127
132
|
}
|
|
128
133
|
|
|
@@ -134,7 +139,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
134
139
|
await this._afterPrepare()
|
|
135
140
|
return {
|
|
136
141
|
env: this.config.env,
|
|
137
|
-
targetDirectory: this.targetDirectory
|
|
142
|
+
targetDirectory: this.targetDirectory,
|
|
138
143
|
}
|
|
139
144
|
} else {
|
|
140
145
|
return await super.prepare()
|
|
@@ -153,22 +158,21 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
153
158
|
|
|
154
159
|
async _getConfigFileContents () {
|
|
155
160
|
const config = {
|
|
156
|
-
$schema: `https://platformatic.dev/
|
|
161
|
+
$schema: `https://schemas.platformatic.dev/@platformatic/runtime/${this.platformaticVersion}.json`,
|
|
157
162
|
entrypoint: this.entryPoint.name,
|
|
158
|
-
|
|
159
|
-
hotReload: true,
|
|
163
|
+
watch: true,
|
|
160
164
|
autoload: {
|
|
161
165
|
path: 'services',
|
|
162
|
-
exclude: ['docs']
|
|
166
|
+
exclude: ['docs'],
|
|
163
167
|
},
|
|
164
168
|
server: {
|
|
165
169
|
hostname: '{PLT_SERVER_HOSTNAME}',
|
|
166
170
|
port: '{PORT}',
|
|
167
171
|
logger: {
|
|
168
|
-
level: '{PLT_SERVER_LOGGER_LEVEL}'
|
|
169
|
-
}
|
|
172
|
+
level: '{PLT_SERVER_LOGGER_LEVEL}',
|
|
173
|
+
},
|
|
170
174
|
},
|
|
171
|
-
managementApi: '{PLT_MANAGEMENT_API}'
|
|
175
|
+
managementApi: '{PLT_MANAGEMENT_API}',
|
|
172
176
|
}
|
|
173
177
|
|
|
174
178
|
return config
|
|
@@ -182,28 +186,28 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
182
186
|
this.addEnvVars({
|
|
183
187
|
...this.config.env,
|
|
184
188
|
...this.getRuntimeEnv(),
|
|
185
|
-
...servicesEnv
|
|
189
|
+
...servicesEnv,
|
|
186
190
|
})
|
|
187
191
|
|
|
188
192
|
this.addFile({
|
|
189
193
|
path: '',
|
|
190
194
|
file: '.env',
|
|
191
|
-
contents: envObjectToString(this.config.env)
|
|
195
|
+
contents: envObjectToString(this.config.env),
|
|
192
196
|
})
|
|
193
197
|
|
|
194
198
|
this.addFile({
|
|
195
199
|
path: '',
|
|
196
200
|
file: '.env.sample',
|
|
197
|
-
contents: envObjectToString(this.config.env)
|
|
201
|
+
contents: envObjectToString(this.config.env),
|
|
198
202
|
})
|
|
199
203
|
|
|
200
204
|
if (!this.existingConfig) {
|
|
201
|
-
this.addFile({ path: '', file: 'README.md', contents: await readFile(join(__dirname, 'README.md')) })
|
|
205
|
+
this.addFile({ path: '', file: 'README.md', contents: await readFile(join(__dirname, 'README.md'), 'utf-8') })
|
|
202
206
|
}
|
|
203
207
|
|
|
204
208
|
return {
|
|
205
209
|
targetDirectory: this.targetDirectory,
|
|
206
|
-
env: servicesEnv
|
|
210
|
+
env: servicesEnv,
|
|
207
211
|
}
|
|
208
212
|
}
|
|
209
213
|
|
|
@@ -225,7 +229,10 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
225
229
|
name: 'typescript',
|
|
226
230
|
message: 'Do you want to use TypeScript?',
|
|
227
231
|
default: false,
|
|
228
|
-
choices: [
|
|
232
|
+
choices: [
|
|
233
|
+
{ name: 'yes', value: true },
|
|
234
|
+
{ name: 'no', value: false },
|
|
235
|
+
],
|
|
229
236
|
})
|
|
230
237
|
|
|
231
238
|
if (this.existingConfig) {
|
|
@@ -237,7 +244,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
237
244
|
type: 'input',
|
|
238
245
|
name: 'port',
|
|
239
246
|
default: 3042,
|
|
240
|
-
message: 'What port do you want to use?'
|
|
247
|
+
message: 'What port do you want to use?',
|
|
241
248
|
})
|
|
242
249
|
}
|
|
243
250
|
|
|
@@ -252,11 +259,11 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
252
259
|
}
|
|
253
260
|
|
|
254
261
|
setServicesConfig (configToOverride) {
|
|
255
|
-
this.services.forEach(
|
|
262
|
+
this.services.forEach(service => {
|
|
256
263
|
const originalConfig = service.config
|
|
257
264
|
service.setConfig({
|
|
258
265
|
...originalConfig,
|
|
259
|
-
...configToOverride
|
|
266
|
+
...configToOverride,
|
|
260
267
|
})
|
|
261
268
|
})
|
|
262
269
|
}
|
|
@@ -267,12 +274,12 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
267
274
|
// Propagate TypeScript
|
|
268
275
|
svc.service.setConfig({
|
|
269
276
|
...svc.service.config,
|
|
270
|
-
typescript: this.config.typescript
|
|
277
|
+
typescript: this.config.typescript,
|
|
271
278
|
})
|
|
272
279
|
const svcEnv = await svc.service.prepare()
|
|
273
280
|
servicesEnv = {
|
|
274
281
|
...servicesEnv,
|
|
275
|
-
...svcEnv.env
|
|
282
|
+
...svcEnv.env,
|
|
276
283
|
}
|
|
277
284
|
}
|
|
278
285
|
return servicesEnv
|
|
@@ -288,7 +295,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
288
295
|
|
|
289
296
|
getRuntimeEnv () {
|
|
290
297
|
return {
|
|
291
|
-
PORT: this.config.port
|
|
298
|
+
PORT: this.config.port,
|
|
292
299
|
}
|
|
293
300
|
}
|
|
294
301
|
|
|
@@ -306,9 +313,11 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
306
313
|
|
|
307
314
|
async loadFromDir () {
|
|
308
315
|
const output = {
|
|
309
|
-
services: []
|
|
316
|
+
services: [],
|
|
310
317
|
}
|
|
311
|
-
const runtimePkgConfigFileData = JSON.parse(
|
|
318
|
+
const runtimePkgConfigFileData = JSON.parse(
|
|
319
|
+
await readFile(join(this.targetDirectory, 'platformatic.json'), 'utf-8')
|
|
320
|
+
)
|
|
312
321
|
const servicesPath = join(this.targetDirectory, runtimePkgConfigFileData.autoload.path)
|
|
313
322
|
|
|
314
323
|
// load all services
|
|
@@ -324,7 +333,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
324
333
|
const template = servicePltJson.module || getServiceTemplateFromSchemaUrl(servicePltJson.$schema)
|
|
325
334
|
const Generator = await this._getGeneratorForTemplate(currentServicePath, template)
|
|
326
335
|
const instance = new Generator({
|
|
327
|
-
logger: this.logger
|
|
336
|
+
logger: this.logger,
|
|
328
337
|
})
|
|
329
338
|
this.addService(instance, s)
|
|
330
339
|
output.services.push(await instance.loadFromDir(s, this.targetDirectory))
|
|
@@ -341,11 +350,11 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
341
350
|
const currrentPackageJson = JSON.parse(await readFile(join(this.targetDirectory, 'package.json'), 'utf-8'))
|
|
342
351
|
const currentRuntimeDependencies = currrentPackageJson.dependencies
|
|
343
352
|
// check all services are present with the same template
|
|
344
|
-
const allCurrentServicesNames = this.services.map(
|
|
345
|
-
const allNewServicesNames = newConfig.services.map(
|
|
353
|
+
const allCurrentServicesNames = this.services.map(s => s.name)
|
|
354
|
+
const allNewServicesNames = newConfig.services.map(s => s.name)
|
|
346
355
|
// load dotenv tool
|
|
347
356
|
const envTool = new DotEnvTool({
|
|
348
|
-
path: join(this.targetDirectory, '.env')
|
|
357
|
+
path: join(this.targetDirectory, '.env'),
|
|
349
358
|
})
|
|
350
359
|
|
|
351
360
|
await envTool.load()
|
|
@@ -356,24 +365,25 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
356
365
|
// handle service delete
|
|
357
366
|
|
|
358
367
|
// delete env variables
|
|
359
|
-
const s = this.services.find(
|
|
368
|
+
const s = this.services.find(f => f.name === removedService)
|
|
360
369
|
const allKeys = envTool.getKeys()
|
|
361
|
-
allKeys.forEach(
|
|
370
|
+
allKeys.forEach(k => {
|
|
362
371
|
if (k.startsWith(`PLT_${s.service.config.envPrefix}`)) {
|
|
363
372
|
envTool.deleteKey(k)
|
|
364
373
|
}
|
|
365
374
|
})
|
|
366
375
|
|
|
367
376
|
// delete dependencies
|
|
368
|
-
const servicePackageJson = JSON.parse(
|
|
377
|
+
const servicePackageJson = JSON.parse(
|
|
378
|
+
await readFile(join(this.targetDirectory, 'services', s.name, 'platformatic.json'), 'utf-8')
|
|
379
|
+
)
|
|
369
380
|
if (servicePackageJson.plugins && servicePackageJson.plugins.packages) {
|
|
370
|
-
servicePackageJson.plugins.packages
|
|
371
|
-
.
|
|
372
|
-
|
|
373
|
-
})
|
|
381
|
+
servicePackageJson.plugins.packages.forEach(p => {
|
|
382
|
+
delete currrentPackageJson.dependencies[p.name]
|
|
383
|
+
})
|
|
374
384
|
}
|
|
375
385
|
// delete directory
|
|
376
|
-
await
|
|
386
|
+
await safeRemove(join(this.targetDirectory, 'services', s.name))
|
|
377
387
|
}
|
|
378
388
|
// throw new CannotRemoveServiceOnUpdateError(removedServices.join(', '))
|
|
379
389
|
}
|
|
@@ -381,15 +391,18 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
381
391
|
// handle new services
|
|
382
392
|
for (const newService of newConfig.services) {
|
|
383
393
|
// create generator for the service
|
|
384
|
-
const ServiceGenerator = await this._getGeneratorForTemplate(
|
|
394
|
+
const ServiceGenerator = await this._getGeneratorForTemplate(
|
|
395
|
+
join(this.targetDirectory, 'package.json'),
|
|
396
|
+
newService.template
|
|
397
|
+
)
|
|
385
398
|
const serviceInstance = new ServiceGenerator({
|
|
386
|
-
logger: this.logger
|
|
399
|
+
logger: this.logger,
|
|
387
400
|
})
|
|
388
401
|
const baseConfig = {
|
|
389
402
|
isRuntimeContext: true,
|
|
390
403
|
targetDirectory: join(this.targetDirectory, 'services', newService.name),
|
|
391
404
|
serviceName: newService.name,
|
|
392
|
-
plugin: true
|
|
405
|
+
plugin: true,
|
|
393
406
|
}
|
|
394
407
|
if (allCurrentServicesNames.includes(newService.name)) {
|
|
395
408
|
// update existing services env values
|
|
@@ -398,15 +411,15 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
398
411
|
|
|
399
412
|
// handle service's plugin differences
|
|
400
413
|
const oldServiceMetadata = await serviceInstance.loadFromDir(newService.name, this.targetDirectory)
|
|
401
|
-
const oldServicePackages = oldServiceMetadata.plugins.map(
|
|
402
|
-
const newServicePackages = newService.plugins.map(
|
|
414
|
+
const oldServicePackages = oldServiceMetadata.plugins.map(meta => meta.name)
|
|
415
|
+
const newServicePackages = newService.plugins.map(meta => meta.name)
|
|
403
416
|
const pluginsToRemove = getArrayDifference(oldServicePackages, newServicePackages)
|
|
404
|
-
pluginsToRemove.forEach(
|
|
417
|
+
pluginsToRemove.forEach(p => delete currentRuntimeDependencies[p])
|
|
405
418
|
} else {
|
|
406
419
|
// add service to the generator
|
|
407
420
|
this.services.push({
|
|
408
421
|
name: newService.name,
|
|
409
|
-
service: serviceInstance
|
|
422
|
+
service: serviceInstance,
|
|
410
423
|
})
|
|
411
424
|
}
|
|
412
425
|
serviceInstance.setConfig(baseConfig)
|
|
@@ -431,7 +444,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
431
444
|
await serviceInstance.writeFiles()
|
|
432
445
|
// cleanup runtime env removing keys not present anymore in service plugins
|
|
433
446
|
const allKeys = envTool.getKeys()
|
|
434
|
-
allKeys.forEach(
|
|
447
|
+
allKeys.forEach(k => {
|
|
435
448
|
if (k.startsWith(`${serviceEnvPrefix}_FST_PLUGIN`) && !runtimeAddedEnvKeys.includes(k)) {
|
|
436
449
|
envTool.deleteKey(k)
|
|
437
450
|
}
|
|
@@ -445,26 +458,28 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
445
458
|
// update runtime package.json dependencies
|
|
446
459
|
currrentPackageJson.dependencies = {
|
|
447
460
|
...currrentPackageJson.dependencies,
|
|
448
|
-
...allServicesDependencies
|
|
461
|
+
...allServicesDependencies,
|
|
449
462
|
}
|
|
450
463
|
this.addFile({
|
|
451
464
|
path: '',
|
|
452
465
|
file: 'package.json',
|
|
453
|
-
contents: JSON.stringify(currrentPackageJson, null, 2)
|
|
466
|
+
contents: JSON.stringify(currrentPackageJson, null, 2),
|
|
454
467
|
})
|
|
455
468
|
|
|
456
469
|
// set new entrypoint if specified
|
|
457
470
|
const newEntrypoint = newConfig.entrypoint
|
|
458
471
|
if (newEntrypoint) {
|
|
459
472
|
// load platformatic.json runtime config
|
|
460
|
-
const runtimePkgConfigFileData = JSON.parse(
|
|
473
|
+
const runtimePkgConfigFileData = JSON.parse(
|
|
474
|
+
await readFile(join(this.targetDirectory, 'platformatic.json'), 'utf-8')
|
|
475
|
+
)
|
|
461
476
|
|
|
462
477
|
this.setEntryPoint(newEntrypoint)
|
|
463
478
|
runtimePkgConfigFileData.entrypoint = newEntrypoint
|
|
464
479
|
this.addFile({
|
|
465
480
|
path: '',
|
|
466
481
|
file: 'platformatic.json',
|
|
467
|
-
contents: JSON.stringify(runtimePkgConfigFileData, null, 2)
|
|
482
|
+
contents: JSON.stringify(runtimePkgConfigFileData, null, 2),
|
|
468
483
|
})
|
|
469
484
|
}
|
|
470
485
|
await this.writeFiles()
|
package/lib/logger.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { join } = require('node:path')
|
|
4
|
+
const { isatty } = require('node:tty')
|
|
5
|
+
|
|
6
|
+
const pino = require('pino')
|
|
7
|
+
const pretty = require('pino-pretty')
|
|
8
|
+
|
|
9
|
+
function createLogger (config, runtimeLogsDir) {
|
|
10
|
+
const loggerConfig = { ...config.server?.logger }
|
|
11
|
+
const cliStream = isatty(1) ? pretty() : pino.destination(1)
|
|
12
|
+
|
|
13
|
+
if (!config.managementApi) {
|
|
14
|
+
return [pino(loggerConfig, cliStream), cliStream]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const multiStream = pino.multistream([
|
|
18
|
+
{ stream: cliStream, level: loggerConfig.level || 'info' },
|
|
19
|
+
])
|
|
20
|
+
|
|
21
|
+
if (loggerConfig.transport) {
|
|
22
|
+
const transport = pino.transport(loggerConfig.transport)
|
|
23
|
+
multiStream.add({ level: loggerConfig.level || 'info', stream: transport })
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (config.managementApi) {
|
|
27
|
+
const logsFileMb = 5
|
|
28
|
+
const logsLimitMb = config.managementApi?.logs?.maxSize || 200
|
|
29
|
+
|
|
30
|
+
let logsLimitCount = Math.ceil(logsLimitMb / logsFileMb) - 1
|
|
31
|
+
if (logsLimitCount < 1) {
|
|
32
|
+
logsLimitCount = 1
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const pinoRoll = pino.transport({
|
|
36
|
+
target: 'pino-roll',
|
|
37
|
+
options: {
|
|
38
|
+
file: join(runtimeLogsDir, 'logs'),
|
|
39
|
+
mode: 0o600,
|
|
40
|
+
size: logsFileMb + 'm',
|
|
41
|
+
mkdir: true,
|
|
42
|
+
fsync: true,
|
|
43
|
+
limit: {
|
|
44
|
+
count: logsLimitCount,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
multiStream.add({ level: 'trace', stream: pinoRoll })
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return [pino({ level: 'trace' }, multiStream), multiStream]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = { createLogger }
|
package/lib/management-api.js
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { tmpdir } = require('node:os')
|
|
4
|
-
const { platform } = require('node:os')
|
|
3
|
+
const { platform, tmpdir } = require('node:os')
|
|
5
4
|
const { join } = require('node:path')
|
|
6
|
-
const {
|
|
5
|
+
const { createDirectory, safeRemove } = require('@platformatic/utils')
|
|
6
|
+
|
|
7
7
|
const fastify = require('fastify')
|
|
8
8
|
const ws = require('ws')
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
const errors = require('./errors')
|
|
11
|
+
const { getRuntimeLogsDir } = require('./utils')
|
|
11
12
|
|
|
12
13
|
const PLATFORMATIC_TMP_DIR = join(tmpdir(), 'platformatic', 'runtimes')
|
|
13
14
|
|
|
14
15
|
async function managementApiPlugin (app, opts) {
|
|
15
16
|
app.log.warn(
|
|
16
17
|
'Runtime Management API is in the experimental stage. ' +
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
'The feature is not subject to semantic versioning rules. ' +
|
|
19
|
+
'Non-backward compatible changes or removal may occur in any future release. ' +
|
|
20
|
+
'Use of the feature is not recommended in production environments.'
|
|
20
21
|
)
|
|
21
22
|
|
|
22
23
|
const runtime = opts.runtime
|
|
@@ -35,7 +36,7 @@ async function managementApiPlugin (app, opts) {
|
|
|
35
36
|
|
|
36
37
|
app.post('/stop', async () => {
|
|
37
38
|
app.log.debug('stop services')
|
|
38
|
-
await runtime.close()
|
|
39
|
+
await runtime.close(true)
|
|
39
40
|
})
|
|
40
41
|
|
|
41
42
|
app.post('/reload', async () => {
|
|
@@ -47,40 +48,40 @@ async function managementApiPlugin (app, opts) {
|
|
|
47
48
|
return runtime.getServices()
|
|
48
49
|
})
|
|
49
50
|
|
|
50
|
-
app.get('/services/:id', async
|
|
51
|
+
app.get('/services/:id', async request => {
|
|
51
52
|
const { id } = request.params
|
|
52
53
|
app.log.debug('get service details', { id })
|
|
53
54
|
return runtime.getServiceDetails(id)
|
|
54
55
|
})
|
|
55
56
|
|
|
56
|
-
app.get('/services/:id/config', async
|
|
57
|
+
app.get('/services/:id/config', async request => {
|
|
57
58
|
const { id } = request.params
|
|
58
59
|
app.log.debug('get service config', { id })
|
|
59
60
|
return runtime.getServiceConfig(id)
|
|
60
61
|
})
|
|
61
62
|
|
|
62
|
-
app.get('/services/:id/openapi-schema', async
|
|
63
|
+
app.get('/services/:id/openapi-schema', async request => {
|
|
63
64
|
const { id } = request.params
|
|
64
65
|
app.log.debug('get openapi-schema', { id })
|
|
65
66
|
return runtime.getServiceOpenapiSchema(id)
|
|
66
67
|
})
|
|
67
68
|
|
|
68
|
-
app.get('/services/:id/graphql-schema', async
|
|
69
|
+
app.get('/services/:id/graphql-schema', async request => {
|
|
69
70
|
const { id } = request.params
|
|
70
71
|
app.log.debug('get graphql-schema', { id })
|
|
71
72
|
return runtime.getServiceGraphqlSchema(id)
|
|
72
73
|
})
|
|
73
74
|
|
|
74
|
-
app.post('/services/:id/start', async
|
|
75
|
+
app.post('/services/:id/start', async request => {
|
|
75
76
|
const { id } = request.params
|
|
76
77
|
app.log.debug('start service', { id })
|
|
77
78
|
await runtime.startService(id)
|
|
78
79
|
})
|
|
79
80
|
|
|
80
|
-
app.post('/services/:id/stop', async
|
|
81
|
+
app.post('/services/:id/stop', async request => {
|
|
81
82
|
const { id } = request.params
|
|
82
83
|
app.log.debug('stop service', { id })
|
|
83
|
-
await runtime.
|
|
84
|
+
await runtime._stopService(id)
|
|
84
85
|
})
|
|
85
86
|
|
|
86
87
|
app.all('/services/:id/proxy/*', async (request, reply) => {
|
|
@@ -97,27 +98,22 @@ async function managementApiPlugin (app, opts) {
|
|
|
97
98
|
url: requestUrl || '/',
|
|
98
99
|
headers: request.headers,
|
|
99
100
|
query: request.query,
|
|
100
|
-
body: request.body
|
|
101
|
+
body: request.body,
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
const res = await runtime.inject(id, injectParams)
|
|
104
105
|
|
|
105
|
-
reply
|
|
106
|
-
.code(res.statusCode)
|
|
107
|
-
.headers(res.headers)
|
|
108
|
-
.send(res.body)
|
|
106
|
+
reply.code(res.statusCode).headers(res.headers).send(res.body)
|
|
109
107
|
})
|
|
110
108
|
|
|
111
|
-
app.get('/metrics/live', { websocket: true }, async
|
|
109
|
+
app.get('/metrics/live', { websocket: true }, async socket => {
|
|
112
110
|
const cachedMetrics = runtime.getCachedMetrics()
|
|
113
111
|
if (cachedMetrics.length > 0) {
|
|
114
|
-
const serializedMetrics = cachedMetrics
|
|
115
|
-
.map((metric) => JSON.stringify(metric))
|
|
116
|
-
.join('\n')
|
|
112
|
+
const serializedMetrics = cachedMetrics.map(metric => JSON.stringify(metric)).join('\n')
|
|
117
113
|
socket.send(serializedMetrics + '\n')
|
|
118
114
|
}
|
|
119
115
|
|
|
120
|
-
const eventHandler =
|
|
116
|
+
const eventHandler = metrics => {
|
|
121
117
|
const serializedMetrics = JSON.stringify(metrics)
|
|
122
118
|
socket.send(serializedMetrics + '\n')
|
|
123
119
|
}
|
|
@@ -147,7 +143,7 @@ async function managementApiPlugin (app, opts) {
|
|
|
147
143
|
runtime.pipeLogsStream(stream, req.log, startLogId)
|
|
148
144
|
})
|
|
149
145
|
|
|
150
|
-
app.get('/logs/indexes', async
|
|
146
|
+
app.get('/logs/indexes', async req => {
|
|
151
147
|
const returnAllIds = req.query.all === 'true'
|
|
152
148
|
|
|
153
149
|
if (returnAllIds) {
|
|
@@ -168,16 +164,10 @@ async function managementApiPlugin (app, opts) {
|
|
|
168
164
|
|
|
169
165
|
reply.hijack()
|
|
170
166
|
|
|
171
|
-
runtime.pipeLogsStream(
|
|
172
|
-
reply.raw,
|
|
173
|
-
req.log,
|
|
174
|
-
startLogId,
|
|
175
|
-
endLogId,
|
|
176
|
-
runtimePID
|
|
177
|
-
)
|
|
167
|
+
runtime.pipeLogsStream(reply.raw, req.log, startLogId, endLogId, runtimePID)
|
|
178
168
|
})
|
|
179
169
|
|
|
180
|
-
app.get('/logs/:id', async
|
|
170
|
+
app.get('/logs/:id', async req => {
|
|
181
171
|
const logId = parseInt(req.params.id)
|
|
182
172
|
const runtimePID = parseInt(req.query.pid) || process.pid
|
|
183
173
|
|
|
@@ -186,10 +176,7 @@ async function managementApiPlugin (app, opts) {
|
|
|
186
176
|
throw new errors.LogFileNotFound(logId)
|
|
187
177
|
}
|
|
188
178
|
|
|
189
|
-
const logFileStream = await runtime.getLogFileStream(
|
|
190
|
-
logId,
|
|
191
|
-
runtimePID
|
|
192
|
-
)
|
|
179
|
+
const logFileStream = await runtime.getLogFileStream(logId, runtimePID)
|
|
193
180
|
return logFileStream
|
|
194
181
|
})
|
|
195
182
|
}
|
|
@@ -200,13 +187,11 @@ async function startManagementApi (runtime, configManager) {
|
|
|
200
187
|
try {
|
|
201
188
|
const runtimePIDDir = join(PLATFORMATIC_TMP_DIR, runtimePID.toString())
|
|
202
189
|
if (platform() !== 'win32') {
|
|
203
|
-
await
|
|
204
|
-
await mkdir(runtimePIDDir, { recursive: true })
|
|
190
|
+
await createDirectory(runtimePIDDir, true)
|
|
205
191
|
}
|
|
206
192
|
|
|
207
193
|
const runtimeLogsDir = getRuntimeLogsDir(configManager.dirname, process.pid)
|
|
208
|
-
await
|
|
209
|
-
await mkdir(runtimeLogsDir, { recursive: true })
|
|
194
|
+
await createDirectory(runtimeLogsDir, true)
|
|
210
195
|
|
|
211
196
|
let socketPath = null
|
|
212
197
|
if (platform() === 'win32') {
|
|
@@ -221,13 +206,13 @@ async function startManagementApi (runtime, configManager) {
|
|
|
221
206
|
|
|
222
207
|
managementApi.addHook('onClose', async () => {
|
|
223
208
|
if (platform() !== 'win32') {
|
|
224
|
-
await
|
|
209
|
+
await safeRemove(runtimePIDDir)
|
|
225
210
|
}
|
|
226
211
|
})
|
|
227
212
|
|
|
228
213
|
await managementApi.listen({ path: socketPath })
|
|
229
214
|
return managementApi
|
|
230
|
-
|
|
215
|
+
/* c8 ignore next 4 */
|
|
231
216
|
} catch (err) {
|
|
232
217
|
console.error(err)
|
|
233
218
|
process.exit(1)
|