@platformatic/runtime 3.68.0 → 4.0.0-new-config.1

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/lib/config.js CHANGED
@@ -9,22 +9,24 @@ import {
9
9
  omitProperties,
10
10
  runtimeUnwrappablePropertiesList
11
11
  } from '@platformatic/foundation'
12
- import { realpathSync } from 'node:fs'
13
12
  import { readdir, readFile } from 'node:fs/promises'
14
13
  import { createRequire } from 'node:module'
14
+ import { loadAdditionalApplications } from '@platformatic/foundation/lib/v4/index.js'
15
15
  import { isAbsolute, join, resolve as resolvePath } from 'node:path'
16
+ import { fileURLToPath } from 'node:url'
16
17
 
17
18
  import {
18
- ApplicationIdCollisionError,
19
19
  InspectAndInspectBrkError,
20
20
  InspectorHostError,
21
21
  InspectorPortError,
22
- InvalidArgumentError,
23
- InvalidEntrypointError
22
+ InvalidArgumentError
24
23
  } from './errors.js'
25
24
  import { schema } from './schema.js'
26
25
  import { upgrade } from './upgrade.js'
27
26
 
27
+ // The runtime package's own entry point, which is where the bundled capability copies live.
28
+ const runtimeScopePath = fileURLToPath(new URL('../index.js', import.meta.url))
29
+
28
30
  // Validate and coerce workers values early to avoid runtime hangs when invalid
