@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 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
- service: number | string;
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 service. Defaults to the folder name if not specified.
257
+ * The name of the application. Defaults to the folder name if not specified.
254
258
  */
255
- serviceName: string;
259
+ applicationName: string;
256
260
  /**
257
- * The version of the service (optional)
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
- serviceTimeout?: number | string;
337
+ applicationTimeout?: number | string;
334
338
  messagingTimeout?: number | string;
335
- resolvedServicesBasePath?: string;
339
+ resolvedApplicationsBasePath?: string;
336
340
  env?: {
337
341
  [k: string]: string;
338
342
  };
package/eslint.config.js CHANGED
@@ -1,8 +1,6 @@
1
- 'use strict'
1
+ import neostandard from 'neostandard'
2
2
 
3
- const neostandard = require('neostandard')
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 ServiceCommandContext = {
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 ServiceCommand = (
17
+ export type ApplicationCommand = (
18
18
  logger: Logger,
19
19
  configuration: Configuration<unknown>,
20
20
  args: string[],
21
- context: ServiceCommandContext
21
+ context: ApplicationCommandContext
22
22
  ) => Promise<void>
23
23
 
24
- export interface ServicesCommands {
25
- services: Record<string, Configuration<unknown>>
26
- commands: Record<string, ServiceCommand>
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 ServiceNotFoundError: (id: string) => FastifyError
34
- export const ServiceNotStartedError: (id: string) => FastifyError
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 ApplicationNotStartedError: () => FastifyError
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 kServiceId: unique symbol
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 loadServicesCommands (): Promise<ServicesCommands>
94
+ export declare function loadApplicationsCommands (): Promise<ApplicationsCommands>
package/index.js CHANGED
@@ -1,31 +1,27 @@
1
- 'use strict'
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
- findRuntimeConfigurationFile,
9
- loadConfiguration: utilsLoadConfiguration,
4
+ ensureLoggableError,
10
5
  extractModuleFromSchemaUrl,
11
- ensureLoggableError
12
- } = require('@platformatic/foundation')
13
- const { resolve, validationOptions } = require('@platformatic/basic')
14
- const { NodeInspectorFlagsNotSupportedError } = require('./lib/errors')
15
- const { wrapInRuntimeConfig, transform } = require('./lib/config')
16
- const { RuntimeGenerator, WrappedGenerator } = require('./lib/generator')
17
- const { Runtime } = require('./lib/runtime')
18
- const symbols = require('./lib/worker/symbols')
19
- const { schema } = require('./lib/schema')
20
- const { upgrade } = require('./lib/upgrade')
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 services ...')
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 services.')
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 loadServicesCommands () {
62
- const services = {}
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 { services, commands, help }
78
+ return { applications, commands, help }
83
79
  }
84
80
 
85
- for (const service of config.services) {
81
+ for (const application of config.applications) {
86
82
  try {
87
- const serviceConfig = await utilsLoadConfiguration(service.config)
88
- const pkg = await loadConfigurationModule(service.path, serviceConfig)
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(service.id)
87
+ const definition = await pkg.createCommands(application.id)
92
88
  for (const command of Object.keys(definition.commands)) {
93
- services[command] = service
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 service
97
+ // No-op, ignore the application
102
98
  }
103
99
  }
104
100
 
105
- return { services, commands, help }
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
- const platformaticVersion = require('./package.json').version
151
-
152
- module.exports.errors = require('./lib/errors')
153
- module.exports.Generator = RuntimeGenerator
154
- module.exports.WrappedGenerator = WrappedGenerator
155
- module.exports.schema = schema
156
- module.exports.symbols = symbols
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
- 'use strict'
2
-
3
- const { join, resolve: resolvePath, isAbsolute } = require('node:path')
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
- loadConfigurationModule,
5
+ kMetadata,
14
6
  loadConfiguration,
15
- extractModuleFromSchemaUrl
16
- } = require('@platformatic/foundation')
17
- const {
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
- InvalidEntrypointError,
20
- InvalidServicesWithWebError,
21
- MissingEntrypointError,
17
+ InspectorHostError,
22
18
  InspectorPortError,
23
- InspectorHostError
24
- } = require('./errors')
25
- const { schema } = require('./schema')
26
- const { upgrade } = require('./upgrade')
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 serviceId = 'main'
72
+ export async function wrapInRuntimeConfig (config, context) {
73
+ let applicationId = 'main'
30
74
  try {
31
- const packageJson = join(config[kMetadata].root, 'package.json')
32
- serviceId = require(packageJson).name || 'main'
75
+ const packageJson = JSON.parse(await readFile(join(config[kMetadata].root, 'package.json'), 'utf-8'))
76
+ applicationId = packageJson?.name ?? 'main'
33
77
 
34
- if (serviceId.startsWith('@')) {
35
- serviceId = serviceId.split('/')[1]
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 service supports its (so far, only @platformatic/service and descendants)
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: serviceId,
54
- services: [
97
+ entrypoint: applicationId,
98
+ applications: [
55
99
  {
56
- id: serviceId,
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 service = { id, config, path: entryPath, useHttp: !!mapping.useHttp, health: mapping.health }
162
- const existingServiceId = services.findIndex(service => service.id === id)
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 (existingServiceId !== -1) {
165
- services[existingServiceId] = { ...service, ...services[existingServiceId] }
205
+ if (existingApplicationId !== -1) {
206
+ applications[existingApplicationId] = { ...application, ...applications[existingApplicationId] }
166
207
  } else {
167
- services.push(service)
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
- for (let i = 0; i < services.length; ++i) {
179
- const service = services[i]
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 (service.path && !isAbsolute(service.path) && !service.path.match(/^\{.*\}$/)) {
184
- service.path = resolvePath(config[kMetadata].root, service.path)
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 (service.path && service.config) {
188
- service.config = resolvePath(service.path, service.config)
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 (service.config) {
195
- const config = await loadConfiguration(service.config)
196
- pkg = await loadConfigurationModule(service.path, config)
245
+ if (application.config) {
246
+ const config = await loadConfiguration(application.config)
247
+ pkg = await loadConfigurationModule(application.path, config)
197
248
 
198
- service.type = extractModuleFromSchemaUrl(config, true).module
199
- service.skipTelemetryHooks = pkg.skipTelemetryHooks
249
+ application.type = extractModuleFromSchemaUrl(config, true).module
250
+ application.skipTelemetryHooks = pkg.skipTelemetryHooks
200
251
  } else {
201
- const { moduleName, stackable } = await importStackableAndConfig(service.path)
202
- pkg = stackable
252
+ const { moduleName, capability } = await importCapabilityAndConfig(application.path)
253
+ pkg = capability
203
254
 
204
- service.type = moduleName
255
+ application.type = moduleName
205
256
  }
206
257
 
207
- service.skipTelemetryHooks = pkg.skipTelemetryHooks
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(service.path)
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 services configs are available. Given that we are running this only
220
- // to ddetermine the type of the service, it's safe to ignore this error and default to unknown
221
- service.type = 'unknown'
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
- service.entrypoint = service.id === config.entrypoint
225
- service.dependencies = []
226
- service.localServiceEnvVars = new Map()
227
- service.localUrl = `http://${service.id}.plt.local`
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
- if (typeof service.watch === 'undefined') {
230
- service.watch = config.watch
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 (service.entrypoint) {
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 service, it becomes the entrypoint
243
- if (services.length === 1) {
244
- services[0].entrypoint = true
245
- config.entrypoint = services[0].id
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 service uses @platformatic/composer
249
- const composers = []
307
+ // Search if exactly application uses @platformatic/gateway
308
+ const gateways = []
250
309
 
251
- for (const service of services) {
252
- if (!service.config) {
310
+ for (const application of applications) {
311
+ if (!application.config) {
253
312
  continue
254
313
  }
255
314
 
256
- if (service.type === '@platformatic/composer') {
257
- composers.push(service.id)
315
+ if (application.type === '@platformatic/gateway') {
316
+ gateways.push(application.id)
258
317
  }
259
318
  }
260
319
 
261
- if (composers.length === 1) {
262
- services.find(s => s.id === composers[0]).entrypoint = true
263
- config.entrypoint = composers[0]
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 (services.length >= 1) {
331
+ } else if (applications.length >= 1) {
273
332
  throw new MissingEntrypointError()
274
333
  }
275
- // If there are no services, and no entrypoint it's an empty app.
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 services.
336
+ // like adding other applications.
278
337
  }
279
338
 
280
- config.services = services
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
- return config
297
- }
356
+ // Auto-detect and add pprof capture if available
357
+ autoDetectPprofCapture(config)
298
358
 
299
- module.exports = {
300
- wrapInRuntimeConfig,
301
- parseInspectorOptions,
302
- transform
359
+ return config
303
360
  }