@platformatic/runtime 3.67.0 → 4.0.0-new-config.0
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 +5 -43
- package/index.d.ts +10 -12
- package/index.js +191 -6
- package/lib/config.js +125 -60
- package/lib/errors.js +5 -13
- package/lib/generator.js +19 -92
- package/lib/management-api.js +3 -5
- package/lib/management-handlers.js +3 -5
- package/lib/runtime.js +377 -183
- package/lib/schema.js +1 -1
- package/lib/upgrade.js +16 -1
- package/lib/versions/v4.0.0.js +31 -0
- package/lib/worker/controller.js +51 -55
- package/lib/worker/itc.js +5 -6
- package/lib/worker/main.js +4 -19
- package/lib/worker/symbols.js +2 -0
- package/lib/worker-scaler.js +8 -10
- package/package.json +17 -16
- package/schema.json +33 -147
package/lib/schema.js
CHANGED
package/lib/upgrade.js
CHANGED
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
import { abstractLogger } from '@platformatic/foundation'
|
|
2
2
|
import { join } from 'node:path'
|
|
3
|
+
import { lt } from 'semver'
|
|
3
4
|
import { semgrator } from 'semgrator'
|
|
4
5
|
|
|
5
6
|
export async function upgrade (logger, config, version) {
|
|
7
|
+
const runtimeLogger = logger?.child({ name: '@platformatic/runtime' }) ?? abstractLogger
|
|
8
|
+
|
|
9
|
+
const schema = config.$schema
|
|
10
|
+
const isRuntimeSchema =
|
|
11
|
+
!schema ||
|
|
12
|
+
/(?:^|\/)(?:@platformatic\/)?runtime(?:\/|$)/.test(schema) ||
|
|
13
|
+
/(?:^|\/)wattpm(?:\/|$)/.test(schema)
|
|
14
|
+
|
|
15
|
+
if (isRuntimeSchema && config.server && lt(version, '4.0.0')) {
|
|
16
|
+
runtimeLogger.warn(
|
|
17
|
+
'Runtime v4 no longer supports a root server configuration. Move it into the configuration of the capability that owns the listener.'
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
6
21
|
const iterator = semgrator({
|
|
7
22
|
version,
|
|
8
23
|
path: join(import.meta.dirname, 'versions'),
|
|
9
24
|
input: config,
|
|
10
|
-
logger:
|
|
25
|
+
logger: runtimeLogger
|
|
11
26
|
})
|
|
12
27
|
|
|
13
28
|
let result
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
version: '3.99.0',
|
|
3
|
+
up (config) {
|
|
4
|
+
const schema = config.$schema
|
|
5
|
+
const isRuntimeSchema =
|
|
6
|
+
!schema ||
|
|
7
|
+
/(?:^|\/)(?:@platformatic\/)?runtime(?:\/|$)/.test(schema) ||
|
|
8
|
+
/(?:^|\/)wattpm(?:\/|$)/.test(schema)
|
|
9
|
+
|
|
10
|
+
// Standalone application configurations are wrapped by Runtime and pass
|
|
11
|
+
// through this upgrade chain. Their capability-owned server must survive.
|
|
12
|
+
if (!isRuntimeSchema) {
|
|
13
|
+
return config
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
for (const section of ['applications', 'services', 'web']) {
|
|
17
|
+
for (const application of config[section] ?? []) {
|
|
18
|
+
delete application.server
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
for (const application of Object.values(config.autoload?.mappings ?? {})) {
|
|
23
|
+
delete application.server
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
delete config.entrypoint
|
|
27
|
+
delete config.server
|
|
28
|
+
|
|
29
|
+
return config
|
|
30
|
+
}
|
|
31
|
+
}
|
package/lib/worker/controller.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
getOnHttpStatsRunning,
|
|
18
18
|
getOnHttpStatsSize
|
|
19
19
|
} from '@platformatic/globals'
|
|
20
|
+
import { importCapabilityPackage } from '@platformatic/basic'
|
|
20
21
|
import debounce from 'debounce'
|
|
21
22
|
import { EventEmitter } from 'node:events'
|
|
22
23
|
import { existsSync } from 'node:fs'
|
|
@@ -59,13 +60,12 @@ function handleUnhandled (app, event, listeners, timeout, err, ...args) {
|
|
|
59
60
|
export class Controller extends EventEmitter {
|
|
60
61
|
#starting
|
|
61
62
|
#started
|
|
62
|
-
#listening
|
|
63
63
|
#watch
|
|
64
64
|
#fileWatcher
|
|
65
65
|
#debouncedRestart
|
|
66
66
|
#context
|
|
67
67
|
|
|
68
|
-
constructor (runtimeConfig, applicationConfig, workerId,
|
|
68
|
+
constructor (runtimeConfig, applicationConfig, workerId, metricsConfig) {
|
|
69
69
|
super()
|
|
70
70
|
this.runtimeConfig = runtimeConfig
|
|
71
71
|
this.applicationConfig = applicationConfig
|
|
@@ -74,7 +74,6 @@ export class Controller extends EventEmitter {
|
|
|
74
74
|
this.#watch = !!runtimeConfig.watch
|
|
75
75
|
this.#starting = false
|
|
76
76
|
this.#started = false
|
|
77
|
-
this.#listening = false
|
|
78
77
|
this.capability = null
|
|
79
78
|
this.#fileWatcher = null
|
|
80
79
|
|
|
@@ -86,12 +85,10 @@ export class Controller extends EventEmitter {
|
|
|
86
85
|
workerId: this.workerId,
|
|
87
86
|
directory: this.applicationConfig.path,
|
|
88
87
|
dependencies: this.applicationConfig.dependencies,
|
|
89
|
-
isEntrypoint: this.applicationConfig.entrypoint,
|
|
90
88
|
isProduction: this.applicationConfig.isProduction,
|
|
91
89
|
telemetryConfig: this.applicationConfig.telemetry,
|
|
92
90
|
loggerConfig: runtimeConfig.logger,
|
|
93
91
|
metricsConfig,
|
|
94
|
-
serverConfig,
|
|
95
92
|
worker: workerData?.worker,
|
|
96
93
|
resourceLimits: workerData?.resourceLimits,
|
|
97
94
|
hasManagementApi: !!runtimeConfig.managementApi,
|
|
@@ -129,28 +126,52 @@ export class Controller extends EventEmitter {
|
|
|
129
126
|
process.env.NODE_ENV = 'production'
|
|
130
127
|
}
|
|
131
128
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
129
|
+
/*
|
|
130
|
+
v4: the configuration was evaluated exactly once, main-side, and this worker receives the
|
|
131
|
+
validated capability payload as data. There is no file to re-read and no schema to
|
|
132
|
+
rediscover — which is the whole point, since re-parsing per worker meant an application
|
|
133
|
+
with workers: 4 evaluated user code five times and could reach five different answers.
|
|
134
|
+
|
|
135
|
+
The capability is imported through the canonical resolution order, application-scoped first,
|
|
136
|
+
so the copy that runs here is the copy whose schema validated the payload main-side.
|
|
137
|
+
*/
|
|
138
|
+
/*
|
|
139
|
+
v4: the configuration was evaluated exactly once, main-side, and this worker receives the
|
|
140
|
+
validated capability payload as data. There is no file to re-read and no schema to
|
|
141
|
+
rediscover — which is the point, since re-parsing per worker meant an application with
|
|
142
|
+
workers: 4 evaluated user code five times and could reach five different answers.
|
|
143
|
+
|
|
144
|
+
The capability is imported through the canonical resolution order, application-scoped
|
|
145
|
+
first, so the copy that runs here is the copy whose schema validated the payload.
|
|
146
|
+
*/
|
|
147
|
+
if (appConfig.resolvedConfig) {
|
|
148
|
+
const pkg = await importCapabilityPackage(appConfig.path, appConfig.module)
|
|
149
|
+
|
|
150
|
+
this.capability = await pkg.create(appConfig.path, appConfig.resolvedConfig, this.#context)
|
|
151
|
+
} else {
|
|
152
|
+
// Before returning the base application, check if there is any file we recognize
|
|
153
|
+
// and the user just forgot to specify in the configuration.
|
|
154
|
+
if (!appConfig.config) {
|
|
155
|
+
const candidate = listRecognizedConfigurationFiles().find(f => existsSync(resolve(appConfig.path, f)))
|
|
136
156
|
|
|
137
|
-
|
|
138
|
-
|
|
157
|
+
if (candidate) {
|
|
158
|
+
appConfig.config = resolve(appConfig.path, candidate)
|
|
159
|
+
}
|
|
139
160
|
}
|
|
140
|
-
}
|
|
141
161
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
162
|
+
if (appConfig.config) {
|
|
163
|
+
// Parse the configuration file the first time to obtain the schema
|
|
164
|
+
const unvalidatedConfig = await loadConfiguration(appConfig.config, null, {
|
|
165
|
+
onMissingEnv: this.#context.fetchApplicationUrl,
|
|
166
|
+
strictEnv: this.#context.strictEnv
|
|
167
|
+
})
|
|
168
|
+
const pkg = await loadConfigurationModule(appConfig.path, unvalidatedConfig)
|
|
169
|
+
this.capability = await pkg.create(appConfig.path, appConfig.config, this.#context)
|
|
170
|
+
// We could not find a configuration file, we use the bundle @platformatic/basic with the runtime to load it
|
|
171
|
+
} else {
|
|
172
|
+
const pkg = await loadConfigurationModule(resolve(import.meta.dirname, '../..'), {}, '@platformatic/basic')
|
|
173
|
+
this.capability = await pkg.create(appConfig.path, {}, this.#context)
|
|
174
|
+
}
|
|
154
175
|
}
|
|
155
176
|
|
|
156
177
|
this.#updateDispatcher()
|
|
@@ -189,6 +210,7 @@ export class Controller extends EventEmitter {
|
|
|
189
210
|
|
|
190
211
|
try {
|
|
191
212
|
await this.capability.init?.()
|
|
213
|
+
|
|
192
214
|
this.emit('init')
|
|
193
215
|
} catch (err) {
|
|
194
216
|
this.#logAndThrow(err)
|
|
@@ -198,7 +220,6 @@ export class Controller extends EventEmitter {
|
|
|
198
220
|
return
|
|
199
221
|
}
|
|
200
222
|
|
|
201
|
-
this.#updateCapabilityStatus('starting')
|
|
202
223
|
this.emit('starting')
|
|
203
224
|
|
|
204
225
|
if (this.#watch) {
|
|
@@ -215,17 +236,13 @@ export class Controller extends EventEmitter {
|
|
|
215
236
|
}
|
|
216
237
|
}
|
|
217
238
|
|
|
218
|
-
const listen = !!this.applicationConfig.useHttp
|
|
219
|
-
|
|
220
239
|
try {
|
|
221
|
-
await this.capability.start(
|
|
240
|
+
await this.capability.start()
|
|
222
241
|
if (refreshGlobalDispatcher()) {
|
|
223
242
|
this.#updateDispatcher()
|
|
224
243
|
}
|
|
225
|
-
this.#listening = listen
|
|
226
244
|
/* c8 ignore next 5 */
|
|
227
245
|
} catch (err) {
|
|
228
|
-
this.#updateCapabilityStatus('start:error')
|
|
229
246
|
this.emit('start:error', err)
|
|
230
247
|
|
|
231
248
|
this.capability.log({ message: err.message, level: 'debug' })
|
|
@@ -236,19 +253,19 @@ export class Controller extends EventEmitter {
|
|
|
236
253
|
this.#started = true
|
|
237
254
|
this.#starting = false
|
|
238
255
|
|
|
239
|
-
this.#updateCapabilityStatus('started')
|
|
240
256
|
this.emit('started')
|
|
241
257
|
}
|
|
242
258
|
|
|
259
|
+
getUrl () {
|
|
260
|
+
return this.capability.getUrl()
|
|
261
|
+
}
|
|
262
|
+
|
|
243
263
|
async stop (force = false, dependents = []) {
|
|
244
264
|
if (!force && (!this.#started || this.#starting)) {
|
|
245
265
|
throw new RuntimeNotStartedError()
|
|
246
266
|
}
|
|
247
267
|
|
|
248
268
|
this.emit('stopping')
|
|
249
|
-
// Do not update status of the capability to "stopping" here otherwise
|
|
250
|
-
// if stop is called before start is finished, the capability will not
|
|
251
|
-
// be able to wait for start to finish and it will create a race condition.
|
|
252
269
|
|
|
253
270
|
await this.#stopFileWatching()
|
|
254
271
|
await this.capability.waitForDependentsStop(dependents)
|
|
@@ -256,21 +273,10 @@ export class Controller extends EventEmitter {
|
|
|
256
273
|
|
|
257
274
|
this.#started = false
|
|
258
275
|
this.#starting = false
|
|
259
|
-
this.#listening = false
|
|
260
276
|
|
|
261
|
-
this.#updateCapabilityStatus('stopped')
|
|
262
277
|
this.emit('stopped')
|
|
263
278
|
}
|
|
264
279
|
|
|
265
|
-
async listen () {
|
|
266
|
-
// This server is not an entrypoint or already listened in start. Behave as no-op.
|
|
267
|
-
if (!this.applicationConfig.entrypoint || this.applicationConfig.useHttp || this.#listening) {
|
|
268
|
-
return
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
await this.capability.start({ listen: true })
|
|
272
|
-
}
|
|
273
|
-
|
|
274
280
|
async getMetrics ({ format }) {
|
|
275
281
|
const dispatcher = getGlobalDispatcher()
|
|
276
282
|
const onHttpStatsFree = getOnHttpStatsFree({ throwOnMissing: false })
|
|
@@ -396,14 +402,4 @@ export class Controller extends EventEmitter {
|
|
|
396
402
|
}
|
|
397
403
|
})
|
|
398
404
|
}
|
|
399
|
-
|
|
400
|
-
#updateCapabilityStatus (status) {
|
|
401
|
-
if (typeof this.capability.updateStatus === 'function') {
|
|
402
|
-
this.capability.updateStatus(status)
|
|
403
|
-
} else {
|
|
404
|
-
// This is horrible but needed for backward compatibility
|
|
405
|
-
this.capability.status = status
|
|
406
|
-
this.capability.emit(status)
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
405
|
}
|
package/lib/worker/itc.js
CHANGED
|
@@ -201,14 +201,13 @@ export async function setupITC (controller, application, dispatcher, sharedConte
|
|
|
201
201
|
})
|
|
202
202
|
})
|
|
203
203
|
|
|
204
|
-
|
|
204
|
+
// Errors are structured cloned when sent to the runtime, which drops all their custom properties (like the
|
|
205
|
+
// port and the address of listen errors): send a plain object instead so that the runtime can inspect them.
|
|
206
|
+
// eslint-disable-next-line no-throw-literal
|
|
207
|
+
throw { name: e.name, ...ensureLoggableError(e) }
|
|
205
208
|
}
|
|
206
209
|
}
|
|
207
210
|
|
|
208
|
-
if (application.entrypoint) {
|
|
209
|
-
await controller.listen()
|
|
210
|
-
}
|
|
211
|
-
|
|
212
211
|
dispatcher.replaceServer(await controller.capability.getDispatchTarget())
|
|
213
212
|
|
|
214
213
|
const scheduledTasks =
|
|
@@ -217,7 +216,7 @@ export async function setupITC (controller, application, dispatcher, sharedConte
|
|
|
217
216
|
: []
|
|
218
217
|
|
|
219
218
|
return {
|
|
220
|
-
url:
|
|
219
|
+
url: controller.getUrl(),
|
|
221
220
|
scheduledTasks
|
|
222
221
|
}
|
|
223
222
|
},
|
package/lib/worker/main.js
CHANGED
|
@@ -270,18 +270,6 @@ async function main () {
|
|
|
270
270
|
|
|
271
271
|
const { threadDispatcher } = await setDispatcher(runtimeConfig)
|
|
272
272
|
|
|
273
|
-
// If the application is an entrypoint and runtime server config is defined, use it.
|
|
274
|
-
let serverConfig = null
|
|
275
|
-
if (runtimeConfig.server && applicationConfig.entrypoint) {
|
|
276
|
-
serverConfig = runtimeConfig.server
|
|
277
|
-
} else if (applicationConfig.useHttp) {
|
|
278
|
-
serverConfig = {
|
|
279
|
-
port: 0,
|
|
280
|
-
hostname: '127.0.0.1',
|
|
281
|
-
keepAliveTimeout: 5000
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
273
|
const inspectorOptions = workerData.inspectorOptions
|
|
286
274
|
|
|
287
275
|
if (inspectorOptions) {
|
|
@@ -313,15 +301,14 @@ async function main () {
|
|
|
313
301
|
runtimeConfig,
|
|
314
302
|
applicationConfig,
|
|
315
303
|
workerData.worker.index,
|
|
316
|
-
serverConfig,
|
|
317
304
|
metricsConfig
|
|
318
305
|
)
|
|
319
306
|
|
|
320
307
|
await controller.init(cleanup)
|
|
321
308
|
|
|
322
|
-
if (
|
|
309
|
+
if (runtimeConfig.basePath) {
|
|
323
310
|
const meta = await controller.capability.getMeta()
|
|
324
|
-
if (!meta.gateway
|
|
311
|
+
if (!meta.gateway?.wantsAbsoluteUrls) {
|
|
325
312
|
stripBasePath(runtimeConfig.basePath)
|
|
326
313
|
}
|
|
327
314
|
}
|
|
@@ -425,10 +412,8 @@ function stripBasePath (basePath) {
|
|
|
425
412
|
}
|
|
426
413
|
|
|
427
414
|
ServerResponse.prototype.setHeader = function (name, value) {
|
|
428
|
-
if (this[kBasePath]) {
|
|
429
|
-
|
|
430
|
-
value = prependBasePath(value)
|
|
431
|
-
}
|
|
415
|
+
if (this[kBasePath] && name.toLowerCase() === 'location') {
|
|
416
|
+
value = prependBasePath(value)
|
|
432
417
|
}
|
|
433
418
|
originSetHeader.call(this, name, value)
|
|
434
419
|
}
|
package/lib/worker/symbols.js
CHANGED
|
@@ -8,6 +8,8 @@ export const kHealthCheckTimer = Symbol.for('plt.runtime.worker.healthCheckTimer
|
|
|
8
8
|
export const kWorkerStatus = Symbol('plt.runtime.worker.status')
|
|
9
9
|
export const kWorkerHealthSignals = Symbol.for('plt.runtime.worker.healthSignals')
|
|
10
10
|
export const kWorkerStartTime = Symbol.for('plt.runtime.worker.startTime')
|
|
11
|
+
export const kWorkerUrl = Symbol.for('plt.runtime.worker.url')
|
|
12
|
+
export const kWorkerPortOffset = Symbol.for('plt.runtime.worker.portOffset')
|
|
11
13
|
export const kLastHealthCheckELU = Symbol.for('plt.runtime.worker.lastHealthCheckELU')
|
|
12
14
|
export const kLastWorkerScalerELU = Symbol.for('plt.runtime.worker.lastWorkerScalerELU')
|
|
13
15
|
export const kInterceptorReadyPromise = Symbol.for('plt.runtime.worker.interceptorReadyPromise')
|
package/lib/worker-scaler.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import { features } from '@platformatic/foundation'
|
|
2
1
|
import { availableParallelism } from 'node:os'
|
|
3
2
|
import { getMemoryInfo } from './metrics.js'
|
|
4
3
|
import { ScalingAlgorithm } from './scaling-algorithm.js'
|
|
5
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
kApplicationId,
|
|
6
|
+
kId,
|
|
7
|
+
kLastWorkerScalerELU,
|
|
8
|
+
kWorkerStartTime,
|
|
9
|
+
kWorkerStatus
|
|
10
|
+
} from './worker/symbols.js'
|
|
6
11
|
|
|
7
12
|
const healthCheckInterval = 1000
|
|
8
13
|
export const kOriginalWorkers = Symbol('plt.runtime.application.dynamicWorkersScalerOriginalWorkers')
|
|
@@ -93,14 +98,7 @@ export class DynamicWorkersScaler {
|
|
|
93
98
|
async add (application) {
|
|
94
99
|
const config = {}
|
|
95
100
|
|
|
96
|
-
if (application.
|
|
97
|
-
this.#runtime.logger.warn(
|
|
98
|
-
`The "${application.id}" application cannot be scaled because it is an entrypoint and the "reusePort" feature is not available in your OS.`
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
config.minWorkers = 1
|
|
102
|
-
config.maxWorkers = 1
|
|
103
|
-
} else if (application.workers.dynamic === false) {
|
|
101
|
+
if (application.workers.dynamic === false) {
|
|
104
102
|
this.#runtime.logger.warn(
|
|
105
103
|
`The "${application.id}" application cannot be scaled because it has a fixed number of workers (${application.workers.static}).`
|
|
106
104
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-new-config.0",
|
|
4
4
|
"description": "Platformatic runtime",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -39,14 +39,14 @@
|
|
|
39
39
|
"typescript": "~6.0.3",
|
|
40
40
|
"undici-oidc-interceptor": "^0.9.0",
|
|
41
41
|
"why-is-node-running": "^2.2.2",
|
|
42
|
-
"@platformatic/composer": "
|
|
43
|
-
"@platformatic/db": "
|
|
44
|
-
"@platformatic/
|
|
45
|
-
"@platformatic/service": "
|
|
46
|
-
"@platformatic/sql-graphql": "
|
|
47
|
-
"@platformatic/
|
|
48
|
-
"@platformatic/
|
|
49
|
-
"@platformatic/
|
|
42
|
+
"@platformatic/composer": "4.0.0-new-config.0",
|
|
43
|
+
"@platformatic/db": "4.0.0-new-config.0",
|
|
44
|
+
"@platformatic/gateway": "4.0.0-new-config.0",
|
|
45
|
+
"@platformatic/service": "4.0.0-new-config.0",
|
|
46
|
+
"@platformatic/sql-graphql": "4.0.0-new-config.0",
|
|
47
|
+
"@platformatic/node": "4.0.0-new-config.0",
|
|
48
|
+
"@platformatic/sql-mapper": "4.0.0-new-config.0",
|
|
49
|
+
"@platformatic/wattpm-pprof-capture": "4.0.0-new-config.0"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@fastify/accepts": "^5.0.0",
|
|
@@ -72,18 +72,19 @@
|
|
|
72
72
|
"pino-opentelemetry-transport": "^4.0.2",
|
|
73
73
|
"pino-pretty": "^13.0.0",
|
|
74
74
|
"semgrator": "^0.3.0",
|
|
75
|
+
"semver": "^7.6.3",
|
|
75
76
|
"sonic-boom": "^4.2.0",
|
|
76
77
|
"systeminformation": "^5.27.11",
|
|
77
78
|
"undici": "^7.27.2",
|
|
78
79
|
"undici-thread-interceptor": "^1.3.1",
|
|
79
80
|
"ws": "^8.16.0",
|
|
80
|
-
"@platformatic/
|
|
81
|
-
"@platformatic/
|
|
82
|
-
"@platformatic/
|
|
83
|
-
"@platformatic/itc": "
|
|
84
|
-
"@platformatic/
|
|
85
|
-
"@platformatic/
|
|
86
|
-
"@platformatic/
|
|
81
|
+
"@platformatic/globals": "4.0.0-new-config.0",
|
|
82
|
+
"@platformatic/basic": "4.0.0-new-config.0",
|
|
83
|
+
"@platformatic/metrics": "4.0.0-new-config.0",
|
|
84
|
+
"@platformatic/itc": "4.0.0-new-config.0",
|
|
85
|
+
"@platformatic/telemetry": "4.0.0-new-config.0",
|
|
86
|
+
"@platformatic/generators": "4.0.0-new-config.0",
|
|
87
|
+
"@platformatic/foundation": "4.0.0-new-config.0"
|
|
87
88
|
},
|
|
88
89
|
"engines": {
|
|
89
90
|
"node": ">=22.19.0"
|