29
31
  function coercePositiveInteger (value) {
30
32
  if (typeof value === 'number') {
@@ -143,17 +145,6 @@ export async function wrapInRuntimeConfig (config, context) {
143
145
  // on purpose, the package.json might be missing
144
146
  }
145
147
 
146
- // Carry over only the server properties that the user actually set, so
147
- // we do not end up with a `{ hostname: undefined, ... }` object that then
148
- // gets populated by schema defaults or trips truthy checks downstream.
149
- const server = {}
150
- if (config.server) {
151
- for (const key of ['hostname', 'port', 'http2', 'https']) {
152
- if (config.server[key] !== undefined) {
153
- server[key] = config.server[key]
154
- }
155
- }
156
- }
157
148
  const production = context?.isProduction ?? context?.production
158
149
 
159
150
  const runtimeConfig = config.runtime ?? {}
@@ -162,10 +153,8 @@ export async function wrapInRuntimeConfig (config, context) {
162
153
  /* c8 ignore next */
163
154
  const wrapped = {
164
155
  $schema: schema.$id,
165
- ...(Object.keys(server).length > 0 ? { server } : {}),
166
156
  watch: !production,
167
157
  ...omitProperties(runtimeConfig, runtimeUnwrappablePropertiesList),
168
- entrypoint: applicationId,
169
158
  applications: [
170
159
  {
171
160
  id: applicationId,
@@ -228,6 +217,49 @@ export function parseInspectorOptions (config, inspect, inspectBreak) {
228
217
  config.watch = false
229
218
  }
230
219
 
220
+ /*
221
+ The one entry point for applications added while the runtime is running, shared by the HTTP route
222
+ and the management ITC handler so the two cannot drift.
223
+
224
+ Under v4 an added application is evaluated exactly as boot evaluates one -- its configuration
225
+ file is found in its own directory, its environment is resolved main-side, and it arrives with
226
+ resolvedConfig. Skipping that leaves the worker to look for a v3 file name that v4 never writes,
227
+ which fails as an unhelpful "unable to initialize the worker".
228
+ */
229
+ export async function prepareAddedApplications (config, entries, existingIds = []) {
230
+ const metadata = config[kMetadata]
231
+
232
+ if (!metadata?.v4) {
233
+ const prepared = []
234
+
235
+ for (const entry of entries) {
236
+ prepared.push(await prepareApplication(config, entry, config.workers))
237
+ }
238
+
239
+ return prepared
240
+ }
241
+
242
+ const { applications } = await loadAdditionalApplications({
243
+ configPath: metadata.path,
244
+ entries,
245
+ existingIds,
246
+ rootEnvBlock: config.env,
247
+ command: metadata.v4.command,
248
+ mode: metadata.v4.mode,
249
+ production: metadata.v4.production,
250
+ // The runtime is the fallback scope for capability resolution, the same as at boot.
251
+ runtimeScope: runtimeScopePath
252
+ })
253
+
254
+ const prepared = []
255
+
256
+ for (const application of applications) {
257
+ prepared.push(await prepareV4Application(config, application, config.workers))
258
+ }
259
+
260
+ return prepared
261
+ }
262
+
231
263
  export async function prepareApplication (config, application, defaultWorkers) {
232
264
  // We need to have absolute paths here, ot the `loadConfig` will fail
233
265
  // Make sure we don't resolve if env var was not replaced
@@ -249,10 +281,10 @@ export async function prepareApplication (config, application, defaultWorkers) {
249
281
  let pkg
250
282
 
251
283
  if (application.config) {
252
- const config = await loadConfiguration(application.config)
253
- pkg = await loadConfigurationModule(application.path, config)
284
+ const applicationConfig = await loadConfiguration(application.config)
285
+ pkg = await loadConfigurationModule(application.path, applicationConfig)
254
286
 
255
- application.type = extractModuleFromSchemaUrl(config, true).module
287
+ application.type = extractModuleFromSchemaUrl(applicationConfig, true).module
256
288
  application.skipTelemetryHooks = pkg.skipTelemetryHooks
257
289
  } else {
258
290
  const { moduleName, capability } = await importCapabilityAndConfig(application.path)
@@ -279,10 +311,16 @@ export async function prepareApplication (config, application, defaultWorkers) {
279
311
  }
280
312
  }
281
313
 
314
+ return finalizeApplication(config, application, defaultWorkers)
315
+ }
316
+
317
+ // Everything an application needs regardless of how its capability was determined. v3 discovers
318
+ // that by loading the application's config file; v4 has it from the loader's envelope before any
319
+ // worker exists.
320
+ export function finalizeApplication (config, application, defaultWorkers) {
282
321
  // Validate and coerce per-service workers
283
322
  parseWorkers(application, `Service "${application.id}"`, defaultWorkers)
284
323
 
285
- application.entrypoint = application.id === config.entrypoint
286
324
  application.dependencies ??= []
287
325
  application.localUrl = `http://${application.id}.plt.local`
288
326
 
@@ -297,38 +335,37 @@ export async function prepareApplication (config, application, defaultWorkers) {
297
335
  return application
298
336
  }
299
337
 
300
- function canonicalPath (path) {
301
- try {
302
- return realpathSync(path)
303
- } catch {
304
- return resolvePath(path)
305
- }
306
- }
307
-
308
- // An autoloaded directory and an explicitly configured entry with the same id are the same application
309
- // only when they point to the same place: either the configured path resolves to the autoloaded
310
- // directory, or the entry is external and the autoloaded directory is where "resolve" would put it.
311
- // When they don't, returns a description of the configured entry to report in the error.
312
- function conflictingApplicationSource (root, resolvedApplicationsPath, existing, entryPath) {
313
- if (existing.path) {
314
- // The path still contains a placeholder, which means the environment variable was not replaced.
315
- // There is nothing to compare in that case.
316
- if (existing.path.match(/^\{.*\}$/)) {
317
- return null
338
+ /*
339
+ The v4 preparation. The loader resolved the path, selected the capability and imported its schema
340
+ subpath — which carries skipTelemetryHooks and modulesToLoad — all main-side, before any worker
341
+ existed. So there is nothing to discover here, and in particular no application config file to
342
+ re-read: that is the whole point of evaluating configuration exactly once per load.
343
+ */
344
+ export async function prepareV4Application (config, application, defaultWorkers) {
345
+ // resolvedConfig replaces v3's config file path in workerData: the worker receives the validated
346
+ // capability payload as data and never re-reads a file.
347
+ application.resolvedConfig = application.config ?? {}
348
+ application.config = undefined
349
+ application.type = application.module ?? 'unknown'
350
+ application.skipTelemetryHooks = application.capabilityMetadata?.skipTelemetryHooks ?? false
351
+
352
+ // This is needed to work around a Rust bug on dylibs, as in the v3 path.
353
+ const modulesToLoad = application.capabilityMetadata?.modulesToLoad ?? []
354
+
355
+ if (modulesToLoad.length > 0 && application.path) {
356
+ const _require = createRequire(application.path)
357
+
358
+ for (const m of modulesToLoad) {
359
+ try {
360
+ loadModule(_require, _require.resolve(m)).catch(() => {})
361
+ } catch {
362
+ // A module the capability names but the application cannot resolve is not fatal here; the
363
+ // worker reports it with its own context when it actually needs it.
364
+ }
318
365
  }
319
-
320
- const existingPath = isAbsolute(existing.path) ? existing.path : resolvePath(root, existing.path)
321
-
322
- return canonicalPath(existingPath) === canonicalPath(entryPath) ? null : `the path "${existing.path}"`
323
366
  }
324
367
 
325
- if (existing.url) {
326
- const resolvedPath = join(resolvedApplicationsPath, existing.id)
327
-
328
- return canonicalPath(resolvedPath) === canonicalPath(entryPath) ? null : `the URL "${existing.url}"`
329
- }
330
-
331
- return null
368
+ return finalizeApplication(config, application, defaultWorkers)
332
369
  }
333
370
 
334
371
  function isApplicationEnabled (application, environment) {
@@ -393,7 +430,7 @@ export async function transform (config, _, context) {
393
430
  }
394
431
 
395
432
  const scaleConfig = config.verticalScaler.applications[appId]
396
- const workersConfig = appConfig.workers
433
+ const workersConfig = appConfig.workers ??= {}
397
434
 
398
435
  workersConfig.minimum ??= scaleConfig.minWorkers ?? config.workers.minimum
399
436
  workersConfig.maximum ??= scaleConfig.maxWorkers ?? config.workers.maximum
@@ -414,11 +451,7 @@ export async function transform (config, _, context) {
414
451
  const { exclude = [], mappings = {} } = config.autoload
415
452
  let { path } = config.autoload
416
453
 
417
- // Capture these before the loop, as config is shadowed in its body
418
- const root = config[kMetadata].root
419
- const resolvedApplicationsPath = resolvePath(root, config.resolvedApplicationsBasePath ?? 'external')
420
-
421
- path = resolvePath(root, path)
454
+ path = resolvePath(config[kMetadata].root, path)
422
455
  const entries = await readdir(path, { withFileTypes: true })
423
456
 
424
457
  for (let i = 0; i < entries.length; ++i) {
@@ -443,21 +476,7 @@ export async function transform (config, _, context) {
443
476
  const existingApplicationId = applications.findIndex(application => application.id === id)
444
477
 
445
478
  if (existingApplicationId !== -1) {
446
- const existing = applications[existingApplicationId]
447
-
448
- // Merging on the id alone can boot local code where the configuration named a repository, as
449
- // the autoloaded path survives next to the configured url. Reject the duplicate instead: an id
450
- // is the mesh hostname, the injected PLT_<ID>_URL name, the metrics label and the argument of
451
- // "wattpm inject", so two different applications cannot share one.
452
- if (isApplicationEnabled(existing, environment)) {
453
- const source = conflictingApplicationSource(root, resolvedApplicationsPath, existing, entryPath)
454
-
455
- if (source) {
456
- throw new ApplicationIdCollisionError(id, entryPath, source)
457
- }
458
- }
459
-
460
- applications[existingApplicationId] = { ...application, ...existing }
479
+ applications[existingApplicationId] = { ...application, ...applications[existingApplicationId] }
461
480
  } else {
462
481
  applications.push(application)
463
482
  }
@@ -470,54 +489,22 @@ export async function transform (config, _, context) {
470
489
  }
471
490
  }
472
491
 
492
+ return finalizeConfiguration(config, applications, context, production, prepareApplication)
493
+ }
494
+
495
+ // The half of the transform the loader does not own: inspector options, worker counts, the
496
+ // per-application preparation, and the runtime-level normalizations. v4 reaches this directly,
497
+ // having already expanded autoload and resolved enabled in the eval worker.
498
+ export async function finalizeConfiguration (config, applications, context, production, prepare) {
473
499
  config.inspectorOptions = undefined
474
500
  parseInspectorOptions(config, context?.inspect, context?.inspectBreak)
475
501
 
476
- let hasValidEntrypoint = false
477
-
478
502
  // Root-level workers
479
503
  parseWorkers(config, 'Runtime', { static: 1, dynamic: false })
480
504
  const defaultWorkers = config.workers
481
505
 
482
506
  for (let i = 0; i < applications.length; ++i) {
483
- const application = await prepareApplication(config, applications[i], defaultWorkers)
484
-
485
- if (application.entrypoint) {
486
- hasValidEntrypoint = true
487
- }
488
- }
489
-
490
- // If there is no entrypoint, autodetect one
491
- if (!config.entrypoint) {
492
- // If there is only one application, it becomes the entrypoint
493
- if (applications.length === 1) {
494
- applications[0].entrypoint = true
495
- config.entrypoint = applications[0].id
496
- hasValidEntrypoint = true
497
- } else {
498
- // Search if exactly application uses @platformatic/gateway
499
- const gateways = []
500
-
501
- for (const application of applications) {
502
- if (!application.config) {
503
- continue
504
- }
505
-
506
- if (application.type === '@platformatic/gateway') {
507
- gateways.push(application.id)
508
- }
509
- }
510
-
511
- if (gateways.length === 1) {
512
- applications.find(s => s.id === gateways[0]).entrypoint = true
513
- config.entrypoint = gateways[0]
514
- hasValidEntrypoint = true
515
- }
516
- }
517
- }
518
-
519
- if (!hasValidEntrypoint && config.entrypoint && !context.allowMissingEntrypoint) {
520
- throw new InvalidEntrypointError(config.entrypoint)
507
+ await prepare(config, applications[i], defaultWorkers)
521
508
  }
522
509
 
523
510
  if (typeof config.metrics === 'boolean') {
@@ -557,3 +544,27 @@ export async function transform (config, _, context) {
557
544
 
558
545
  return config
559
546
  }
547
+
548
+ /*
549
+ The v4 transform. What is absent is the point:
550
+
551
+ - no alias merging, because `services` and `web` do not exist in v4;
552
+ - no autoload expansion and no `enabled` filtering, because both ran in the root eval worker,
553
+ which is the only place either runs. Leaving them reachable here would let a second expansion
554
+ re-merge entries and read the filesystem after the authoritative snapshot already exists;
555
+ - no verticalScaler migration, which the schema audit removes.
556
+
557
+ The `autoload` declaration survives as data beside the expanded list — `GET /metadata` reports it
558
+ and `applications:add --save` needs it to decide whether a new application belongs in a mapping
559
+ or as an explicit entry. It is carried, never re-executed.
560
+ */
561
+ export async function transformV4 (config, _, context) {
562
+ const production = context?.isProduction ?? context?.production
563
+ const applications = config.applications ?? []
564
+
565
+ if (typeof config.watch === 'undefined') {
566
+ config.watch = !production
567
+ }
568
+
569
+ return finalizeConfiguration(config, applications, context, production, prepareV4Application)
570
+ }
package/lib/errors.js CHANGED
@@ -13,7 +13,11 @@ export const ERROR_PREFIX = 'PLT_RUNTIME'
13
13
 
14
14
  export const AddressInUseError = createError(
15
15
  `${ERROR_PREFIX}_EADDR_IN_USE`,
16
- 'The current port is in use by another application'
16
+ 'Port %d is already in use by applications "%s" and "%s"'
17
+ )
18
+ export const WorkerAddressInUseError = createError(
19
+ `${ERROR_PREFIX}_WORKER_EADDR_IN_USE`,
20
+ 'Port %d is already in use by another worker of the application "%s". Multiple workers can share a port only when the reusePort feature is available in your OS, otherwise set "server.portAssignment" to "perWorkerIncrement" in the application configuration or use a single worker.'
17
21
  )
18
22
  export const RuntimeExitedError = createError(
19
23
  `${ERROR_PREFIX}_RUNTIME_EXIT`,
@@ -98,18 +102,6 @@ export const NoConfigFileFoundError = createError(
98
102
  `${ERROR_PREFIX}_NO_CONFIG_FILE_FOUND`,
99
103
  "No config file found for application '%s'"
100
104
  )
101
- export const InvalidEntrypointError = createError(
102
- `${ERROR_PREFIX}_INVALID_ENTRYPOINT`,
103
- "Invalid entrypoint: '%s' does not exist"
104
- )
105
- export const ApplicationIdCollisionError = createError(
106
- `${ERROR_PREFIX}_APPLICATION_ID_COLLISION`,
107
- 'The application id "%s" is used by the autoloaded directory "%s" and by a different application defined in the configuration file via %s. Application ids must be unique.'
108
- )
109
- export const MissingEntrypointError = createError(
110
- `${ERROR_PREFIX}_MISSING_ENTRYPOINT`,
111
- 'Missing application entrypoint.'
112
- )
113
105
  export const MissingDependencyError = createError(`${ERROR_PREFIX}_MISSING_DEPENDENCY`, 'Missing dependency: "%s"')
114
106
  export const InspectAndInspectBrkError = createError(
115
107
  `${ERROR_PREFIX}_INSPECT_AND_INSPECT_BRK`,
@@ -232,10 +224,6 @@ export const HealthSignalTypeMustBeStringError = createError(
232
224
  `${ERROR_PREFIX}_HEALTH_SIGNAL_TYPE_MUST_BE_STRING`,
233
225
  'Health signal type must be a string, received "%s"'
234
226
  )
235
- export const CannotRemoveEntrypointError = createError(
236
- `${ERROR_PREFIX}_CANNOT_REMOVE_ENTRYPOINT`,
237
- 'Cannot remove the entrypoint application.'
238
- )
239
227
  export const WorkerInterceptorNotReadyError = createError(
240
228
  `${ERROR_PREFIX}_WORKER_INTERCEPTOR_NOT_READY`,
241
229
  'The "%s" application worker interceptor is not ready'
package/lib/generator.js CHANGED
@@ -1,4 +1,3 @@
1
- import createError from '@fastify/error'
2
1
  import {
3
2
  createEnvFileTool,
4
3
  defaultPackageManager,
@@ -23,44 +22,20 @@ const engines = {
23
22
  node: '>=22.19.0'
24
23
  }
25
24
 
26
- export const ERROR_PREFIX = 'PLT_RUNTIME_GEN'
27
-
28
- const NoApplicationNamedError = createError(
29
- `${ERROR_PREFIX}_NO_APPLICATION_FOUND`,
30
- "No application named '%s' has been added to this runtime."
31
- )
32
- const NoEntryPointError = createError(`${ERROR_PREFIX}_NO_ENTRYPOINT`, 'No entrypoint had been defined.')
33
-
34
- function getRuntimeWrappableProperties (skipServer) {
35
- const wrappableProperties = {
25
+ function getRuntimeWrappableProperties () {
26
+ return {
36
27
  logger: {
37
28
  level: '{PLT_SERVER_LOGGER_LEVEL}'
38
29
  },
39
30
  managementApi: '{PLT_MANAGEMENT_API}'
40
31
  }
41
-
42
- if (!skipServer) {
43
- wrappableProperties.server = {
44
- hostname: '{PLT_SERVER_HOSTNAME}',
45
- port: '{PORT}'
46
- }
47
- }
48
-
49
- return wrappableProperties
50
32
  }
51
33
 
52
34
  function getRuntimeBaseEnvVars (config) {
53
- const env = {}
54
-
55
- if (!config.skipServer) {
56
- env.PLT_SERVER_HOSTNAME = '127.0.0.1'
57
- env.PORT = config.port || 3042
35
+ return {
36
+ PLT_SERVER_LOGGER_LEVEL: config.logLevel || 'info',
37
+ PLT_MANAGEMENT_API: true
58
38
  }
59
-
60
- env.PLT_SERVER_LOGGER_LEVEL = config.logLevel || 'info'
61
- env.PLT_MANAGEMENT_API = true
62
-
63
- return env
64
39
  }
65
40
 
66
41
  export class RuntimeGenerator extends BaseGenerator {
@@ -73,7 +48,6 @@ export class RuntimeGenerator extends BaseGenerator {
73
48
  this.applicationsFolder = opts.applicationsFolder ?? 'applications'
74
49
  this.applications = []
75
50
  this.existingApplications = []
76
- this.entryPoint = null
77
51
  this.packageManager = opts.packageManager ?? defaultPackageManager
78
52
  }
79
53
 
@@ -97,15 +71,6 @@ export class RuntimeGenerator extends BaseGenerator {
97
71
  application.setRuntime(this)
98
72
  }
99
73
 
100
- setEntryPoint (entryPoint) {
101
- const application =
102
- this.existingApplications.includes(entryPoint) || this.applications.find(svc => svc.name === entryPoint)
103
- if (!application) {
104
- throw new NoApplicationNamedError(entryPoint)
105
- }
106
- this.entryPoint = application
107
- }
108
-
109
74
  async generatePackageJson () {
110
75
  const template = {
111
76
  name: `${this.runtimeName}`,
@@ -165,8 +130,6 @@ export class RuntimeGenerator extends BaseGenerator {
165
130
 
166
131
  const { PLT_ROOT, ...existingEnvironment } = this.existingConfig[kMetadata].env
167
132
  this.config.env = existingEnvironment
168
- this.config.port = this.config.env.PORT
169
- this.entryPoint = this.existingConfig.applications.find(svc => svc.entrypoint)
170
133
  this.existingApplications = this.existingConfig.applications.map(s => s.id)
171
134
 
172
135
  this.updateRuntimeConfig(this.existingConfigRaw)
@@ -190,37 +153,42 @@ export class RuntimeGenerator extends BaseGenerator {
190
153
  }
191
154
 
192
155
  setApplicationsConfigValues () {
193
- this.applications.forEach(({ application }) => {
156
+ let newApplicationOrdinal = 0
157
+ this.applications.forEach(({ name, application }) => {
194
158
  if (!application.config) {
195
159
  // set default config
196
160
  application.setConfig()
197
161
  }
162
+ const existingOrdinal = this.existingApplications.indexOf(name)
163
+ const ordinal = existingOrdinal === -1 ? this.existingApplications.length + newApplicationOrdinal++ : existingOrdinal
164
+ this.setApplicationPort(application, ordinal)
198
165
  })
199
166
  }
200
167
 
168
+ setApplicationPort (application, ordinal) {
169
+ if (application.config.port === 3042) {
170
+ application.setConfig({ port: 3042 + ordinal })
171
+ }
172
+ }
173
+
201
174
  async _getConfigFileContents () {
202
175
  const config = {
203
176
  $schema: `https://schemas.platformatic.dev/wattpm/${this.platformaticVersion}.json`,
204
- entrypoint: this.entryPoint.name,
205
177
  watch: true,
206
178
  autoload: {
207
179
  path: this.config.autoload || this.applicationsFolder,
208
180
  exclude: ['docs']
209
181
  },
210
- ...getRuntimeWrappableProperties(this.config.skipServer)
182
+ ...getRuntimeWrappableProperties()
211
183
  }
212
184
 
213
185
  return config
214
186
  }
215
187
 
216
188
  async _afterPrepare () {
217
- if (!this.entryPoint) {
218
- throw new NoEntryPointError()
219
- }
220
189
  const applicationsEnv = await this.prepareApplicationFiles()
221
190
  this.addEnvVars({
222
191
  ...this.config.env,
223
- ...this.getRuntimeEnv(),
224
192
  ...applicationsEnv
225
193
  })
226
194
 
@@ -258,21 +226,6 @@ export class RuntimeGenerator extends BaseGenerator {
258
226
 
259
227
  async prepareQuestions () {
260
228
  await this.populateFromExistingConfig()
261
-
262
- if (this.existingConfig) {
263
- return
264
- }
265
-
266
- if (!this.config.skipServer) {
267
- // port
268
- this.questions.push({
269
- type: 'input',
270
- name: 'port',
271
- default: '3042',
272
- message: 'What port do you want to use?',
273
- filter: Number
274
- })
275
- }
276
229
  }
277
230
 
278
231
  setApplicationsDirectory () {
@@ -322,12 +275,6 @@ export class RuntimeGenerator extends BaseGenerator {
322
275
  // do nothing, makes no sense
323
276
  }
324
277
 
325
- getRuntimeEnv () {
326
- return {
327
- PORT: this.config.port
328
- }
329
- }
330
-
331
278
  async postInstallActions () {
332
279
  for (const { application } of this.applications) {
333
280
  await application.postInstallActions()
@@ -451,6 +398,7 @@ export class RuntimeGenerator extends BaseGenerator {
451
398
  })
452
399
  }
453
400
  applicationInstance.setConfig(baseConfig)
401
+ this.setApplicationPort(applicationInstance, allNewApplicationsNames.indexOf(newApplication.name))
454
402
  applicationInstance.setConfigFields(newApplication.fields)
455
403
 
456
404
  const applicationEnvPrefix = `PLT_${applicationInstance.config.envPrefix}`
@@ -494,18 +442,6 @@ export class RuntimeGenerator extends BaseGenerator {
494
442
  contents: JSON.stringify(currrentPackageJson, null, 2)
495
443
  })
496
444
 
497
- // set new entrypoint if specified
498
- const newEntrypoint = newConfig.entrypoint
499
- if (newEntrypoint) {
500
- // load platformatic.json runtime config
501
- const runtimePkgConfigFileData = JSON.parse(
502
- await readFile(join(this.targetDirectory, this.runtimeConfig), 'utf-8')
503
- )
504
-
505
- this.setEntryPoint(newEntrypoint)
506
- runtimePkgConfigFileData.entrypoint = newEntrypoint
507
- this.updateRuntimeConfig(runtimePkgConfigFileData)
508
- }
509
445
  await this.writeFiles()
510
446
  // save new env
511
447
  await envTool.save()
@@ -548,15 +484,6 @@ export class RuntimeGenerator extends BaseGenerator {
548
484
  tags: ['runtime-env']
549
485
  })
550
486
  }
551
-
552
- updateConfigEntryPoint (entrypoint) {
553
- // This can return null if the generator was not supposed to modify the config
554
- const configObject = this.getRuntimeConfigFileObject()
555
- const config = JSON.parse(configObject.contents)
556
- config.entrypoint = entrypoint
557
-
558
- this.updateRuntimeConfig(config)
559
- }
560
487
  }
561
488
 
562
489
  export class WrappedGenerator extends BaseGenerator {
@@ -626,7 +553,7 @@ export class WrappedGenerator extends BaseGenerator {
626
553
  async #createConfigFile () {
627
554
  const config = {
628
555
  $schema: `https://schemas.platformatic.dev/${this.module}/${this.platformaticVersion}.json`,
629
- runtime: getRuntimeWrappableProperties(this.config.skipServer)
556
+ runtime: getRuntimeWrappableProperties()
630
557
  }
631
558
 
632
559
  this.addFile({
@@ -14,7 +14,7 @@ import { platform, tmpdir } from 'node:os'
14
14
  import { dirname, join } from 'node:path'
15
15
  import { setTimeout as sleep } from 'node:timers/promises'
16
16
  import { createWebSocketStream } from 'ws'
17
- import { prepareApplication } from './config.js'
17
+ import { prepareAddedApplications } from './config.js'
18
18
 
19
19
  const PLATFORMATIC_TMP_DIR = join(tmpdir(), 'platformatic', 'runtimes')
20
20
 
@@ -169,11 +169,9 @@ export async function managementApiPlugin (app, opts) {
169
169
  }
170
170
  }
171
171
 
172
- for (let i = 0; i < applications.length; i++) {
173
- applications[i] = await prepareApplication(config, applications[i], config.workers)
174
- }
172
+ const prepared = await prepareAddedApplications(config, applications, runtime.getApplicationsIds())
175
173
 
176
- const created = await runtime.addApplications(applications, request.query.start !== 'false')
174
+ const created = await runtime.addApplications(prepared, request.query.start !== 'false')
177
175
  reply.code(201)
178
176
  return created
179
177
  })
@@ -3,7 +3,7 @@ import {
3
3
  kMetadata,
4
4
  validate
5
5
  } from '@platformatic/foundation'
6
- import { prepareApplication } from './config.js'
6
+ import { prepareAddedApplications } from './config.js'
7
7
 
8
8
  const allOperations = [
9
9
  'getRuntimeStatus',
@@ -138,11 +138,9 @@ export function createManagementHandlers (runtime, allowedOperations) {
138
138
 
139
139
  validate(applicationSchema, applications, {}, true, config[kMetadata].root)
140
140
 
141
- for (let i = 0; i < applications.length; i++) {
142
- applications[i] = await prepareApplication(config, applications[i], config.workers)
143
- }
141
+ const prepared = await prepareAddedApplications(config, applications, runtime.getApplicationsIds())
144
142
 
145
- return runtime.addApplications(applications, start)
143
+ return runtime.addApplications(prepared, start)
146
144
  })
147
145
 
148
146
  register('removeApplications', async ({ ids }) => {