@platformatic/runtime 2.74.3 → 3.0.0-alpha.2
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 +1 -1
- package/index.d.ts +70 -21
- package/index.js +151 -18
- package/lib/config.js +160 -219
- package/lib/errors.js +150 -108
- package/lib/{generator/runtime-generator.js → generator.js} +36 -53
- package/lib/logger.js +7 -30
- package/lib/management-api.js +6 -56
- package/lib/runtime.js +233 -264
- package/lib/schema.js +2 -1
- package/lib/shared-http-cache.js +1 -1
- package/lib/upgrade.js +6 -4
- package/lib/utils.js +1 -48
- package/lib/worker/app.js +52 -68
- package/lib/worker/itc.js +16 -4
- package/lib/worker/main.js +6 -3
- package/lib/worker/messaging.js +2 -2
- package/package.json +22 -30
- package/schema.json +2 -1
- package/help/compile.txt +0 -8
- package/help/help.txt +0 -5
- package/help/start.txt +0 -21
- package/index.test-d.ts +0 -41
- package/lib/build-server.js +0 -67
- package/lib/compile.js +0 -108
- package/lib/generator/README.md +0 -32
- package/lib/generator/errors.js +0 -10
- package/lib/generator/runtime-generator.d.ts +0 -37
- package/lib/start.js +0 -211
- package/lib/worker/default-stackable.js +0 -33
- package/runtime.mjs +0 -54
package/lib/errors.js
CHANGED
|
@@ -4,113 +4,155 @@ const createError = require('@fastify/error')
|
|
|
4
4
|
|
|
5
5
|
const ERROR_PREFIX = 'PLT_RUNTIME'
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
7
|
+
const AddressInUseError = createError(
|
|
8
|
+
`${ERROR_PREFIX}_EADDR_IN_USE`,
|
|
9
|
+
'The current port is in use by another application'
|
|
10
|
+
)
|
|
11
|
+
const RuntimeExitedError = createError(
|
|
12
|
+
`${ERROR_PREFIX}_RUNTIME_EXIT`,
|
|
13
|
+
'The runtime exited before the operation completed'
|
|
14
|
+
)
|
|
15
|
+
const RuntimeAbortedError = createError(`${ERROR_PREFIX}_RUNTIME_ABORT`, 'The runtime aborted the operation')
|
|
16
|
+
// The following two use the same code as we only need to differentiate the label
|
|
17
|
+
const ServiceExitedError = createError(
|
|
18
|
+
`${ERROR_PREFIX}_SERVICE_EXIT`,
|
|
19
|
+
'The service "%s" exited prematurely with error code %d'
|
|
20
|
+
)
|
|
21
|
+
const WorkerExitedError = createError(
|
|
22
|
+
`${ERROR_PREFIX}_SERVICE_EXIT`,
|
|
23
|
+
'The worker %s of the service "%s" exited prematurely with error code %d'
|
|
24
|
+
)
|
|
25
|
+
const UnknownRuntimeAPICommandError = createError(
|
|
26
|
+
`${ERROR_PREFIX}_UNKNOWN_RUNTIME_API_COMMAND`,
|
|
27
|
+
'Unknown Runtime API command "%s"'
|
|
28
|
+
)
|
|
29
|
+
const ServiceNotFoundError = createError(
|
|
30
|
+
`${ERROR_PREFIX}_SERVICE_NOT_FOUND`,
|
|
31
|
+
'Service %s not found. Available services are: %s'
|
|
32
|
+
)
|
|
33
|
+
const WorkerNotFoundError = createError(
|
|
34
|
+
`${ERROR_PREFIX}_WORKER_NOT_FOUND`,
|
|
35
|
+
'Worker %s of service %s not found. Available services are: %s'
|
|
36
|
+
)
|
|
37
|
+
const ServiceNotStartedError = createError(`${ERROR_PREFIX}_SERVICE_NOT_STARTED`, "Service with id '%s' is not started")
|
|
38
|
+
const ServiceStartTimeoutError = createError(
|
|
39
|
+
`${ERROR_PREFIX}_SERVICE_START_TIMEOUT`,
|
|
40
|
+
"Service with id '%s' failed to start in %dms."
|
|
41
|
+
)
|
|
42
|
+
const FailedToRetrieveOpenAPISchemaError = createError(
|
|
43
|
+
`${ERROR_PREFIX}_FAILED_TO_RETRIEVE_OPENAPI_SCHEMA`,
|
|
44
|
+
'Failed to retrieve OpenAPI schema for service with id "%s": %s'
|
|
45
|
+
)
|
|
46
|
+
const FailedToRetrieveGraphQLSchemaError = createError(
|
|
47
|
+
`${ERROR_PREFIX}_FAILED_TO_RETRIEVE_GRAPHQL_SCHEMA`,
|
|
48
|
+
'Failed to retrieve GraphQL schema for service with id "%s": %s'
|
|
49
|
+
)
|
|
50
|
+
const FailedToRetrieveMetaError = createError(
|
|
51
|
+
`${ERROR_PREFIX}_FAILED_TO_RETRIEVE_META`,
|
|
52
|
+
'Failed to retrieve metadata for service with id "%s": %s'
|
|
53
|
+
)
|
|
54
|
+
const FailedToRetrieveMetricsError = createError(
|
|
55
|
+
`${ERROR_PREFIX}_FAILED_TO_RETRIEVE_METRICS`,
|
|
56
|
+
'Failed to retrieve metrics for service with id "%s": %s'
|
|
57
|
+
)
|
|
58
|
+
const FailedToRetrieveHealthError = createError(
|
|
59
|
+
`${ERROR_PREFIX}_FAILED_TO_RETRIEVE_HEALTH`,
|
|
60
|
+
'Failed to retrieve health for service with id "%s": %s'
|
|
61
|
+
)
|
|
62
|
+
const FailedToPerformCustomHealthCheckError = createError(
|
|
63
|
+
`${ERROR_PREFIX}_FAILED_TO_PERFORM_CUSTOM_HEALTH_CHECK`,
|
|
64
|
+
'Failed to perform custom healthcheck for service with id "%s": %s'
|
|
65
|
+
)
|
|
66
|
+
const FailedToPerformCustomReadinessCheckError = createError(
|
|
67
|
+
`${ERROR_PREFIX}_FAILED_TO_PERFORM_CUSTOM_READINESS_CHECK`,
|
|
68
|
+
'Failed to perform custom readiness check for service with id "%s": %s'
|
|
69
|
+
)
|
|
70
|
+
const ApplicationAlreadyStartedError = createError(
|
|
71
|
+
`${ERROR_PREFIX}_APPLICATION_ALREADY_STARTED`,
|
|
72
|
+
'Application is already started'
|
|
73
|
+
)
|
|
74
|
+
const ApplicationNotStartedError = createError(
|
|
75
|
+
`${ERROR_PREFIX}_APPLICATION_NOT_STARTED`,
|
|
76
|
+
'Application has not been started'
|
|
77
|
+
)
|
|
78
|
+
const ConfigPathMustBeStringError = createError(
|
|
79
|
+
`${ERROR_PREFIX}_CONFIG_PATH_MUST_BE_STRING`,
|
|
80
|
+
'Config path must be a string'
|
|
81
|
+
)
|
|
82
|
+
const NoConfigFileFoundError = createError(
|
|
83
|
+
`${ERROR_PREFIX}_NO_CONFIG_FILE_FOUND`,
|
|
84
|
+
"No config file found for service '%s'"
|
|
85
|
+
)
|
|
86
|
+
const InvalidEntrypointError = createError(
|
|
87
|
+
`${ERROR_PREFIX}_INVALID_ENTRYPOINT`,
|
|
88
|
+
"Invalid entrypoint: '%s' does not exist"
|
|
89
|
+
)
|
|
90
|
+
const MissingEntrypointError = createError(`${ERROR_PREFIX}_MISSING_ENTRYPOINT`, 'Missing application entrypoint.')
|
|
91
|
+
const InvalidServicesWithWebError = createError(
|
|
92
|
+
`${ERROR_PREFIX}_INVALID_SERVICES_WITH_WEB`,
|
|
93
|
+
'The "services" property cannot be used when the "web" property is also defined'
|
|
94
|
+
)
|
|
95
|
+
const MissingDependencyError = createError(`${ERROR_PREFIX}_MISSING_DEPENDENCY`, 'Missing dependency: "%s"')
|
|
96
|
+
const InspectAndInspectBrkError = createError(
|
|
97
|
+
`${ERROR_PREFIX}_INSPECT_AND_INSPECT_BRK`,
|
|
98
|
+
'--inspect and --inspect-brk cannot be used together'
|
|
99
|
+
)
|
|
100
|
+
const InspectorPortError = createError(
|
|
101
|
+
`${ERROR_PREFIX}_INSPECTOR_PORT`,
|
|
102
|
+
'Inspector port must be 0 or in range 1024 to 65535'
|
|
103
|
+
)
|
|
104
|
+
const InspectorHostError = createError(`${ERROR_PREFIX}_INSPECTOR_HOST`, 'Inspector host cannot be empty')
|
|
105
|
+
const CannotMapSpecifierToAbsolutePathError = createError(
|
|
106
|
+
`${ERROR_PREFIX}_CANNOT_MAP_SPECIFIER_TO_ABSOLUTE_PATH`,
|
|
107
|
+
'Cannot map "%s" to an absolute path'
|
|
108
|
+
)
|
|
109
|
+
const NodeInspectorFlagsNotSupportedError = createError(
|
|
110
|
+
`${ERROR_PREFIX}_NODE_INSPECTOR_FLAGS_NOT_SUPPORTED`,
|
|
111
|
+
"The Node.js inspector flags are not supported. Please use 'platformatic start --inspect' instead."
|
|
112
|
+
)
|
|
113
|
+
const FailedToUnlinkManagementApiSocket = createError(
|
|
114
|
+
`${ERROR_PREFIX}_FAILED_TO_UNLINK_MANAGEMENT_API_SOCKET`,
|
|
115
|
+
'Failed to unlink management API socket "%s"'
|
|
116
|
+
)
|
|
117
|
+
const LogFileNotFound = createError(`${ERROR_PREFIX}_LOG_FILE_NOT_FOUND`, 'Log file with index %s not found', 404)
|
|
118
|
+
const WorkerIsRequired = createError(`${ERROR_PREFIX}_REQUIRED_WORKER`, 'The worker parameter is required')
|
|
119
|
+
const InvalidArgumentError = createError(`${ERROR_PREFIX}_INVALID_ARGUMENT`, 'Invalid argument: "%s"')
|
|
120
|
+
const MessagingError = createError(`${ERROR_PREFIX}_MESSAGING_ERROR`, 'Cannot send a message to service "%s": %s')
|
|
110
121
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
122
|
+
module.exports = {
|
|
123
|
+
AddressInUseError,
|
|
124
|
+
RuntimeExitedError,
|
|
125
|
+
RuntimeAbortedError,
|
|
126
|
+
ServiceExitedError,
|
|
127
|
+
WorkerExitedError,
|
|
128
|
+
UnknownRuntimeAPICommandError,
|
|
129
|
+
ServiceNotFoundError,
|
|
130
|
+
WorkerNotFoundError,
|
|
131
|
+
ServiceNotStartedError,
|
|
132
|
+
ServiceStartTimeoutError,
|
|
133
|
+
FailedToRetrieveOpenAPISchemaError,
|
|
134
|
+
FailedToRetrieveGraphQLSchemaError,
|
|
135
|
+
FailedToRetrieveMetaError,
|
|
136
|
+
FailedToRetrieveMetricsError,
|
|
137
|
+
FailedToRetrieveHealthError,
|
|
138
|
+
FailedToPerformCustomHealthCheckError,
|
|
139
|
+
FailedToPerformCustomReadinessCheckError,
|
|
140
|
+
ApplicationAlreadyStartedError,
|
|
141
|
+
ApplicationNotStartedError,
|
|
142
|
+
ConfigPathMustBeStringError,
|
|
143
|
+
NoConfigFileFoundError,
|
|
144
|
+
InvalidEntrypointError,
|
|
145
|
+
MissingEntrypointError,
|
|
146
|
+
InvalidServicesWithWebError,
|
|
147
|
+
MissingDependencyError,
|
|
148
|
+
InspectAndInspectBrkError,
|
|
149
|
+
InspectorPortError,
|
|
150
|
+
InspectorHostError,
|
|
151
|
+
CannotMapSpecifierToAbsolutePathError,
|
|
152
|
+
NodeInspectorFlagsNotSupportedError,
|
|
153
|
+
FailedToUnlinkManagementApiSocket,
|
|
154
|
+
LogFileNotFound,
|
|
155
|
+
WorkerIsRequired,
|
|
156
|
+
InvalidArgumentError,
|
|
157
|
+
MessagingError
|
|
116
158
|
}
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const createError = require('@fastify/error')
|
|
3
4
|
const { BaseGenerator } = require('@platformatic/generators')
|
|
4
|
-
const { NoEntryPointError, NoServiceNamedError } = require('./errors')
|
|
5
5
|
const { existsSync } = require('node:fs')
|
|
6
6
|
const { join, basename } = require('node:path')
|
|
7
7
|
const { envObjectToString } = require('@platformatic/generators/lib/utils')
|
|
8
8
|
const { readFile, readdir, stat } = require('node:fs/promises')
|
|
9
|
-
const {
|
|
10
|
-
const { platformaticRuntime } = require('../config')
|
|
9
|
+
const { transform } = require('./config')
|
|
11
10
|
const { getServiceTemplateFromSchemaUrl } = require('@platformatic/generators/lib/utils')
|
|
12
11
|
const { DotEnvTool } = require('dotenv-tool')
|
|
13
|
-
const { getArrayDifference } = require('
|
|
12
|
+
const { getArrayDifference } = require('./utils')
|
|
13
|
+
const { schema } = require('./schema')
|
|
14
14
|
const { pathToFileURL } = require('node:url')
|
|
15
|
-
const {
|
|
15
|
+
const {
|
|
16
|
+
safeRemove,
|
|
17
|
+
generateDashedName,
|
|
18
|
+
findConfigurationFile,
|
|
19
|
+
loadConfiguration,
|
|
20
|
+
loadConfigurationFile,
|
|
21
|
+
kMetadata,
|
|
22
|
+
defaultPackageManager
|
|
23
|
+
} = require('@platformatic/foundation')
|
|
16
24
|
const { createRequire } = require('node:module')
|
|
17
25
|
|
|
18
26
|
const wrappableProperties = {
|
|
@@ -27,9 +35,17 @@ const wrappableProperties = {
|
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
const engines = {
|
|
30
|
-
node: '
|
|
38
|
+
node: '>=22.18.0'
|
|
31
39
|
}
|
|
32
40
|
|
|
41
|
+
const ERROR_PREFIX = 'PLT_RUNTIME_GEN'
|
|
42
|
+
|
|
43
|
+
const NoServiceNamedError = createError(
|
|
44
|
+
`${ERROR_PREFIX}_NO_SERVICE_FOUND`,
|
|
45
|
+
"No service named '%s' has been added to this runtime."
|
|
46
|
+
)
|
|
47
|
+
const NoEntryPointError = createError(`${ERROR_PREFIX}_NO_ENTRYPOINT`, 'No entrypoint had been defined.')
|
|
48
|
+
|
|
33
49
|
function getRuntimeBaseEnvVars (config) {
|
|
34
50
|
return {
|
|
35
51
|
PLT_SERVER_HOSTNAME: '127.0.0.1',
|
|
@@ -50,7 +66,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
50
66
|
this.services = []
|
|
51
67
|
this.existingServices = []
|
|
52
68
|
this.entryPoint = null
|
|
53
|
-
this.packageManager = opts.packageManager ??
|
|
69
|
+
this.packageManager = opts.packageManager ?? defaultPackageManager
|
|
54
70
|
}
|
|
55
71
|
|
|
56
72
|
async addService (service, name) {
|
|
@@ -70,9 +86,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
70
86
|
service
|
|
71
87
|
})
|
|
72
88
|
|
|
73
|
-
|
|
74
|
-
service.setRuntime(this)
|
|
75
|
-
}
|
|
89
|
+
service.setRuntime(this)
|
|
76
90
|
}
|
|
77
91
|
|
|
78
92
|
setEntryPoint (entryPoint) {
|
|
@@ -108,13 +122,6 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
108
122
|
template.workspaces = [this.servicesFolder + '/*']
|
|
109
123
|
}
|
|
110
124
|
|
|
111
|
-
if (this.config.typescript) {
|
|
112
|
-
const typescriptVersion = JSON.parse(await readFile(join(__dirname, '..', '..', 'package.json'), 'utf-8'))
|
|
113
|
-
.devDependencies.typescript
|
|
114
|
-
template.scripts.clean = 'rm -fr ./dist'
|
|
115
|
-
template.scripts.build = 'platformatic compile'
|
|
116
|
-
template.devDependencies.typescript = typescriptVersion
|
|
117
|
-
}
|
|
118
125
|
return template
|
|
119
126
|
}
|
|
120
127
|
|
|
@@ -141,21 +148,19 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
141
148
|
return
|
|
142
149
|
}
|
|
143
150
|
this._hasCheckedForExistingConfig = true
|
|
144
|
-
const existingConfigFile =
|
|
145
|
-
this.runtimeConfig ?? (await ConfigManager.findConfigFile(this.targetDirectory, 'runtime'))
|
|
151
|
+
const existingConfigFile = this.runtimeConfig ?? (await findConfigurationFile(this.targetDirectory, 'runtime'))
|
|
146
152
|
if (existingConfigFile && existsSync(join(this.targetDirectory, existingConfigFile))) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
153
|
+
this.existingConfigRaw = await loadConfigurationFile(join(this.targetDirectory, existingConfigFile))
|
|
154
|
+
this.existingConfig = await loadConfiguration(join(this.targetDirectory, existingConfigFile), schema, {
|
|
155
|
+
transform,
|
|
156
|
+
ignoreProcessEnv: true
|
|
150
157
|
})
|
|
151
|
-
await configManager.parse()
|
|
152
158
|
|
|
153
|
-
|
|
154
|
-
this.
|
|
155
|
-
this.config.
|
|
156
|
-
this.
|
|
157
|
-
this.
|
|
158
|
-
this.existingServices = configManager.current.services.map(s => s.id)
|
|
159
|
+
const { PLT_ROOT, ...existingEnvironment } = this.existingConfig[kMetadata].env
|
|
160
|
+
this.config.env = existingEnvironment
|
|
161
|
+
this.config.port = this.config.env.PORT
|
|
162
|
+
this.entryPoint = this.existingConfig.services.find(svc => svc.entrypoint)
|
|
163
|
+
this.existingServices = this.existingConfig.services.map(s => s.id)
|
|
159
164
|
|
|
160
165
|
this.updateRuntimeConfig(this.existingConfigRaw)
|
|
161
166
|
this.updateRuntimeEnv(await readFile(join(this.targetDirectory, '.env'), 'utf-8'))
|
|
@@ -183,7 +188,6 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
183
188
|
// set default config
|
|
184
189
|
service.setConfig()
|
|
185
190
|
}
|
|
186
|
-
service.config.typescript = this.config.typescript
|
|
187
191
|
})
|
|
188
192
|
}
|
|
189
193
|
|
|
@@ -221,10 +225,6 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
221
225
|
contents: envObjectToString(this.config.defaultEnv)
|
|
222
226
|
})
|
|
223
227
|
|
|
224
|
-
if (!this.existingConfig) {
|
|
225
|
-
this.addFile({ path: '', file: 'README.md', contents: await readFile(join(__dirname, 'README.md'), 'utf-8') })
|
|
226
|
-
}
|
|
227
|
-
|
|
228
228
|
return {
|
|
229
229
|
targetDirectory: this.targetDirectory,
|
|
230
230
|
env: servicesEnv
|
|
@@ -252,18 +252,6 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
252
252
|
async prepareQuestions () {
|
|
253
253
|
await this.populateFromExistingConfig()
|
|
254
254
|
|
|
255
|
-
// typescript
|
|
256
|
-
this.questions.push({
|
|
257
|
-
type: 'list',
|
|
258
|
-
name: 'typescript',
|
|
259
|
-
message: 'Do you want to use TypeScript?',
|
|
260
|
-
default: false,
|
|
261
|
-
choices: [
|
|
262
|
-
{ name: 'yes', value: true },
|
|
263
|
-
{ name: 'no', value: false }
|
|
264
|
-
]
|
|
265
|
-
})
|
|
266
|
-
|
|
267
255
|
if (this.existingConfig) {
|
|
268
256
|
return
|
|
269
257
|
}
|
|
@@ -307,11 +295,6 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
307
295
|
async prepareServiceFiles () {
|
|
308
296
|
let servicesEnv = {}
|
|
309
297
|
for (const svc of this.services) {
|
|
310
|
-
// Propagate TypeScript
|
|
311
|
-
svc.service.setConfig({
|
|
312
|
-
...svc.service.config,
|
|
313
|
-
typescript: this.config.typescript
|
|
314
|
-
})
|
|
315
298
|
const svcEnv = await svc.service.prepare()
|
|
316
299
|
servicesEnv = {
|
|
317
300
|
...servicesEnv,
|
|
@@ -362,7 +345,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
362
345
|
const dirStat = await stat(currentServicePath)
|
|
363
346
|
if (dirStat.isDirectory()) {
|
|
364
347
|
// load the service config
|
|
365
|
-
const configFile = await
|
|
348
|
+
const configFile = await findConfigurationFile(currentServicePath)
|
|
366
349
|
const servicePltJson = JSON.parse(await readFile(join(currentServicePath, configFile), 'utf-8'))
|
|
367
350
|
// get module to load
|
|
368
351
|
const template = servicePltJson.module || getServiceTemplateFromSchemaUrl(servicePltJson.$schema)
|
|
@@ -410,7 +393,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
410
393
|
|
|
411
394
|
// delete dependencies
|
|
412
395
|
const servicePath = join(this.targetDirectory, this.servicesFolder, s.name)
|
|
413
|
-
const configFile = await
|
|
396
|
+
const configFile = await findConfigurationFile(servicePath)
|
|
414
397
|
const servicePackageJson = JSON.parse(await readFile(join(servicePath, configFile), 'utf-8'))
|
|
415
398
|
if (servicePackageJson.plugins && servicePackageJson.plugins.packages) {
|
|
416
399
|
servicePackageJson.plugins.packages.forEach(p => {
|
package/lib/logger.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { once } = require('node:events')
|
|
4
|
-
const { join } = require('node:path')
|
|
5
3
|
const { isatty } = require('node:tty')
|
|
6
4
|
const pino = require('pino')
|
|
7
5
|
const pretty = require('pino-pretty')
|
|
8
|
-
const { buildPinoFormatters, buildPinoTimestamp } = require('@platformatic/
|
|
6
|
+
const { abstractLogger, buildPinoFormatters, buildPinoTimestamp } = require('@platformatic/foundation')
|
|
9
7
|
|
|
10
8
|
const customPrettifiers = {
|
|
11
9
|
name (name, _, obj) {
|
|
@@ -19,26 +17,24 @@ const customPrettifiers = {
|
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
// Create the runtime logger
|
|
22
|
-
async function createLogger (config
|
|
20
|
+
async function createLogger (config) {
|
|
23
21
|
const loggerConfig = { ...config.logger, transport: undefined }
|
|
24
22
|
if (config.logger.base === null) {
|
|
25
23
|
loggerConfig.base = undefined
|
|
26
24
|
}
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
let cliStream = process.env.PLT_RUNTIME_LOGGER_STDOUT
|
|
30
|
-
? pino.destination(process.env.PLT_RUNTIME_LOGGER_STDOUT)
|
|
31
|
-
: isatty(1)
|
|
32
|
-
? pretty({ customPrettifiers })
|
|
33
|
-
: pino.destination(1)
|
|
26
|
+
let cliStream
|
|
34
27
|
|
|
35
28
|
if (config.logger.transport) {
|
|
36
29
|
cliStream = pino.transport(config.logger.transport)
|
|
30
|
+
} else {
|
|
31
|
+
cliStream = isatty(1) ? pretty({ customPrettifiers }) : pino.destination(1)
|
|
37
32
|
}
|
|
38
33
|
|
|
39
34
|
if (loggerConfig.formatters) {
|
|
40
35
|
loggerConfig.formatters = buildPinoFormatters(loggerConfig.formatters)
|
|
41
36
|
}
|
|
37
|
+
|
|
42
38
|
if (loggerConfig.timestamp) {
|
|
43
39
|
loggerConfig.timestamp = buildPinoTimestamp(loggerConfig.timestamp)
|
|
44
40
|
}
|
|
@@ -57,26 +53,7 @@ async function createLogger (config, runtimeLogsDir) {
|
|
|
57
53
|
logsLimitCount = 1
|
|
58
54
|
}
|
|
59
55
|
|
|
60
|
-
const pinoRoll = pino.transport({
|
|
61
|
-
target: 'pino-roll',
|
|
62
|
-
options: {
|
|
63
|
-
file: join(runtimeLogsDir, 'logs'),
|
|
64
|
-
mode: 0o600,
|
|
65
|
-
size: logsFileMb + 'm',
|
|
66
|
-
mkdir: true,
|
|
67
|
-
fsync: true,
|
|
68
|
-
limit: {
|
|
69
|
-
count: logsLimitCount
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
multiStream.add({ level: loggerConfig.level, stream: pinoRoll })
|
|
75
|
-
|
|
76
|
-
// Make sure there is a file before continuing otherwise the management API log endpoint might bail out
|
|
77
|
-
await once(pinoRoll, 'ready')
|
|
78
|
-
|
|
79
56
|
return [pino(loggerConfig, multiStream), multiStream]
|
|
80
57
|
}
|
|
81
58
|
|
|
82
|
-
module.exports = { createLogger }
|
|
59
|
+
module.exports = { abstractLogger, createLogger }
|
package/lib/management-api.js
CHANGED
|
@@ -2,14 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
const { platform, tmpdir } = require('node:os')
|
|
4
4
|
const { join } = require('node:path')
|
|
5
|
-
const { createDirectory, safeRemove } = require('@platformatic/
|
|
5
|
+
const { createDirectory, safeRemove } = require('@platformatic/foundation')
|
|
6
6
|
|
|
7
7
|
const fastify = require('fastify')
|
|
8
8
|
const ws = require('ws')
|
|
9
9
|
|
|
10
|
-
const errors = require('./errors')
|
|
11
|
-
const { getRuntimeLogsDir } = require('./utils')
|
|
12
|
-
|
|
13
10
|
const PLATFORMATIC_TMP_DIR = join(tmpdir(), 'platformatic', 'runtimes')
|
|
14
11
|
|
|
15
12
|
async function managementApiPlugin (app, opts) {
|
|
@@ -152,58 +149,11 @@ async function managementApiPlugin (app, opts) {
|
|
|
152
149
|
})
|
|
153
150
|
|
|
154
151
|
app.get('/logs/live', { websocket: true }, async (socket, req) => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (startLogId) {
|
|
158
|
-
const logIds = await runtime.getLogIds()
|
|
159
|
-
if (!logIds.includes(startLogId)) {
|
|
160
|
-
throw new errors.LogFileNotFound(startLogId)
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const stream = ws.createWebSocketStream(socket)
|
|
165
|
-
runtime.pipeLogsStream(stream, req.log, startLogId)
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
app.get('/logs/indexes', async req => {
|
|
169
|
-
const returnAllIds = req.query.all === 'true'
|
|
170
|
-
|
|
171
|
-
if (returnAllIds) {
|
|
172
|
-
const runtimesLogsIds = await runtime.getAllLogIds()
|
|
173
|
-
return runtimesLogsIds
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const runtimeLogsIds = await runtime.getLogIds()
|
|
177
|
-
return { indexes: runtimeLogsIds }
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
app.get('/logs/all', async (req, reply) => {
|
|
181
|
-
const runtimePID = parseInt(req.query.pid) || process.pid
|
|
182
|
-
|
|
183
|
-
const logsIds = await runtime.getLogIds(runtimePID)
|
|
184
|
-
const startLogId = logsIds.at(0)
|
|
185
|
-
const endLogId = logsIds.at(-1)
|
|
186
|
-
|
|
187
|
-
reply.hijack()
|
|
188
|
-
|
|
189
|
-
runtime.pipeLogsStream(reply.raw, req.log, startLogId, endLogId, runtimePID)
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
app.get('/logs/:id', async req => {
|
|
193
|
-
const logId = parseInt(req.params.id)
|
|
194
|
-
const runtimePID = parseInt(req.query.pid) || process.pid
|
|
195
|
-
|
|
196
|
-
const logIds = await runtime.getLogIds(runtimePID)
|
|
197
|
-
if (!logIds || !logIds.includes(logId)) {
|
|
198
|
-
throw new errors.LogFileNotFound(logId)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const logFileStream = await runtime.getLogFileStream(logId, runtimePID)
|
|
202
|
-
return logFileStream
|
|
152
|
+
runtime.addLoggerDestination(ws.createWebSocketStream(socket))
|
|
203
153
|
})
|
|
204
154
|
}
|
|
205
155
|
|
|
206
|
-
async function startManagementApi (runtime,
|
|
156
|
+
async function startManagementApi (runtime, root) {
|
|
207
157
|
const runtimePID = process.pid
|
|
208
158
|
|
|
209
159
|
try {
|
|
@@ -212,9 +162,6 @@ async function startManagementApi (runtime, configManager) {
|
|
|
212
162
|
await createDirectory(runtimePIDDir, true)
|
|
213
163
|
}
|
|
214
164
|
|
|
215
|
-
const runtimeLogsDir = getRuntimeLogsDir(configManager.dirname, process.pid)
|
|
216
|
-
await createDirectory(runtimeLogsDir, true)
|
|
217
|
-
|
|
218
165
|
let socketPath = null
|
|
219
166
|
if (platform() === 'win32') {
|
|
220
167
|
socketPath = '\\\\.\\pipe\\platformatic-' + runtimePID.toString()
|
|
@@ -232,6 +179,9 @@ async function startManagementApi (runtime, configManager) {
|
|
|
232
179
|
}
|
|
233
180
|
})
|
|
234
181
|
|
|
182
|
+
// When the runtime closes, close the management API as well
|
|
183
|
+
runtime.on('closed', managementApi.close.bind(managementApi))
|
|
184
|
+
|
|
235
185
|
await managementApi.listen({ path: socketPath })
|
|
236
186
|
return managementApi
|
|
237
187
|
/* c8 ignore next 4 */
|