@platformatic/runtime 3.4.1 → 3.5.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.
Files changed (49) hide show
  1. package/README.md +1 -1
  2. package/config.d.ts +224 -77
  3. package/eslint.config.js +3 -5
  4. package/index.d.ts +73 -24
  5. package/index.js +173 -29
  6. package/lib/config.js +279 -197
  7. package/lib/errors.js +126 -34
  8. package/lib/generator.js +640 -0
  9. package/lib/logger.js +43 -41
  10. package/lib/management-api.js +109 -118
  11. package/lib/prom-server.js +202 -16
  12. package/lib/runtime.js +1963 -585
  13. package/lib/scheduler.js +119 -0
  14. package/lib/schema.js +22 -234
  15. package/lib/shared-http-cache.js +43 -0
  16. package/lib/upgrade.js +6 -8
  17. package/lib/utils.js +6 -61
  18. package/lib/version.js +7 -0
  19. package/lib/versions/v1.36.0.js +2 -4
  20. package/lib/versions/v1.5.0.js +2 -4
  21. package/lib/versions/v2.0.0.js +3 -5
  22. package/lib/versions/v3.0.0.js +16 -0
  23. package/lib/worker/controller.js +302 -0
  24. package/lib/worker/http-cache.js +171 -0
  25. package/lib/worker/interceptors.js +190 -10
  26. package/lib/worker/itc.js +146 -59
  27. package/lib/worker/main.js +220 -81
  28. package/lib/worker/messaging.js +182 -0
  29. package/lib/worker/round-robin-map.js +62 -0
  30. package/lib/worker/shared-context.js +22 -0
  31. package/lib/worker/symbols.js +14 -5
  32. package/package.json +47 -38
  33. package/schema.json +1383 -55
  34. package/help/compile.txt +0 -8
  35. package/help/help.txt +0 -5
  36. package/help/start.txt +0 -21
  37. package/index.test-d.ts +0 -41
  38. package/lib/build-server.js +0 -69
  39. package/lib/compile.js +0 -98
  40. package/lib/dependencies.js +0 -59
  41. package/lib/generator/README.md +0 -32
  42. package/lib/generator/errors.js +0 -10
  43. package/lib/generator/runtime-generator.d.ts +0 -37
  44. package/lib/generator/runtime-generator.js +0 -498
  45. package/lib/start.js +0 -190
  46. package/lib/worker/app.js +0 -278
  47. package/lib/worker/default-stackable.js +0 -33
  48. package/lib/worker/metrics.js +0 -122
  49. package/runtime.mjs +0 -54
