@platformatic/runtime 3.4.1 → 3.5.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/README.md +1 -1
- package/config.d.ts +224 -77
- package/eslint.config.js +3 -5
- package/index.d.ts +73 -24
- package/index.js +173 -29
- package/lib/config.js +279 -197
- package/lib/errors.js +126 -34
- package/lib/generator.js +640 -0
- package/lib/logger.js +43 -41
- package/lib/management-api.js +109 -118
- package/lib/prom-server.js +202 -16
- package/lib/runtime.js +1963 -585
- package/lib/scheduler.js +119 -0
- package/lib/schema.js +22 -234
- package/lib/shared-http-cache.js +43 -0
- package/lib/upgrade.js +6 -8
- package/lib/utils.js +6 -61
- package/lib/version.js +7 -0
- package/lib/versions/v1.36.0.js +2 -4
- package/lib/versions/v1.5.0.js +2 -4
- package/lib/versions/v2.0.0.js +3 -5
- package/lib/versions/v3.0.0.js +16 -0
- package/lib/worker/controller.js +302 -0
- package/lib/worker/http-cache.js +171 -0
- package/lib/worker/interceptors.js +190 -10
- package/lib/worker/itc.js +146 -59
- package/lib/worker/main.js +220 -81
- package/lib/worker/messaging.js +182 -0
- package/lib/worker/round-robin-map.js +62 -0
- package/lib/worker/shared-context.js +22 -0
- package/lib/worker/symbols.js +14 -5
- package/package.json +47 -38
- package/schema.json +1383 -55
- 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 -69
- package/lib/compile.js +0 -98
- package/lib/dependencies.js +0 -59
- 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/generator/runtime-generator.js +0 -498
- package/lib/start.js +0 -190
- package/lib/worker/app.js +0 -278
- package/lib/worker/default-stackable.js +0 -33
- package/lib/worker/metrics.js +0 -122
- package/runtime.mjs +0 -54
package/lib/config.js
CHANGED
|
@@ -1,52 +1,177 @@
|
|
|
1
|
-
|
|
1
|
+
import { importCapabilityAndConfig, validationOptions } from '@platformatic/basic'
|
|
2
|
+
import {
|
|
3
|
+
extractModuleFromSchemaUrl,
|
|
4
|
+
findConfigurationFile,
|
|
5
|
+
kMetadata,
|
|
6
|
+
loadConfiguration,
|
|
7
|
+
loadConfigurationModule,
|
|
8
|
+
loadModule,
|
|
9
|
+
omitProperties,
|
|
10
|
+
runtimeUnwrappablePropertiesList
|
|
11
|
+
} from '@platformatic/foundation'
|
|
12
|
+
import { readdir, readFile } from 'node:fs/promises'
|
|
13
|
+
import { createRequire } from 'node:module'
|
|
14
|
+
import { isAbsolute, join, resolve as resolvePath } from 'node:path'
|
|
15
|
+
import {
|
|
16
|
+
InspectAndInspectBrkError,
|
|
17
|
+
InspectorHostError,
|
|
18
|
+
InspectorPortError,
|
|
19
|
+
InvalidArgumentError,
|
|
20
|
+
InvalidEntrypointError,
|
|
21
|
+
MissingEntrypointError
|
|
22
|
+
} from './errors.js'
|
|
23
|
+
import { schema } from './schema.js'
|
|
24
|
+
import { upgrade } from './upgrade.js'
|
|
25
|
+
|
|
26
|
+
// Validate and coerce workers values early to avoid runtime hangs when invalid
|
|
27
|
+
function coercePositiveInteger (value) {
|
|
28
|
+
if (typeof value === 'number') {
|
|
29
|
+
if (!Number.isInteger(value) || value < 1) return null
|
|
30
|
+
return value
|
|
31
|
+
}
|
|
32
|
+
if (typeof value === 'string') {
|
|
33
|
+
// Trim to handle accidental spaces
|
|
34
|
+
const trimmed = value.trim()
|
|
35
|
+
if (trimmed.length === 0) return null
|
|
36
|
+
const num = Number(trimmed)
|
|
37
|
+
if (!Number.isFinite(num) || !Number.isInteger(num) || num < 1) return null
|
|
38
|
+
return num
|
|
39
|
+
}
|
|
40
|
+
return null
|
|
41
|
+
}
|
|
2
42
|
|
|
3
|
-
|
|
4
|
-
const
|
|
43
|
+
function raiseInvalidWorkersError (location, received, hint) {
|
|
44
|
+
const extra = hint ? ` (${hint})` : ''
|
|
45
|
+
throw new InvalidArgumentError(`${location} workers must be a positive integer; received "${received}"${extra}`)
|
|
46
|
+
}
|
|
5
47
|
|
|
6
|
-
|
|
48
|
+
export function autoDetectPprofCapture (config) {
|
|
49
|
+
const require = createRequire(import.meta.url)
|
|
7
50
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
51
|
+
let pprofCapturePath
|
|
52
|
+
try {
|
|
53
|
+
pprofCapturePath = require.resolve('@platformatic/wattpm-pprof-capture')
|
|
54
|
+
} catch (err) {
|
|
55
|
+
// No-op
|
|
56
|
+
}
|
|
12
57
|
|
|
13
|
-
|
|
14
|
-
|
|
58
|
+
// Add to preload if not already present
|
|
59
|
+
if (!config.preload) {
|
|
60
|
+
config.preload = []
|
|
61
|
+
} else if (typeof config.preload === 'string') {
|
|
62
|
+
config.preload = [config.preload]
|
|
63
|
+
}
|
|
15
64
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
65
|
+
if (pprofCapturePath && !config.preload.includes(pprofCapturePath)) {
|
|
66
|
+
config.preload.push(pprofCapturePath)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return config
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function wrapInRuntimeConfig (config, context) {
|
|
73
|
+
let applicationId = 'main'
|
|
74
|
+
try {
|
|
75
|
+
const packageJson = JSON.parse(await readFile(join(config[kMetadata].root, 'package.json'), 'utf-8'))
|
|
76
|
+
applicationId = packageJson?.name ?? 'main'
|
|
77
|
+
|
|
78
|
+
if (applicationId.startsWith('@')) {
|
|
79
|
+
applicationId = applicationId.split('/')[1]
|
|
20
80
|
}
|
|
81
|
+
} catch (err) {
|
|
82
|
+
// on purpose, the package.json might be missing
|
|
83
|
+
}
|
|
21
84
|
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
85
|
+
// If the application supports its (so far, only @platformatic/service and descendants)
|
|
86
|
+
const { hostname, port, http2, https } = config.server ?? {}
|
|
87
|
+
const server = { hostname, port, http2, https }
|
|
88
|
+
const production = context?.isProduction ?? context?.production
|
|
89
|
+
|
|
90
|
+
// Important: do not change the order of the properties in this object
|
|
91
|
+
/* c8 ignore next */
|
|
92
|
+
const wrapped = {
|
|
93
|
+
$schema: schema.$id,
|
|
94
|
+
server,
|
|
95
|
+
watch: !production,
|
|
96
|
+
...omitProperties(config.runtime ?? {}, runtimeUnwrappablePropertiesList),
|
|
97
|
+
entrypoint: applicationId,
|
|
98
|
+
applications: [
|
|
99
|
+
{
|
|
100
|
+
id: applicationId,
|
|
101
|
+
path: config[kMetadata].root,
|
|
102
|
+
config: config[kMetadata].path
|
|
103
|
+
}
|
|
104
|
+
]
|
|
25
105
|
}
|
|
26
106
|
|
|
107
|
+
return loadConfiguration(wrapped, context?.schema ?? schema, {
|
|
108
|
+
validationOptions,
|
|
109
|
+
transform,
|
|
110
|
+
upgrade,
|
|
111
|
+
replaceEnv: true,
|
|
112
|
+
root: config[kMetadata].root,
|
|
113
|
+
...context
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function parseInspectorOptions (config, inspect, inspectBreak) {
|
|
118
|
+
const hasInspect = inspect != null
|
|
119
|
+
const hasInspectBrk = inspectBreak != null
|
|
120
|
+
|
|
121
|
+
if (hasInspect && hasInspectBrk) {
|
|
122
|
+
throw new InspectAndInspectBrkError()
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const value = inspectBreak ?? inspect
|
|
126
|
+
|
|
127
|
+
if (!value) {
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let host = '127.0.0.1'
|
|
132
|
+
let port = 9229
|
|
133
|
+
|
|
134
|
+
if (typeof value === 'string' && value.length > 0) {
|
|
135
|
+
const splitAt = value.lastIndexOf(':')
|
|
136
|
+
|
|
137
|
+
if (splitAt === -1) {
|
|
138
|
+
port = value
|
|
139
|
+
} else {
|
|
140
|
+
host = value.substring(0, splitAt)
|
|
141
|
+
port = value.substring(splitAt + 1)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
port = Number.parseInt(port, 10)
|
|
145
|
+
|
|
146
|
+
if (!(port === 0 || (port >= 1024 && port <= 65535))) {
|
|
147
|
+
throw new InspectorPortError()
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!host) {
|
|
151
|
+
throw new InspectorHostError()
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
config.inspectorOptions = { host, port, breakFirstLine: hasInspectBrk, watchDisabled: !!config.watch }
|
|
156
|
+
config.watch = false
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export async function transform (config, _, context) {
|
|
160
|
+
const production = context?.isProduction ?? context?.production
|
|
161
|
+
const applications = [...(config.applications ?? []), ...(config.services ?? []), ...(config.web ?? [])]
|
|
162
|
+
|
|
27
163
|
const watchType = typeof config.watch
|
|
28
164
|
if (watchType === 'string') {
|
|
29
165
|
config.watch = config.watch === 'true'
|
|
30
166
|
} else if (watchType === 'undefined') {
|
|
31
|
-
|
|
32
|
-
args,
|
|
33
|
-
strict: false,
|
|
34
|
-
options: { production: { type: 'boolean', short: 'p', default: false } }
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
config.watch = !values.production
|
|
167
|
+
config.watch = !production
|
|
38
168
|
}
|
|
39
169
|
|
|
40
170
|
if (config.autoload) {
|
|
41
171
|
const { exclude = [], mappings = {} } = config.autoload
|
|
42
172
|
let { path } = config.autoload
|
|
43
173
|
|
|
44
|
-
|
|
45
|
-
// while we are upgrading the config
|
|
46
|
-
if (configManager._fixPaths) {
|
|
47
|
-
path = pathResolve(configManager.dirname, path)
|
|
48
|
-
}
|
|
49
|
-
|
|
174
|
+
path = resolvePath(config[kMetadata].root, path)
|
|
50
175
|
const entries = await readdir(path, { withFileTypes: true })
|
|
51
176
|
|
|
52
177
|
for (let i = 0; i < entries.length; ++i) {
|
|
@@ -61,218 +186,175 @@ async function _transformConfig (configManager, args) {
|
|
|
61
186
|
const entryPath = join(path, entry.name)
|
|
62
187
|
|
|
63
188
|
let config
|
|
64
|
-
const configFilename = mapping.config ?? (await
|
|
189
|
+
const configFilename = mapping.config ?? (await findConfigurationFile(entryPath))
|
|
65
190
|
|
|
66
191
|
if (typeof configFilename === 'string') {
|
|
67
192
|
config = join(entryPath, configFilename)
|
|
68
193
|
}
|
|
69
194
|
|
|
70
|
-
const
|
|
71
|
-
|
|
195
|
+
const application = {
|
|
196
|
+
id,
|
|
197
|
+
config,
|
|
198
|
+
path: entryPath,
|
|
199
|
+
useHttp: !!mapping.useHttp,
|
|
200
|
+
health: mapping.health,
|
|
201
|
+
dependencies: mapping.dependencies
|
|
202
|
+
}
|
|
203
|
+
const existingApplicationId = applications.findIndex(application => application.id === id)
|
|
72
204
|
|
|
73
|
-
if (
|
|
74
|
-
|
|
205
|
+
if (existingApplicationId !== -1) {
|
|
206
|
+
applications[existingApplicationId] = { ...application, ...applications[existingApplicationId] }
|
|
75
207
|
} else {
|
|
76
|
-
|
|
208
|
+
applications.push(application)
|
|
77
209
|
}
|
|
78
210
|
}
|
|
79
211
|
}
|
|
80
212
|
|
|
81
|
-
|
|
82
|
-
|
|
213
|
+
config.inspectorOptions = undefined
|
|
214
|
+
parseInspectorOptions(config, context?.inspect, context?.inspectBreak)
|
|
83
215
|
|
|
84
216
|
let hasValidEntrypoint = false
|
|
85
217
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
service.dependencies = []
|
|
94
|
-
service.localServiceEnvVars = new Map()
|
|
95
|
-
service.localUrl = `http://${service.id}.plt.local`
|
|
96
|
-
|
|
97
|
-
if (typeof service.watch === 'undefined') {
|
|
98
|
-
service.watch = config.watch
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (service.entrypoint) {
|
|
102
|
-
hasValidEntrypoint = true
|
|
218
|
+
// Root-level workers
|
|
219
|
+
if (typeof config.workers !== 'undefined') {
|
|
220
|
+
const coerced = coercePositiveInteger(config.workers)
|
|
221
|
+
if (coerced === null) {
|
|
222
|
+
const raw = config.workers
|
|
223
|
+
const hint = typeof raw === 'string' && /\{.*\}/.test(raw) ? 'check your environment variable' : ''
|
|
224
|
+
raiseInvalidWorkersError('Runtime', config.workers, hint)
|
|
103
225
|
}
|
|
104
|
-
|
|
105
|
-
configManager.current.serviceMap.set(service.id, service)
|
|
226
|
+
config.workers = coerced
|
|
106
227
|
}
|
|
107
228
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// If there is only one service, it becomes the entrypoint
|
|
111
|
-
if (services.length === 1) {
|
|
112
|
-
services[0].entrypoint = true
|
|
113
|
-
config.entrypoint = services[0].id
|
|
114
|
-
hasValidEntrypoint = true
|
|
115
|
-
} else {
|
|
116
|
-
// Search if exactly service uses @platformatic/composer
|
|
117
|
-
const composers = []
|
|
118
|
-
|
|
119
|
-
for (const service of services) {
|
|
120
|
-
if (!service.config) {
|
|
121
|
-
continue
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const manager = new ConfigManager({ source: pathResolve(service.path, service.config) })
|
|
125
|
-
await manager.parse()
|
|
126
|
-
const config = manager.current
|
|
127
|
-
const type = config.$schema ? ConfigManager.matchKnownSchema(config.$schema) : undefined
|
|
229
|
+
for (let i = 0; i < applications.length; ++i) {
|
|
230
|
+
const application = applications[i]
|
|
128
231
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
232
|
+
// We need to have absolute paths here, ot the `loadConfig` will fail
|
|
233
|
+
// Make sure we don't resolve if env var was not replaced
|
|
234
|
+
if (application.path && !isAbsolute(application.path) && !application.path.match(/^\{.*\}$/)) {
|
|
235
|
+
application.path = resolvePath(config[kMetadata].root, application.path)
|
|
236
|
+
}
|
|
133
237
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
config.entrypoint = composers[0]
|
|
137
|
-
hasValidEntrypoint = true
|
|
138
|
-
}
|
|
238
|
+
if (application.path && application.config) {
|
|
239
|
+
application.config = resolvePath(application.path, application.config)
|
|
139
240
|
}
|
|
140
|
-
}
|
|
141
241
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
? new errors.InvalidEntrypointError(config.entrypoint)
|
|
145
|
-
: new errors.MissingEntrypointError()
|
|
146
|
-
}
|
|
242
|
+
try {
|
|
243
|
+
let pkg
|
|
147
244
|
|
|
148
|
-
|
|
149
|
-
|
|
245
|
+
if (application.config) {
|
|
246
|
+
const config = await loadConfiguration(application.config)
|
|
247
|
+
pkg = await loadConfigurationModule(application.path, config)
|
|
150
248
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
249
|
+
application.type = extractModuleFromSchemaUrl(config, true).module
|
|
250
|
+
application.skipTelemetryHooks = pkg.skipTelemetryHooks
|
|
251
|
+
} else {
|
|
252
|
+
const { moduleName, capability } = await importCapabilityAndConfig(application.path)
|
|
253
|
+
pkg = capability
|
|
155
254
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
255
|
+
application.type = moduleName
|
|
256
|
+
}
|
|
159
257
|
|
|
160
|
-
|
|
161
|
-
platformaticRuntime.schema = schema
|
|
162
|
-
platformaticRuntime.configType = 'runtime'
|
|
163
|
-
platformaticRuntime.configManagerConfig = {
|
|
164
|
-
version: require('../package.json').version,
|
|
165
|
-
schema,
|
|
166
|
-
allowToWatch: ['.env'],
|
|
167
|
-
schemaOptions: {
|
|
168
|
-
useDefaults: true,
|
|
169
|
-
coerceTypes: true,
|
|
170
|
-
allErrors: true,
|
|
171
|
-
strict: false
|
|
172
|
-
},
|
|
173
|
-
async transformConfig (args) {
|
|
174
|
-
await _transformConfig(this, args)
|
|
175
|
-
},
|
|
176
|
-
upgrade
|
|
177
|
-
}
|
|
258
|
+
application.skipTelemetryHooks = pkg.skipTelemetryHooks
|
|
178
259
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
260
|
+
// This is needed to work around Rust bug on dylibs:
|
|
261
|
+
// https://github.com/rust-lang/rust/issues/91979
|
|
262
|
+
// https://github.com/rollup/rollup/issues/5761
|
|
263
|
+
const _require = createRequire(application.path)
|
|
264
|
+
for (const m of pkg.modulesToLoad ?? []) {
|
|
265
|
+
const toLoad = _require.resolve(m)
|
|
266
|
+
loadModule(_require, toLoad).catch(() => {})
|
|
267
|
+
}
|
|
268
|
+
} catch (err) {
|
|
269
|
+
// This should not happen, it happens on running some unit tests if we prepare the runtime
|
|
270
|
+
// when not all the applications configs are available. Given that we are running this only
|
|
271
|
+
// to ddetermine the type of the application, it's safe to ignore this error and default to unknown
|
|
272
|
+
application.type = 'unknown'
|
|
186
273
|
}
|
|
187
|
-
} catch (err) {
|
|
188
|
-
// on purpose, the package.json might be missing
|
|
189
|
-
}
|
|
190
274
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
id: serviceId,
|
|
199
|
-
path: configManager.dirname,
|
|
200
|
-
config: configManager.fullPath
|
|
275
|
+
// Validate and coerce per-service workers
|
|
276
|
+
if (typeof application.workers !== 'undefined') {
|
|
277
|
+
const coerced = coercePositiveInteger(application.workers)
|
|
278
|
+
if (coerced === null) {
|
|
279
|
+
const raw = config.application?.[i]?.workers
|
|
280
|
+
const hint = typeof raw === 'string' && /\{.*\}/.test(raw) ? 'check your environment variable' : ''
|
|
281
|
+
raiseInvalidWorkersError(`Service "${application.id}"`, application.workers, hint)
|
|
201
282
|
}
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
const cm = new ConfigManager({
|
|
205
|
-
source: wrapperConfig,
|
|
206
|
-
schema,
|
|
207
|
-
schemaOptions: {
|
|
208
|
-
useDefaults: true,
|
|
209
|
-
coerceTypes: true,
|
|
210
|
-
allErrors: true,
|
|
211
|
-
strict: false
|
|
212
|
-
},
|
|
213
|
-
transformConfig (args) {
|
|
214
|
-
return _transformConfig(this, args)
|
|
283
|
+
application.workers = coerced
|
|
215
284
|
}
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
await cm.parseAndValidate()
|
|
219
|
-
return cm
|
|
220
|
-
}
|
|
221
285
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const hasInspectBrk = 'inspect-brk' in args
|
|
226
|
-
let inspectFlag
|
|
286
|
+
application.entrypoint = application.id === config.entrypoint
|
|
287
|
+
application.dependencies ??= []
|
|
288
|
+
application.localUrl = `http://${application.id}.plt.local`
|
|
227
289
|
|
|
228
|
-
|
|
229
|
-
|
|
290
|
+
if (typeof application.watch === 'undefined') {
|
|
291
|
+
application.watch = config.watch
|
|
292
|
+
}
|
|
230
293
|
|
|
231
|
-
if (
|
|
232
|
-
|
|
294
|
+
if (application.entrypoint) {
|
|
295
|
+
hasValidEntrypoint = true
|
|
233
296
|
}
|
|
234
|
-
} else if (hasInspectBrk) {
|
|
235
|
-
inspectFlag = args['inspect-brk']
|
|
236
297
|
}
|
|
237
298
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
host = inspectFlag.substring(0, splitAt)
|
|
249
|
-
port = inspectFlag.substring(splitAt + 1)
|
|
250
|
-
}
|
|
299
|
+
// If there is no entrypoint, autodetect one
|
|
300
|
+
if (!config.entrypoint) {
|
|
301
|
+
// If there is only one application, it becomes the entrypoint
|
|
302
|
+
if (applications.length === 1) {
|
|
303
|
+
applications[0].entrypoint = true
|
|
304
|
+
config.entrypoint = applications[0].id
|
|
305
|
+
hasValidEntrypoint = true
|
|
306
|
+
} else {
|
|
307
|
+
// Search if exactly application uses @platformatic/gateway
|
|
308
|
+
const gateways = []
|
|
251
309
|
|
|
252
|
-
|
|
310
|
+
for (const application of applications) {
|
|
311
|
+
if (!application.config) {
|
|
312
|
+
continue
|
|
313
|
+
}
|
|
253
314
|
|
|
254
|
-
|
|
255
|
-
|
|
315
|
+
if (application.type === '@platformatic/gateway') {
|
|
316
|
+
gateways.push(application.id)
|
|
317
|
+
}
|
|
256
318
|
}
|
|
257
319
|
|
|
258
|
-
if (
|
|
259
|
-
|
|
320
|
+
if (gateways.length === 1) {
|
|
321
|
+
applications.find(s => s.id === gateways[0]).entrypoint = true
|
|
322
|
+
config.entrypoint = gateways[0]
|
|
323
|
+
hasValidEntrypoint = true
|
|
260
324
|
}
|
|
261
325
|
}
|
|
326
|
+
}
|
|
262
327
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
328
|
+
if (!hasValidEntrypoint && !context.allowMissingEntrypoint) {
|
|
329
|
+
if (config.entrypoint) {
|
|
330
|
+
throw new InvalidEntrypointError(config.entrypoint)
|
|
331
|
+
} else if (applications.length >= 1) {
|
|
332
|
+
throw new MissingEntrypointError()
|
|
268
333
|
}
|
|
334
|
+
// If there are no applications, and no entrypoint it's an empty app.
|
|
335
|
+
// It won't start, but we should be able to parse and operate on it,
|
|
336
|
+
// like adding other applications.
|
|
337
|
+
}
|
|
269
338
|
|
|
270
|
-
|
|
339
|
+
config.applications = applications
|
|
340
|
+
config.web = undefined
|
|
341
|
+
config.services = undefined
|
|
342
|
+
config.logger ??= {}
|
|
343
|
+
|
|
344
|
+
if (production) {
|
|
345
|
+
// Any value below 10 is considered as "immediate restart" and won't be processed via setTimeout or similar
|
|
346
|
+
// Important: do not use 2 otherwise ajv will convert to boolean `true`
|
|
347
|
+
config.restartOnError = 2
|
|
348
|
+
} else {
|
|
349
|
+
if (config.restartOnError === true) {
|
|
350
|
+
config.restartOnError = 5000
|
|
351
|
+
} else if (config.restartOnError < 0) {
|
|
352
|
+
config.restartOnError = 0
|
|
353
|
+
}
|
|
271
354
|
}
|
|
272
|
-
}
|
|
273
355
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
356
|
+
// Auto-detect and add pprof capture if available
|
|
357
|
+
autoDetectPprofCapture(config)
|
|
358
|
+
|
|
359
|
+
return config
|
|
278
360
|
}
|