@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.
- package/README.md +1 -1
- package/config.d.ts +224 -77
- package/eslint.config.js +3 -5
- package/index.d.ts +73 -24
- package/index.js +173 -29
- package/lib/config.js +279 -197
- package/lib/errors.js +126 -34
- package/lib/generator.js +640 -0
- package/lib/logger.js +43 -41
- package/lib/management-api.js +109 -118
- package/lib/prom-server.js +202 -16
- package/lib/runtime.js +1963 -585
- package/lib/scheduler.js +119 -0
- package/lib/schema.js +22 -234
- package/lib/shared-http-cache.js +43 -0
- package/lib/upgrade.js +6 -8
- package/lib/utils.js +6 -61
- package/lib/version.js +7 -0
- package/lib/versions/v1.36.0.js +2 -4
- package/lib/versions/v1.5.0.js +2 -4
- package/lib/versions/v2.0.0.js +3 -5
- package/lib/versions/v3.0.0.js +16 -0
- package/lib/worker/controller.js +302 -0
- package/lib/worker/http-cache.js +171 -0
- package/lib/worker/interceptors.js +190 -10
- package/lib/worker/itc.js +146 -59
- package/lib/worker/main.js +220 -81
- package/lib/worker/messaging.js +182 -0
- package/lib/worker/round-robin-map.js +62 -0
- package/lib/worker/shared-context.js +22 -0
- package/lib/worker/symbols.js +14 -5
- package/package.json +47 -38
- package/schema.json +1383 -55
- package/help/compile.txt +0 -8
- package/help/help.txt +0 -5
- package/help/start.txt +0 -21
- package/index.test-d.ts +0 -41
- package/lib/build-server.js +0 -69
- package/lib/compile.js +0 -98
- package/lib/dependencies.js +0 -59
- package/lib/generator/README.md +0 -32
- package/lib/generator/errors.js +0 -10
- package/lib/generator/runtime-generator.d.ts +0 -37
- package/lib/generator/runtime-generator.js +0 -498
- package/lib/start.js +0 -190
- package/lib/worker/app.js +0 -278
- package/lib/worker/default-stackable.js +0 -33
- package/lib/worker/metrics.js +0 -122
- package/runtime.mjs +0 -54
|
@@ -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 }
|