@@ -1,498 +0,0 @@
1
- 'use strict'
2
-
3
- const { BaseGenerator } = require('@platformatic/generators')
4
- const { NoEntryPointError, NoServiceNamedError } = require('./errors')
5
- const generateName = require('boring-name-generator')
6
- const { join } = require('node:path')
7
- const { envObjectToString } = require('@platformatic/generators/lib/utils')
8
- const { readFile, readdir, stat } = require('node:fs/promises')
9
- const { ConfigManager } = require('@platformatic/config')
10
- const { platformaticRuntime } = require('../config')
11
- const { getServiceTemplateFromSchemaUrl } = require('@platformatic/generators/lib/utils')
12
- const { DotEnvTool } = require('dotenv-tool')
13
- const { getArrayDifference } = require('../utils')
14
- const { createRequire } = require('node:module')
15
- const { pathToFileURL } = require('node:url')
16
- const { safeRemove } = require('@platformatic/utils')
17
-
18
- class RuntimeGenerator extends BaseGenerator {
19
- constructor (opts) {
20
- super({
21
- ...opts,
22
- module: '@platformatic/runtime',
23
- })
24
- this.runtimeName = opts.name
25
- this.services = []
26
- this.entryPoint = null
27
- }
28
-
29
- async addService (service, name) {
30
- // ensure service config is correct
31
- const originalConfig = service.config
32
- const serviceName = name || generateName().dashed
33
- const newConfig = {
34
- ...originalConfig,
35
- isRuntimeContext: true,
36
- serviceName,
37
- }
38
- // reset all files previously generated by the service
39
- service.reset()
40
- service.setConfig(newConfig)
41
- this.services.push({
42
- name: serviceName,
43
- service,
44
- })
45
-
46
- if (typeof service.setRuntime === 'function') {
47
- service.setRuntime(this)
48
- }
49
- }
50
-
51
- setEntryPoint (entryPoint) {
52
- const service = this.services.find(svc => svc.name === entryPoint)
53
- if (!service) {
54
- throw new NoServiceNamedError(entryPoint)
55
- }
56
- this.entryPoint = service
57
- }
58
-
59
- async generatePackageJson () {
60
- const template = {
61
- name: `${this.runtimeName}`,
62
- workspaces: ['services/*'],
63
- scripts: {
64
- start: 'platformatic start',
65
- },
66
- devDependencies: {
67
- fastify: `^${this.fastifyVersion}`,
68
- borp: `${this.pkgData.devDependencies.borp}`,
69
- },
70
- dependencies: {
71
- '@platformatic/runtime': `^${this.platformaticVersion}`,
72
- platformatic: `^${this.platformaticVersion}`,
73
- ...this.config.dependencies,
74
- },
75
- engines: {
76
- node: '^18.8.0 || >=20.6.0',
77
- },
78
- }
79
- if (this.config.typescript) {
80
- const typescriptVersion = JSON.parse(await readFile(join(__dirname, '..', '..', 'package.json'), 'utf-8'))
81
- .devDependencies.typescript
82
- template.scripts.clean = 'rm -fr ./dist'
83
- template.scripts.build = 'platformatic compile'
84
- template.devDependencies.typescript = typescriptVersion
85
- }
86
- return template
87
- }
88
-
89
- async _beforePrepare () {
90
- this.setServicesDirectory()
91
- this.setServicesConfigValues()
92
- this.addServicesDependencies()
93
-
94
- this.addEnvVars(
95
- {
96
- PLT_SERVER_HOSTNAME: '127.0.0.1',
97
- PORT: this.config.port || 3042,
98
- PLT_SERVER_LOGGER_LEVEL: this.config.logLevel || 'info',
99
- PLT_MANAGEMENT_API: true,
100
- },
101
- { overwrite: false, default: true }
102
- )
103
- }
104
-
105
- addServicesDependencies () {
106
- this.services.forEach(({ service }) => {
107
- if (service.config.dependencies) {
108
- Object.entries(service.config.dependencies).forEach(kv => {
109
- this.config.dependencies[kv[0]] = kv[1]
110
- })
111
- }
112
- })
113
- }
114
-
115
- async populateFromExistingConfig () {
116
- if (this._hasCheckedForExistingConfig) {
117
- return
118
- }
119
- this._hasCheckedForExistingConfig = true
120
- const existingConfigFile = await ConfigManager.findConfigFile(this.targetDirectory, 'runtime')
121
- if (existingConfigFile) {
122
- const configManager = new ConfigManager({
123
- ...platformaticRuntime.configManagerConfig,
124
- source: join(this.targetDirectory, existingConfigFile),
125
- })
126
- await configManager.parse()
127
- this.existingConfig = configManager.current
128
- this.config.env = configManager.env
129
- this.config.port = configManager.env.PORT
130
- this.entryPoint = configManager.current.services.find(svc => svc.entrypoint)
131
- }
132
- }
133
-
134
- async prepare () {
135
- await this.populateFromExistingConfig()
136
- if (this.existingConfig) {
137
- this.setServicesDirectory()
138
- this.setServicesConfigValues()
139
- await this._afterPrepare()
140
- return {
141
- env: this.config.env,
142
- targetDirectory: this.targetDirectory,
143
- }
144
- } else {
145
- return await super.prepare()
146
- }
147
- }
148
-
149
- setServicesConfigValues () {
150
- this.services.forEach(({ service }) => {
151
- if (!service.config) {
152
- // set default config
153
- service.setConfig()
154
- }
155
- service.config.typescript = this.config.typescript
156
- })
157
- }
158
-
159
- async _getConfigFileContents () {
160
- const config = {
161
- $schema: `https://schemas.platformatic.dev/@platformatic/runtime/${this.platformaticVersion}.json`,
162
- entrypoint: this.entryPoint.name,
163
- watch: true,
164
- autoload: {
165
- path: this.config.autoload || 'services',
166
- exclude: ['docs'],
167
- },
168
- logger: {
169
- level: '{PLT_SERVER_LOGGER_LEVEL}',
170
- },
171
- server: {
172
- hostname: '{PLT_SERVER_HOSTNAME}',
173
- port: '{PORT}'
174
- },
175
- managementApi: '{PLT_MANAGEMENT_API}',
176
- }
177
-
178
- return config
179
- }
180
-
181
- async _afterPrepare () {
182
- if (!this.entryPoint) {
183
- throw new NoEntryPointError()
184
- }
185
- const servicesEnv = await this.prepareServiceFiles()
186
- this.addEnvVars({
187
- ...this.config.env,
188
- ...this.getRuntimeEnv(),
189
- ...servicesEnv,
190
- })
191
-
192
- this.addFile({
193
- path: '',
194
- file: '.env',
195
- contents: envObjectToString(this.config.env),
196
- })
197
-
198
- this.addFile({
199
- path: '',
200
- file: '.env.sample',
201
- contents: envObjectToString(this.config.env),
202
- })
203
-
204
- if (!this.existingConfig) {
205
- this.addFile({ path: '', file: 'README.md', contents: await readFile(join(__dirname, 'README.md'), 'utf-8') })
206
- }
207
-
208
- return {
209
- targetDirectory: this.targetDirectory,
210
- env: servicesEnv,
211
- }
212
- }
213
-
214
- async writeFiles () {
215
- await super.writeFiles()
216
- if (!this.config.isUpdating) {
217
- for (const { service } of this.services) {
218
- await service.writeFiles()
219
- }
220
- }
221
- }
222
-
223
- async prepareQuestions () {
224
- await this.populateFromExistingConfig()
225
-
226
- // typescript
227
- this.questions.push({
228
- type: 'list',
229
- name: 'typescript',
230
- message: 'Do you want to use TypeScript?',
231
- default: false,
232
- choices: [
233
- { name: 'yes', value: true },
234
- { name: 'no', value: false },
235
- ],
236
- })
237
-
238
- if (this.existingConfig) {
239
- return
240
- }
241
-
242
- // port
243
- this.questions.push({
244
- type: 'input',
245
- name: 'port',
246
- default: 3042,
247
- message: 'What port do you want to use?',
248
- })
249
- }
250
-
251
- setServicesDirectory () {
252
- this.services.forEach(({ service }) => {
253
- if (!service.config) {
254
- // set default config
255
- service.setConfig()
256
- }
257
- let basePath
258
- if (this.existingConfig) {
259
- basePath = this.existingConfig.autoload.path
260
- } else {
261
- basePath = join(this.targetDirectory, this.config.autoload || 'services')
262
- }
263
- service.setTargetDirectory(join(basePath, service.config.serviceName))
264
- })
265
- }
266
-
267
- setServicesConfig (configToOverride) {
268
- this.services.forEach(service => {
269
- const originalConfig = service.config
270
- service.setConfig({
271
- ...originalConfig,
272
- ...configToOverride,
273
- })
274
- })
275
- }
276
-
277
- async prepareServiceFiles () {
278
- let servicesEnv = {}
279
- for (const svc of this.services) {
280
- // Propagate TypeScript
281
- svc.service.setConfig({
282
- ...svc.service.config,
283
- typescript: this.config.typescript,
284
- })
285
- const svcEnv = await svc.service.prepare()
286
- servicesEnv = {
287
- ...servicesEnv,
288
- ...svcEnv.env,
289
- }
290
- }
291
- return servicesEnv
292
- }
293
-
294
- getConfigFieldsDefinitions () {
295
- return []
296
- }
297
-
298
- setConfigFields () {
299
- // do nothing, makes no sense
300
- }
301
-
302
- getRuntimeEnv () {
303
- return {
304
- PORT: this.config.port,
305
- }
306
- }
307
-
308
- async postInstallActions () {
309
- for (const { service } of this.services) {
310
- await service.postInstallActions()
311
- }
312
- }
313
-
314
- async _getGeneratorForTemplate (dir, pkg) {
315
- const _require = createRequire(dir)
316
- const fileToImport = _require.resolve(pkg)
317
- return (await import(pathToFileURL(fileToImport))).Generator
318
- }
319
-
320
- async loadFromDir () {
321
- const output = {
322
- services: [],
323
- }
324
- const runtimePkgConfigFileData = JSON.parse(
325
- await readFile(join(this.targetDirectory, 'platformatic.json'), 'utf-8')
326
- )
327
- const servicesPath = join(this.targetDirectory, runtimePkgConfigFileData.autoload.path)
328
-
329
- // load all services
330
- const allServices = await readdir(servicesPath)
331
- for (const s of allServices) {
332
- // check is a directory
333
- const currentServicePath = join(servicesPath, s)
334
- const dirStat = await stat(currentServicePath)
335
- if (dirStat.isDirectory()) {
336
- // load the package json file
337
- const servicePltJson = JSON.parse(await readFile(join(currentServicePath, 'platformatic.json'), 'utf-8'))
338
- // get module to load
339
- const template = servicePltJson.module || getServiceTemplateFromSchemaUrl(servicePltJson.$schema)
340
- const Generator = await this._getGeneratorForTemplate(currentServicePath, template)
341
- const instance = new Generator({
342
- logger: this.logger,
343
- })
344
- this.addService(instance, s)
345
- output.services.push(await instance.loadFromDir(s, this.targetDirectory))
346
- }
347
- }
348
- return output
349
- }
350
-
351
- async update (newConfig) {
352
- let allServicesDependencies = {}
353
- const runtimeAddedEnvKeys = []
354
-
355
- this.config.isUpdating = true
356
- const currrentPackageJson = JSON.parse(await readFile(join(this.targetDirectory, 'package.json'), 'utf-8'))
357
- const currentRuntimeDependencies = currrentPackageJson.dependencies
358
- // check all services are present with the same template
359
- const allCurrentServicesNames = this.services.map(s => s.name)
360
- const allNewServicesNames = newConfig.services.map(s => s.name)
361
- // load dotenv tool
362
- const envTool = new DotEnvTool({
363
- path: join(this.targetDirectory, '.env'),
364
- })
365
-
366
- await envTool.load()
367
-
368
- const removedServices = getArrayDifference(allCurrentServicesNames, allNewServicesNames)
369
- if (removedServices.length > 0) {
370
- for (const removedService of removedServices) {
371
- // handle service delete
372
-
373
- // delete env variables
374
- const s = this.services.find(f => f.name === removedService)
375
- const allKeys = envTool.getKeys()
376
- allKeys.forEach(k => {
377
- if (k.startsWith(`PLT_${s.service.config.envPrefix}`)) {
378
- envTool.deleteKey(k)
379
- }
380
- })
381
-
382
- // delete dependencies
383
- const servicePackageJson = JSON.parse(
384
- await readFile(join(this.targetDirectory, 'services', s.name, 'platformatic.json'), 'utf-8')
385
- )
386
- if (servicePackageJson.plugins && servicePackageJson.plugins.packages) {
387
- servicePackageJson.plugins.packages.forEach(p => {
388
- delete currrentPackageJson.dependencies[p.name]
389
- })
390
- }
391
- // delete directory
392
- await safeRemove(join(this.targetDirectory, 'services', s.name))
393
- }
394
- // throw new CannotRemoveServiceOnUpdateError(removedServices.join(', '))
395
- }
396
-
397
- // handle new services
398
- for (const newService of newConfig.services) {
399
- // create generator for the service
400
- const ServiceGenerator = await this._getGeneratorForTemplate(
401
- join(this.targetDirectory, 'package.json'),
402
- newService.template
403
- )
404
- const serviceInstance = new ServiceGenerator({
405
- logger: this.logger,
406
- })
407
- const baseConfig = {
408
- isRuntimeContext: true,
409
- targetDirectory: join(this.targetDirectory, 'services', newService.name),
410
- serviceName: newService.name,
411
- plugin: true,
412
- }
413
- if (allCurrentServicesNames.includes(newService.name)) {
414
- // update existing services env values
415
- // otherwise, is a new service
416
- baseConfig.isUpdating = true
417
-
418
- // handle service's plugin differences
419
- const oldServiceMetadata = await serviceInstance.loadFromDir(newService.name, this.targetDirectory)
420
- const oldServicePackages = oldServiceMetadata.plugins.map(meta => meta.name)
421
- const newServicePackages = newService.plugins.map(meta => meta.name)
422
- const pluginsToRemove = getArrayDifference(oldServicePackages, newServicePackages)
423
- pluginsToRemove.forEach(p => delete currentRuntimeDependencies[p])
424
- } else {
425
- // add service to the generator
426
- this.services.push({
427
- name: newService.name,
428
- service: serviceInstance,
429
- })
430
- }
431
- serviceInstance.setConfig(baseConfig)
432
- serviceInstance.setConfigFields(newService.fields)
433
-
434
- const serviceEnvPrefix = `PLT_${serviceInstance.config.envPrefix}`
435
- for (const plug of newService.plugins) {
436
- await serviceInstance.addPackage(plug)
437
- for (const opt of plug.options) {
438
- const key = `${serviceEnvPrefix}_${opt.name}`
439
- runtimeAddedEnvKeys.push(key)
440
- const value = opt.value
441
- if (envTool.hasKey(key)) {
442
- envTool.updateKey(key, value)
443
- } else {
444
- envTool.addKey(key, value)
445
- }
446
- }
447
- }
448
- allServicesDependencies = { ...allServicesDependencies, ...serviceInstance.config.dependencies }
449
- const afterPrepareMetadata = await serviceInstance.prepare()
450
- await serviceInstance.writeFiles()
451
- // cleanup runtime env removing keys not present anymore in service plugins
452
- const allKeys = envTool.getKeys()
453
- allKeys.forEach(k => {
454
- if (k.startsWith(`${serviceEnvPrefix}_FST_PLUGIN`) && !runtimeAddedEnvKeys.includes(k)) {
455
- envTool.deleteKey(k)
456
- }
457
- })
458
-
459
- // add service env variables to runtime env
460
- Object.entries(afterPrepareMetadata.env).forEach(([key, value]) => {
461
- envTool.addKey(key, value)
462
- })
463
- }
464
- // update runtime package.json dependencies
465
- currrentPackageJson.dependencies = {
466
- ...currrentPackageJson.dependencies,
467
- ...allServicesDependencies,
468
- }
469
- this.addFile({
470
- path: '',
471
- file: 'package.json',
472
- contents: JSON.stringify(currrentPackageJson, null, 2),
473
- })
474
-
475
- // set new entrypoint if specified
476
- const newEntrypoint = newConfig.entrypoint
477
- if (newEntrypoint) {
478
- // load platformatic.json runtime config
479
- const runtimePkgConfigFileData = JSON.parse(
480
- await readFile(join(this.targetDirectory, 'platformatic.json'), 'utf-8')
481
- )
482
-
483
- this.setEntryPoint(newEntrypoint)
484
- runtimePkgConfigFileData.entrypoint = newEntrypoint
485
- this.addFile({
486
- path: '',
487
- file: 'platformatic.json',
488
- contents: JSON.stringify(runtimePkgConfigFileData, null, 2),
489
- })
490
- }
491
- await this.writeFiles()
492
- // save new env
493
- await envTool.save()
494
- }
495
- }
496
-
497
- module.exports = RuntimeGenerator
498
- module.exports.RuntimeGenerator = RuntimeGenerator
package/lib/start.js DELETED
@@ -1,190 +0,0 @@
1
- 'use strict'
2
-
3
- const inspector = require('node:inspector')
4
- const { writeFile } = require('node:fs/promises')
5
- const { join, resolve, dirname } = require('node:path')
6
-
7
- const { printConfigValidationErrors } = require('@platformatic/config')
8
- const {
9
- errors: { ensureLoggableError }
10
- } = require('@platformatic/utils')
11
- const closeWithGrace = require('close-with-grace')
12
- const pino = require('pino')
13
- const pretty = require('pino-pretty')
14
-
15
- const pkg = require('../package.json')
16
- const { parseInspectorOptions, wrapConfigInRuntimeConfig } = require('./config')
17
- const { Runtime } = require('./runtime')
18
- const errors = require('./errors')
19
- const { getRuntimeLogsDir, loadConfig } = require('./utils')
20
-
21
- async function buildRuntime (configManager, env) {
22
- env = env || process.env
23
-
24
- if (inspector.url()) {
25
- throw new errors.NodeInspectorFlagsNotSupportedError()
26
- }
27
-
28
- if (configManager.args) {
29
- parseInspectorOptions(configManager)
30
- }
31
-
32
- const dirname = configManager.dirname
33
- const runtimeLogsDir = getRuntimeLogsDir(dirname, process.pid)
34
-
35
- const runtime = new Runtime(configManager, runtimeLogsDir, env)
36
-
37
- /* c8 ignore next 3 */
38
- process.on('SIGUSR2', async () => {
39
- runtime.logger.info('Received SIGUSR2, restarting all services ...')
40
-
41
- try {
42
- await runtime.restart()
43
- } catch (err) {
44
- runtime.logger.error({ err: ensureLoggableError(err) }, 'Failed to restart services.')
45
- }
46
- })
47
-
48
- try {
49
- await runtime.init()
50
- } catch (e) {
51
- await runtime.close()
52
- throw e
53
- }
54
-
55
- return runtime
56
- }
57
-
58
- async function start (args) {
59
- const config = await loadConfig({}, args)
60
-
61
- if (config.configType !== 'runtime') {
62
- const configManager = await wrapConfigInRuntimeConfig(config)
63
- config.configManager = configManager
64
- }
65
-
66
- const app = await buildRuntime(config.configManager)
67
- await app.start()
68
- return app
69
- }
70
-
71
- async function setupAndStartRuntime (config) {
72
- const MAX_PORT = 65535
73
- let runtimeConfig
74
-
75
- if (config.configType === 'runtime') {
76
- config.configManager.args = config.args
77
- runtimeConfig = config.configManager
78
- } else {
79
- const wrappedConfig = await wrapConfigInRuntimeConfig(config)
80
- wrappedConfig.args = config.args
81
- runtimeConfig = wrappedConfig
82
- }
83
-
84
- let runtime = await buildRuntime(runtimeConfig)
85
-
86
- let address = null
87
- const startErr = null
88
- const originalPort = runtimeConfig.current.server?.port || 0
89
- while (address === null) {
90
- try {
91
- address = await runtime.start()
92
- } catch (err) {
93
- if (err.code === 'EADDRINUSE') {
94
- await runtime.close()
95
-
96
- if (runtimeConfig.current?.server?.port > MAX_PORT) throw err
97
- runtimeConfig.current.server.port++
98
- runtime = await buildRuntime(runtimeConfig)
99
- } else {
100
- throw err
101
- }
102
- }
103
- }
104
- if (startErr?.code === 'PLT_RUNTIME_EADDR_IN_USE') {
105
- const logger = pino(
106
- pretty({
107
- translateTime: 'SYS:HH:MM:ss',
108
- ignore: 'hostname,pid'
109
- })
110
- )
111
- logger.warn(`Port: ${originalPort} is already in use!`)
112
- logger.warn(`Starting service on port: ${runtimeConfig.current.server.port}`)
113
- }
114
- return { address, runtime }
115
- }
116
-
117
- async function startCommand (args, throwAllErrors = false, returnRuntime = false) {
118
- try {
119
- const config = await loadConfig(
120
- {
121
- alias: {
122
- p: 'production'
123
- },
124
- boolean: ['p', 'production']
125
- },
126
- args
127
- )
128
-
129
- const startResult = await setupAndStartRuntime(config)
130
-
131
- const runtime = startResult.runtime
132
- const res = startResult.address
133
-
134
- closeWithGrace(async event => {
135
- if (event.err instanceof Error) {
136
- console.error(event.err)
137
- }
138
- await runtime.close()
139
- })
140
-
141
- return returnRuntime ? runtime : res
142
- } catch (err) {
143
- if (throwAllErrors) {
144
- throw err
145
- }
146
-
147
- if (err.code === 'PLT_CONFIG_NO_CONFIG_FILE_FOUND' && args.length === 1) {
148
- const config = {
149
- $schema: `https://schemas.platformatic.dev/@platformatic/service/${pkg.version}.json`,
150
- server: {
151
- hostname: '127.0.0.1',
152
- port: 3042,
153
- logger: {
154
- level: 'info'
155
- }
156
- },
157
- plugins: {
158
- paths: [args[0]]
159
- },
160
- service: {
161
- openapi: true
162
- },
163
- watch: true
164
- }
165
- const toWrite = join(dirname(resolve(args[0])), 'platformatic.service.json')
166
- console.log(`No config file found, creating ${join(dirname(args[0]), 'platformatic.service.json')}`)
167
- await writeFile(toWrite, JSON.stringify(config, null, 2))
168
- return startCommand(['--config', toWrite])
169
- }
170
-
171
- if (err.filenames) {
172
- console.error(`Missing config file!
173
- Be sure to have a config file with one of the following names:
174
-
175
- ${err.filenames.map(s => ' * ' + s).join('\n')}
176
-
177
- In alternative run "npm create platformatic@latest" to generate a basic plt service config.`)
178
- process.exit(1)
179
- } else if (err.validationErrors) {
180
- printConfigValidationErrors(err)
181
- process.exit(1)
182
- }
183
-
184
- console.error(err)
185
-
186
- process.exit(1)
187
- }
188
- }
189
-
190
- module.exports = { buildRuntime, start, startCommand, setupAndStartRuntime }