@platformatic/runtime 3.0.0-alpha.5 → 3.0.0-alpha.8
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 +11 -7
- package/eslint.config.js +2 -4
- package/index.d.ts +11 -11
- package/index.js +35 -46
- package/lib/config.js +159 -102
- package/lib/errors.js +65 -99
- package/lib/generator.js +160 -164
- package/lib/logger.js +6 -8
- package/lib/management-api.js +91 -63
- package/lib/prom-server.js +10 -14
- package/lib/runtime.js +815 -747
- package/lib/scheduler.js +13 -15
- package/lib/schema.js +11 -8
- package/lib/shared-http-cache.js +5 -9
- package/lib/upgrade.js +5 -9
- package/lib/utils.js +6 -14
- 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/{app.js → controller.js} +68 -63
- package/lib/worker/http-cache.js +11 -14
- package/lib/worker/interceptors.js +14 -18
- package/lib/worker/itc.js +85 -79
- package/lib/worker/main.js +49 -55
- package/lib/worker/messaging.js +23 -27
- package/lib/worker/round-robin-map.js +23 -19
- package/lib/worker/shared-context.js +2 -6
- package/lib/worker/symbols.js +12 -29
- package/package.json +24 -23
- package/schema.json +281 -20
- package/lib/dependencies.js +0 -65
package/config.d.ts
CHANGED
|
@@ -32,18 +32,22 @@ export type PlatformaticRuntimeConfig = {
|
|
|
32
32
|
maxYoungGeneration?: number | string;
|
|
33
33
|
};
|
|
34
34
|
preload?: string | string[];
|
|
35
|
+
dependencies?: string[];
|
|
35
36
|
arguments?: string[];
|
|
36
37
|
nodeOptions?: string;
|
|
37
38
|
};
|
|
38
39
|
};
|
|
39
40
|
};
|
|
41
|
+
applications?: {
|
|
42
|
+
[k: string]: unknown;
|
|
43
|
+
}[];
|
|
40
44
|
services?: {
|
|
41
45
|
[k: string]: unknown;
|
|
42
46
|
}[];
|
|
43
|
-
workers?: number | string;
|
|
44
47
|
web?: {
|
|
45
48
|
[k: string]: unknown;
|
|
46
49
|
}[];
|
|
50
|
+
workers?: number | string;
|
|
47
51
|
logger?: {
|
|
48
52
|
level: (
|
|
49
53
|
| ("fatal" | "error" | "warn" | "info" | "debug" | "trace" | "silent")
|
|
@@ -131,7 +135,7 @@ export type PlatformaticRuntimeConfig = {
|
|
|
131
135
|
restartOnError?: boolean | number;
|
|
132
136
|
gracefulShutdown?: {
|
|
133
137
|
runtime: number | string;
|
|
134
|
-
|
|
138
|
+
application: number | string;
|
|
135
139
|
};
|
|
136
140
|
health?: {
|
|
137
141
|
enabled?: boolean | string;
|
|
@@ -250,11 +254,11 @@ export type PlatformaticRuntimeConfig = {
|
|
|
250
254
|
telemetry?: {
|
|
251
255
|
enabled?: boolean | string;
|
|
252
256
|
/**
|
|
253
|
-
* The name of the
|
|
257
|
+
* The name of the application. Defaults to the folder name if not specified.
|
|
254
258
|
*/
|
|
255
|
-
|
|
259
|
+
applicationName: string;
|
|
256
260
|
/**
|
|
257
|
-
* The version of the
|
|
261
|
+
* The version of the application (optional)
|
|
258
262
|
*/
|
|
259
263
|
version?: string;
|
|
260
264
|
/**
|
|
@@ -330,9 +334,9 @@ export type PlatformaticRuntimeConfig = {
|
|
|
330
334
|
watchDisabled?: boolean;
|
|
331
335
|
[k: string]: unknown;
|
|
332
336
|
};
|
|
333
|
-
|
|
337
|
+
applicationTimeout?: number | string;
|
|
334
338
|
messagingTimeout?: number | string;
|
|
335
|
-
|
|
339
|
+
resolvedApplicationsBasePath?: string;
|
|
336
340
|
env?: {
|
|
337
341
|
[k: string]: string;
|
|
338
342
|
};
|
package/eslint.config.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import neostandard from 'neostandard'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
module.exports = neostandard({
|
|
3
|
+
export default neostandard({
|
|
6
4
|
ts: true,
|
|
7
5
|
ignores: [...neostandard.resolveIgnoresFromGitignore(), 'test/tmp/**/*', 'dist/**/*']
|
|
8
6
|
})
|
package/index.d.ts
CHANGED
|
@@ -8,33 +8,33 @@ import { PlatformaticRuntimeConfig } from './config'
|
|
|
8
8
|
|
|
9
9
|
export type RuntimeConfiguration = Promise<Configuration<PlatformaticRuntimeConfig>>
|
|
10
10
|
|
|
11
|
-
export type
|
|
11
|
+
export type ApplicationCommandContext = {
|
|
12
12
|
colorette: typeof colorette
|
|
13
13
|
parseArgs: typeof parseArgs
|
|
14
14
|
logFatalError: typeof logFatalError
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export type
|
|
17
|
+
export type ApplicationCommand = (
|
|
18
18
|
logger: Logger,
|
|
19
19
|
configuration: Configuration<unknown>,
|
|
20
20
|
args: string[],
|
|
21
|
-
context:
|
|
21
|
+
context: ApplicationCommandContext
|
|
22
22
|
) => Promise<void>
|
|
23
23
|
|
|
24
|
-
export interface
|
|
25
|
-
|
|
26
|
-
commands: Record<string,
|
|
24
|
+
export interface ApplicationsCommands {
|
|
25
|
+
applications: Record<string, Configuration<unknown>>
|
|
26
|
+
commands: Record<string, ApplicationCommand>
|
|
27
27
|
help: Record<string, string | (() => string)>
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export module errors {
|
|
31
31
|
export const RuntimeExitedError: () => FastifyError
|
|
32
32
|
export const UnknownRuntimeAPICommandError: (command: string) => FastifyError
|
|
33
|
-
export const
|
|
34
|
-
export const
|
|
33
|
+
export const ApplicationNotFoundError: (id: string) => FastifyError
|
|
34
|
+
export const ApplicationNotStartedError: (id: string) => FastifyError
|
|
35
35
|
export const FailedToRetrieveOpenAPISchemaError: (id: string, error: string) => FastifyError
|
|
36
36
|
export const ApplicationAlreadyStartedError: () => FastifyError
|
|
37
|
-
export const
|
|
37
|
+
export const RuntimeNotStartedError: () => FastifyError
|
|
38
38
|
export const ConfigPathMustBeStringError: () => FastifyError
|
|
39
39
|
export const NoConfigFileFoundError: (id: string) => FastifyError
|
|
40
40
|
export const InvalidEntrypointError: (entrypoint: string) => FastifyError
|
|
@@ -51,7 +51,7 @@ export module symbols {
|
|
|
51
51
|
export declare const kConfig: unique symbol
|
|
52
52
|
export declare const kId: unique symbol
|
|
53
53
|
export declare const kFullId: unique symbol
|
|
54
|
-
export declare const
|
|
54
|
+
export declare const kApplicationId: unique symbol
|
|
55
55
|
export declare const kWorkerId: unique symbol
|
|
56
56
|
export declare const kITC: unique symbol
|
|
57
57
|
export declare const kHealthCheckTimer: unique symbol
|
|
@@ -91,4 +91,4 @@ export function create (
|
|
|
91
91
|
|
|
92
92
|
export declare function transform (config: RuntimeConfiguration): Promise<RuntimeConfiguration> | RuntimeConfiguration
|
|
93
93
|
|
|
94
|
-
export declare function
|
|
94
|
+
export declare function loadApplicationsCommands (): Promise<ApplicationsCommands>
|
package/index.js
CHANGED
|
@@ -1,31 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const inspector = require('node:inspector')
|
|
4
|
-
const {
|
|
5
|
-
kMetadata,
|
|
6
|
-
loadConfigurationModule,
|
|
1
|
+
import { resolve, validationOptions } from '@platformatic/basic'
|
|
2
|
+
import {
|
|
7
3
|
abstractLogger,
|
|
8
|
-
|
|
9
|
-
loadConfiguration: utilsLoadConfiguration,
|
|
4
|
+
ensureLoggableError,
|
|
10
5
|
extractModuleFromSchemaUrl,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
6
|
+
findRuntimeConfigurationFile,
|
|
7
|
+
kMetadata,
|
|
8
|
+
loadConfigurationModule,
|
|
9
|
+
loadConfiguration as utilsLoadConfiguration
|
|
10
|
+
} from '@platformatic/foundation'
|
|
11
|
+
import inspector from 'node:inspector'
|
|
12
|
+
import { transform, wrapInRuntimeConfig } from './lib/config.js'
|
|
13
|
+
import { NodeInspectorFlagsNotSupportedError } from './lib/errors.js'
|
|
14
|
+
import { Runtime } from './lib/runtime.js'
|
|
15
|
+
import { schema } from './lib/schema.js'
|
|
16
|
+
import { upgrade } from './lib/upgrade.js'
|
|
21
17
|
|
|
22
18
|
async function restartRuntime (runtime) {
|
|
23
|
-
runtime.logger.info('Received SIGUSR2, restarting all
|
|
19
|
+
runtime.logger.info('Received SIGUSR2, restarting all applications ...')
|
|
24
20
|
|
|
25
21
|
try {
|
|
26
22
|
await runtime.restart()
|
|
27
23
|
} catch (err) {
|
|
28
|
-
runtime.logger.error({ err: ensureLoggableError(err) }, 'Failed to restart
|
|
24
|
+
runtime.logger.error({ err: ensureLoggableError(err) }, 'Failed to restart applications.')
|
|
29
25
|
}
|
|
30
26
|
}
|
|
31
27
|
|
|
@@ -38,7 +34,7 @@ function handleSignal (runtime) {
|
|
|
38
34
|
})
|
|
39
35
|
}
|
|
40
36
|
|
|
41
|
-
async function loadConfiguration (configOrRoot, sourceOrConfig, context) {
|
|
37
|
+
export async function loadConfiguration (configOrRoot, sourceOrConfig, context) {
|
|
42
38
|
const { root, source } = await resolve(configOrRoot, sourceOrConfig, 'runtime')
|
|
43
39
|
|
|
44
40
|
// First of all, load the configuration without any validation
|
|
@@ -58,8 +54,8 @@ async function loadConfiguration (configOrRoot, sourceOrConfig, context) {
|
|
|
58
54
|
})
|
|
59
55
|
}
|
|
60
56
|
|
|
61
|
-
async function
|
|
62
|
-
const
|
|
57
|
+
export async function loadApplicationsCommands () {
|
|
58
|
+
const applications = {}
|
|
63
59
|
const commands = {}
|
|
64
60
|
const help = {}
|
|
65
61
|
|
|
@@ -79,18 +75,18 @@ async function loadServicesCommands () {
|
|
|
79
75
|
throw new Error('No runtime configuration file found.')
|
|
80
76
|
}
|
|
81
77
|
} catch {
|
|
82
|
-
return {
|
|
78
|
+
return { applications, commands, help }
|
|
83
79
|
}
|
|
84
80
|
|
|
85
|
-
for (const
|
|
81
|
+
for (const application of config.applications) {
|
|
86
82
|
try {
|
|
87
|
-
const
|
|
88
|
-
const pkg = await loadConfigurationModule(
|
|
83
|
+
const applicationConfig = await utilsLoadConfiguration(application.config)
|
|
84
|
+
const pkg = await loadConfigurationModule(application.path, applicationConfig)
|
|
89
85
|
|
|
90
86
|
if (pkg.createCommands) {
|
|
91
|
-
const definition = await pkg.createCommands(
|
|
87
|
+
const definition = await pkg.createCommands(application.id)
|
|
92
88
|
for (const command of Object.keys(definition.commands)) {
|
|
93
|
-
|
|
89
|
+
applications[command] = application
|
|
94
90
|
}
|
|
95
91
|
|
|
96
92
|
Object.assign(commands, definition.commands)
|
|
@@ -98,14 +94,14 @@ async function loadServicesCommands () {
|
|
|
98
94
|
}
|
|
99
95
|
/* c8 ignore next 3 - Hard to test */
|
|
100
96
|
} catch {
|
|
101
|
-
// No-op, ignore the
|
|
97
|
+
// No-op, ignore the application
|
|
102
98
|
}
|
|
103
99
|
}
|
|
104
100
|
|
|
105
|
-
return {
|
|
101
|
+
return { applications, commands, help }
|
|
106
102
|
}
|
|
107
103
|
|
|
108
|
-
async function create (configOrRoot, sourceOrConfig, context) {
|
|
104
|
+
export async function create (configOrRoot, sourceOrConfig, context) {
|
|
109
105
|
const config = await loadConfiguration(configOrRoot, sourceOrConfig, context)
|
|
110
106
|
|
|
111
107
|
if (inspector.url() && !config[kMetadata].env.VSCODE_INSPECTOR_OPTIONS) {
|
|
@@ -147,17 +143,10 @@ async function create (configOrRoot, sourceOrConfig, context) {
|
|
|
147
143
|
return runtime
|
|
148
144
|
}
|
|
149
145
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
module.exports.Runtime = Runtime
|
|
158
|
-
module.exports.wrapInRuntimeConfig = wrapInRuntimeConfig
|
|
159
|
-
module.exports.version = platformaticVersion
|
|
160
|
-
module.exports.loadConfiguration = loadConfiguration
|
|
161
|
-
module.exports.create = create
|
|
162
|
-
module.exports.transform = transform
|
|
163
|
-
module.exports.loadServicesCommands = loadServicesCommands
|
|
146
|
+
export { transform, wrapInRuntimeConfig } from './lib/config.js'
|
|
147
|
+
export * as errors from './lib/errors.js'
|
|
148
|
+
export { RuntimeGenerator as Generator, WrappedGenerator } from './lib/generator.js'
|
|
149
|
+
export { Runtime } from './lib/runtime.js'
|
|
150
|
+
export { schema } from './lib/schema.js'
|
|
151
|
+
export * from './lib/version.js'
|
|
152
|
+
export * as symbols from './lib/worker/symbols.js'
|
package/lib/config.js
CHANGED
|
@@ -1,44 +1,88 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const { readdir } = require('node:fs/promises')
|
|
5
|
-
const { createRequire } = require('node:module')
|
|
6
|
-
const { importStackableAndConfig, validationOptions } = require('@platformatic/basic')
|
|
7
|
-
const {
|
|
8
|
-
kMetadata,
|
|
9
|
-
omitProperties,
|
|
10
|
-
loadModule,
|
|
11
|
-
runtimeUnwrappablePropertiesList,
|
|
1
|
+
import { importCapabilityAndConfig, validationOptions } from '@platformatic/basic'
|
|
2
|
+
import {
|
|
3
|
+
extractModuleFromSchemaUrl,
|
|
12
4
|
findConfigurationFile,
|
|
13
|
-
|
|
5
|
+
kMetadata,
|
|
14
6
|
loadConfiguration,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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 {
|
|
18
16
|
InspectAndInspectBrkError,
|
|
19
|
-
|
|
20
|
-
InvalidServicesWithWebError,
|
|
21
|
-
MissingEntrypointError,
|
|
17
|
+
InspectorHostError,
|
|
22
18
|
InspectorPortError,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
+
}
|
|
42
|
+
|
|
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
|
+
}
|
|
47
|
+
|
|
48
|
+
export function autoDetectPprofCapture (config) {
|
|
49
|
+
const require = createRequire(import.meta.url)
|
|
50
|
+
|
|
51
|
+
let pprofCapturePath
|
|
52
|
+
try {
|
|
53
|
+
pprofCapturePath = require.resolve('@platformatic/wattpm-pprof-capture')
|
|
54
|
+
} catch (err) {
|
|
55
|
+
// No-op
|
|
56
|
+
}
|
|
57
|
+
|
|
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
|
+
}
|
|
64
|
+
|
|
65
|
+
if (pprofCapturePath && !config.preload.includes(pprofCapturePath)) {
|
|
66
|
+
config.preload.push(pprofCapturePath)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return config
|
|
70
|
+
}
|
|
27
71
|
|
|
28
|
-
async function wrapInRuntimeConfig (config, context) {
|
|
29
|
-
let
|
|
72
|
+
export async function wrapInRuntimeConfig (config, context) {
|
|
73
|
+
let applicationId = 'main'
|
|
30
74
|
try {
|
|
31
|
-
const packageJson = join(config[kMetadata].root, 'package.json')
|
|
32
|
-
|
|
75
|
+
const packageJson = JSON.parse(await readFile(join(config[kMetadata].root, 'package.json'), 'utf-8'))
|
|
76
|
+
applicationId = packageJson?.name ?? 'main'
|
|
33
77
|
|
|
34
|
-
if (
|
|
35
|
-
|
|
78
|
+
if (applicationId.startsWith('@')) {
|
|
79
|
+
applicationId = applicationId.split('/')[1]
|
|
36
80
|
}
|
|
37
81
|
} catch (err) {
|
|
38
82
|
// on purpose, the package.json might be missing
|
|
39
83
|
}
|
|
40
84
|
|
|
41
|
-
// If the
|
|
85
|
+
// If the application supports its (so far, only @platformatic/service and descendants)
|
|
42
86
|
const { hostname, port, http2, https } = config.server ?? {}
|
|
43
87
|
const server = { hostname, port, http2, https }
|
|
44
88
|
const production = context?.isProduction ?? context?.production
|
|
@@ -50,10 +94,10 @@ async function wrapInRuntimeConfig (config, context) {
|
|
|
50
94
|
server,
|
|
51
95
|
watch: !production,
|
|
52
96
|
...omitProperties(config.runtime ?? {}, runtimeUnwrappablePropertiesList),
|
|
53
|
-
entrypoint:
|
|
54
|
-
|
|
97
|
+
entrypoint: applicationId,
|
|
98
|
+
applications: [
|
|
55
99
|
{
|
|
56
|
-
id:
|
|
100
|
+
id: applicationId,
|
|
57
101
|
path: config[kMetadata].root,
|
|
58
102
|
config: config[kMetadata].path
|
|
59
103
|
}
|
|
@@ -70,7 +114,7 @@ async function wrapInRuntimeConfig (config, context) {
|
|
|
70
114
|
})
|
|
71
115
|
}
|
|
72
116
|
|
|
73
|
-
function parseInspectorOptions (config, inspect, inspectBreak) {
|
|
117
|
+
export function parseInspectorOptions (config, inspect, inspectBreak) {
|
|
74
118
|
const hasInspect = inspect != null
|
|
75
119
|
const hasInspectBrk = inspectBreak != null
|
|
76
120
|
|
|
@@ -112,19 +156,9 @@ function parseInspectorOptions (config, inspect, inspectBreak) {
|
|
|
112
156
|
config.watch = false
|
|
113
157
|
}
|
|
114
158
|
|
|
115
|
-
async function transform (config, _, context) {
|
|
159
|
+
export async function transform (config, _, context) {
|
|
116
160
|
const production = context?.isProduction ?? context?.production
|
|
117
|
-
|
|
118
|
-
let services
|
|
119
|
-
if (config.web?.length) {
|
|
120
|
-
if (config.services?.length) {
|
|
121
|
-
throw new InvalidServicesWithWebError()
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
services = config.web
|
|
125
|
-
} else {
|
|
126
|
-
services = config.services ?? []
|
|
127
|
-
}
|
|
161
|
+
const applications = [...(config.applications ?? []), ...(config.services ?? []), ...(config.web ?? [])]
|
|
128
162
|
|
|
129
163
|
const watchType = typeof config.watch
|
|
130
164
|
if (watchType === 'string') {
|
|
@@ -158,109 +192,134 @@ async function transform (config, _, context) {
|
|
|
158
192
|
config = join(entryPath, configFilename)
|
|
159
193
|
}
|
|
160
194
|
|
|
161
|
-
const
|
|
162
|
-
|
|
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)
|
|
163
204
|
|
|
164
|
-
if (
|
|
165
|
-
|
|
205
|
+
if (existingApplicationId !== -1) {
|
|
206
|
+
applications[existingApplicationId] = { ...application, ...applications[existingApplicationId] }
|
|
166
207
|
} else {
|
|
167
|
-
|
|
208
|
+
applications.push(application)
|
|
168
209
|
}
|
|
169
210
|
}
|
|
170
211
|
}
|
|
171
212
|
|
|
172
|
-
config.serviceMap = new Map()
|
|
173
213
|
config.inspectorOptions = undefined
|
|
174
214
|
parseInspectorOptions(config, context?.inspect, context?.inspectBreak)
|
|
175
215
|
|
|
176
216
|
let hasValidEntrypoint = false
|
|
177
217
|
|
|
178
|
-
|
|
179
|
-
|
|
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)
|
|
225
|
+
}
|
|
226
|
+
config.workers = coerced
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
for (let i = 0; i < applications.length; ++i) {
|
|
230
|
+
const application = applications[i]
|
|
180
231
|
|
|
181
232
|
// We need to have absolute paths here, ot the `loadConfig` will fail
|
|
182
233
|
// Make sure we don't resolve if env var was not replaced
|
|
183
|
-
if (
|
|
184
|
-
|
|
234
|
+
if (application.path && !isAbsolute(application.path) && !application.path.match(/^\{.*\}$/)) {
|
|
235
|
+
application.path = resolvePath(config[kMetadata].root, application.path)
|
|
185
236
|
}
|
|
186
237
|
|
|
187
|
-
if (
|
|
188
|
-
|
|
238
|
+
if (application.path && application.config) {
|
|
239
|
+
application.config = resolvePath(application.path, application.config)
|
|
189
240
|
}
|
|
190
241
|
|
|
191
242
|
try {
|
|
192
243
|
let pkg
|
|
193
244
|
|
|
194
|
-
if (
|
|
195
|
-
const config = await loadConfiguration(
|
|
196
|
-
pkg = await loadConfigurationModule(
|
|
245
|
+
if (application.config) {
|
|
246
|
+
const config = await loadConfiguration(application.config)
|
|
247
|
+
pkg = await loadConfigurationModule(application.path, config)
|
|
197
248
|
|
|
198
|
-
|
|
199
|
-
|
|
249
|
+
application.type = extractModuleFromSchemaUrl(config, true).module
|
|
250
|
+
application.skipTelemetryHooks = pkg.skipTelemetryHooks
|
|
200
251
|
} else {
|
|
201
|
-
const { moduleName,
|
|
202
|
-
pkg =
|
|
252
|
+
const { moduleName, capability } = await importCapabilityAndConfig(application.path)
|
|
253
|
+
pkg = capability
|
|
203
254
|
|
|
204
|
-
|
|
255
|
+
application.type = moduleName
|
|
205
256
|
}
|
|
206
257
|
|
|
207
|
-
|
|
258
|
+
application.skipTelemetryHooks = pkg.skipTelemetryHooks
|
|
208
259
|
|
|
209
260
|
// This is needed to work around Rust bug on dylibs:
|
|
210
261
|
// https://github.com/rust-lang/rust/issues/91979
|
|
211
262
|
// https://github.com/rollup/rollup/issues/5761
|
|
212
|
-
const _require = createRequire(
|
|
263
|
+
const _require = createRequire(application.path)
|
|
213
264
|
for (const m of pkg.modulesToLoad ?? []) {
|
|
214
265
|
const toLoad = _require.resolve(m)
|
|
215
266
|
loadModule(_require, toLoad).catch(() => {})
|
|
216
267
|
}
|
|
217
268
|
} catch (err) {
|
|
218
269
|
// This should not happen, it happens on running some unit tests if we prepare the runtime
|
|
219
|
-
// when not all the
|
|
220
|
-
// to ddetermine the type of the
|
|
221
|
-
|
|
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'
|
|
222
273
|
}
|
|
223
274
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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)
|
|
282
|
+
}
|
|
283
|
+
application.workers = coerced
|
|
284
|
+
}
|
|
228
285
|
|
|
229
|
-
|
|
230
|
-
|
|
286
|
+
application.entrypoint = application.id === config.entrypoint
|
|
287
|
+
application.dependencies ??= []
|
|
288
|
+
application.localUrl = `http://${application.id}.plt.local`
|
|
289
|
+
|
|
290
|
+
if (typeof application.watch === 'undefined') {
|
|
291
|
+
application.watch = config.watch
|
|
231
292
|
}
|
|
232
293
|
|
|
233
|
-
if (
|
|
294
|
+
if (application.entrypoint) {
|
|
234
295
|
hasValidEntrypoint = true
|
|
235
296
|
}
|
|
236
|
-
|
|
237
|
-
config.serviceMap.set(service.id, service)
|
|
238
297
|
}
|
|
239
298
|
|
|
240
299
|
// If there is no entrypoint, autodetect one
|
|
241
300
|
if (!config.entrypoint) {
|
|
242
|
-
// If there is only one
|
|
243
|
-
if (
|
|
244
|
-
|
|
245
|
-
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
|
|
246
305
|
hasValidEntrypoint = true
|
|
247
306
|
} else {
|
|
248
|
-
// Search if exactly
|
|
249
|
-
const
|
|
307
|
+
// Search if exactly application uses @platformatic/gateway
|
|
308
|
+
const gateways = []
|
|
250
309
|
|
|
251
|
-
for (const
|
|
252
|
-
if (!
|
|
310
|
+
for (const application of applications) {
|
|
311
|
+
if (!application.config) {
|
|
253
312
|
continue
|
|
254
313
|
}
|
|
255
314
|
|
|
256
|
-
if (
|
|
257
|
-
|
|
315
|
+
if (application.type === '@platformatic/gateway') {
|
|
316
|
+
gateways.push(application.id)
|
|
258
317
|
}
|
|
259
318
|
}
|
|
260
319
|
|
|
261
|
-
if (
|
|
262
|
-
|
|
263
|
-
config.entrypoint =
|
|
320
|
+
if (gateways.length === 1) {
|
|
321
|
+
applications.find(s => s.id === gateways[0]).entrypoint = true
|
|
322
|
+
config.entrypoint = gateways[0]
|
|
264
323
|
hasValidEntrypoint = true
|
|
265
324
|
}
|
|
266
325
|
}
|
|
@@ -269,16 +328,17 @@ async function transform (config, _, context) {
|
|
|
269
328
|
if (!hasValidEntrypoint && !context.allowMissingEntrypoint) {
|
|
270
329
|
if (config.entrypoint) {
|
|
271
330
|
throw new InvalidEntrypointError(config.entrypoint)
|
|
272
|
-
} else if (
|
|
331
|
+
} else if (applications.length >= 1) {
|
|
273
332
|
throw new MissingEntrypointError()
|
|
274
333
|
}
|
|
275
|
-
// If there are no
|
|
334
|
+
// If there are no applications, and no entrypoint it's an empty app.
|
|
276
335
|
// It won't start, but we should be able to parse and operate on it,
|
|
277
|
-
// like adding other
|
|
336
|
+
// like adding other applications.
|
|
278
337
|
}
|
|
279
338
|
|
|
280
|
-
config.
|
|
339
|
+
config.applications = applications
|
|
281
340
|
config.web = undefined
|
|
341
|
+
config.services = undefined
|
|
282
342
|
config.logger ??= {}
|
|
283
343
|
|
|
284
344
|
if (production) {
|
|
@@ -293,11 +353,8 @@ async function transform (config, _, context) {
|
|
|
293
353
|
}
|
|
294
354
|
}
|
|
295
355
|
|
|
296
|
-
|
|
297
|
-
|
|
356
|
+
// Auto-detect and add pprof capture if available
|
|
357
|
+
autoDetectPprofCapture(config)
|
|
298
358
|
|
|
299
|
-
|
|
300
|
-
wrapInRuntimeConfig,
|
|
301
|
-
parseInspectorOptions,
|
|
302
|
-
transform
|
|
359
|
+
return config
|
|
303
360
|
}
|