@platformatic/runtime 3.38.1 → 3.40.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 +16 -0
- package/index.d.ts +71 -0
- package/index.js +10 -2
- package/lib/config.js +4 -0
- package/lib/logger.js +27 -2
- package/lib/management-handlers.js +139 -0
- package/lib/runtime.js +29 -6
- package/lib/utils.js +29 -0
- package/lib/worker/interceptors.js +2 -1
- package/lib/worker/main.js +20 -0
- package/lib/worker/management.js +99 -0
- package/package.json +17 -16
- package/schema.json +136 -1
package/config.d.ts
CHANGED
|
@@ -90,6 +90,12 @@ export type PlatformaticRuntimeConfig = {
|
|
|
90
90
|
*/
|
|
91
91
|
directory?: string;
|
|
92
92
|
};
|
|
93
|
+
management?:
|
|
94
|
+
| boolean
|
|
95
|
+
| {
|
|
96
|
+
enabled?: boolean;
|
|
97
|
+
operations?: string[];
|
|
98
|
+
};
|
|
93
99
|
};
|
|
94
100
|
};
|
|
95
101
|
};
|
|
@@ -167,6 +173,10 @@ export type PlatformaticRuntimeConfig = {
|
|
|
167
173
|
customLevels?: {
|
|
168
174
|
[k: string]: unknown;
|
|
169
175
|
};
|
|
176
|
+
openTelemetryExporter?: {
|
|
177
|
+
protocol: "grpc" | "http";
|
|
178
|
+
url: string;
|
|
179
|
+
};
|
|
170
180
|
captureStdio?: boolean;
|
|
171
181
|
[k: string]: unknown;
|
|
172
182
|
};
|
|
@@ -306,6 +316,12 @@ export type PlatformaticRuntimeConfig = {
|
|
|
306
316
|
*/
|
|
307
317
|
socket?: string;
|
|
308
318
|
};
|
|
319
|
+
management?:
|
|
320
|
+
| boolean
|
|
321
|
+
| {
|
|
322
|
+
enabled?: boolean;
|
|
323
|
+
operations?: string[];
|
|
324
|
+
};
|
|
309
325
|
metrics?:
|
|
310
326
|
| boolean
|
|
311
327
|
| {
|
package/index.d.ts
CHANGED
|
@@ -65,6 +65,77 @@ export module symbols {
|
|
|
65
65
|
export declare const kWorkersBroadcast: unique symbol
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
export interface InjectParams {
|
|
69
|
+
method?: string
|
|
70
|
+
url: string
|
|
71
|
+
headers?: Record<string, string>
|
|
72
|
+
query?: Record<string, string>
|
|
73
|
+
body?: unknown
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface InjectResponse {
|
|
77
|
+
statusCode: number
|
|
78
|
+
statusMessage: string
|
|
79
|
+
headers: Record<string, string>
|
|
80
|
+
body: string
|
|
81
|
+
payload: string
|
|
82
|
+
rawPayload: ArrayBuffer
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface ApplicationDetails {
|
|
86
|
+
id: string
|
|
87
|
+
type?: string
|
|
88
|
+
config?: string
|
|
89
|
+
path?: string
|
|
90
|
+
status?: string
|
|
91
|
+
dependencies?: string[]
|
|
92
|
+
version?: string
|
|
93
|
+
localUrl?: string
|
|
94
|
+
entrypoint?: boolean
|
|
95
|
+
sourceMaps?: boolean
|
|
96
|
+
workers?: number
|
|
97
|
+
url?: string | null
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface RuntimeMetadata {
|
|
101
|
+
pid: number
|
|
102
|
+
cwd: string
|
|
103
|
+
argv: string[]
|
|
104
|
+
uptimeSeconds: number
|
|
105
|
+
execPath: string
|
|
106
|
+
nodeVersion: string
|
|
107
|
+
projectDir: string
|
|
108
|
+
packageName: string | null
|
|
109
|
+
packageVersion: string | null
|
|
110
|
+
url: string | null
|
|
111
|
+
platformaticVersion: string
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export declare class ManagementClient {
|
|
115
|
+
constructor (allowedOperations?: string[])
|
|
116
|
+
|
|
117
|
+
getRuntimeStatus (): Promise<string>
|
|
118
|
+
getRuntimeMetadata (): Promise<RuntimeMetadata>
|
|
119
|
+
getRuntimeConfig (): Promise<Record<string, unknown>>
|
|
120
|
+
getRuntimeEnv (): Promise<Record<string, string>>
|
|
121
|
+
getApplicationsIds (): Promise<string[]>
|
|
122
|
+
getApplications (): Promise<{ entrypoint: string; production: boolean; applications: ApplicationDetails[] }>
|
|
123
|
+
getWorkers (): Promise<Record<string, unknown>>
|
|
124
|
+
getApplicationDetails (id: string): Promise<ApplicationDetails>
|
|
125
|
+
getApplicationConfig (id: string): Promise<Record<string, unknown>>
|
|
126
|
+
getApplicationEnv (id: string): Promise<Record<string, string>>
|
|
127
|
+
getApplicationOpenapiSchema (id: string): Promise<unknown>
|
|
128
|
+
getApplicationGraphqlSchema (id: string): Promise<unknown>
|
|
129
|
+
getMetrics (format?: string): Promise<{ metrics: unknown }>
|
|
130
|
+
startApplication (id: string): Promise<void>
|
|
131
|
+
stopApplication (id: string): Promise<void>
|
|
132
|
+
restartApplication (id: string): Promise<void>
|
|
133
|
+
restart (applications?: string[]): Promise<string>
|
|
134
|
+
addApplications (applications: unknown[], start?: boolean): Promise<ApplicationDetails[]>
|
|
135
|
+
removeApplications (ids: string[]): Promise<ApplicationDetails[]>
|
|
136
|
+
inject (id: string, injectParams: InjectParams): Promise<InjectResponse>
|
|
137
|
+
}
|
|
138
|
+
|
|
68
139
|
export class Generator extends BaseGenerator {}
|
|
69
140
|
|
|
70
141
|
export class WrappedGenerator extends BaseGenerator {}
|
package/index.js
CHANGED
|
@@ -82,14 +82,22 @@ export async function loadConfiguration (configOrRoot, sourceOrConfig, context)
|
|
|
82
82
|
})
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
export async function loadApplicationsCommands () {
|
|
85
|
+
export async function loadApplicationsCommands (executableName = '') {
|
|
86
86
|
const applications = {}
|
|
87
87
|
const commands = {}
|
|
88
88
|
const help = {}
|
|
89
89
|
|
|
90
90
|
let config
|
|
91
91
|
try {
|
|
92
|
-
const file = await findRuntimeConfigurationFile(
|
|
92
|
+
const file = await findRuntimeConfigurationFile(
|
|
93
|
+
abstractLogger,
|
|
94
|
+
process.cwd(),
|
|
95
|
+
null,
|
|
96
|
+
false,
|
|
97
|
+
false,
|
|
98
|
+
true,
|
|
99
|
+
executableName
|
|
100
|
+
)
|
|
93
101
|
|
|
94
102
|
/* c8 ignore next 3 - Hard to test */
|
|
95
103
|
if (!file) {
|
package/lib/config.js
CHANGED
|
@@ -281,6 +281,10 @@ export async function prepareApplication (config, application, defaultWorkers) {
|
|
|
281
281
|
application.watch = config.watch
|
|
282
282
|
}
|
|
283
283
|
|
|
284
|
+
if (typeof application.management === 'undefined' && config.management) {
|
|
285
|
+
application.management = config.management
|
|
286
|
+
}
|
|
287
|
+
|
|
284
288
|
return application
|
|
285
289
|
}
|
|
286
290
|
|
package/lib/logger.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildPinoFormatters, buildPinoTimestamp
|
|
1
|
+
import { buildPinoFormatters, buildPinoTimestamp } from '@platformatic/foundation'
|
|
2
2
|
import { isatty } from 'node:tty'
|
|
3
3
|
import pino from 'pino'
|
|
4
4
|
import pretty from 'pino-pretty'
|
|
@@ -158,7 +158,7 @@ export async function createLogger (config) {
|
|
|
158
158
|
|
|
159
159
|
if (config.logger.transport) {
|
|
160
160
|
cliStream = pino.transport(config.logger.transport)
|
|
161
|
-
} else if ((process.env.FORCE_TTY || isatty(1)) &&
|
|
161
|
+
} else if ((process.env.FORCE_TTY || isatty(1)) && process.env.PLT_PRETTY_PRINT !== 'false') {
|
|
162
162
|
cliStream = createPrettifier(context)
|
|
163
163
|
} else {
|
|
164
164
|
cliStream = pino.destination(1)
|
|
@@ -178,6 +178,31 @@ export async function createLogger (config) {
|
|
|
178
178
|
|
|
179
179
|
const multiStream = pino.multistream([{ stream: cliStream, level: loggerConfig.level }])
|
|
180
180
|
|
|
181
|
+
if (config.telemetry && config.logger.openTelemetryExporter) {
|
|
182
|
+
multiStream.add(
|
|
183
|
+
pino.transport({
|
|
184
|
+
target: 'pino-opentelemetry-transport',
|
|
185
|
+
options: {
|
|
186
|
+
resourceAttributes: {
|
|
187
|
+
'service.name': config.telemetry.applicationName,
|
|
188
|
+
'service.version': config.telemetry.version
|
|
189
|
+
},
|
|
190
|
+
logRecordProcessorOptions: [
|
|
191
|
+
{
|
|
192
|
+
recordProcessorType: 'simple',
|
|
193
|
+
exporterOptions: {
|
|
194
|
+
protocol: config.logger.openTelemetryExporter.protocol,
|
|
195
|
+
httpExporterOptions: {
|
|
196
|
+
url: config.logger.openTelemetryExporter.url
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
]
|
|
201
|
+
}
|
|
202
|
+
})
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
|
|
181
206
|
const logsFileMb = 5
|
|
182
207
|
const logsLimitMb = config.managementApi?.logs?.maxSize || 200
|
|
183
208
|
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import {
|
|
2
|
+
applications as applicationSchema,
|
|
3
|
+
kMetadata,
|
|
4
|
+
validate
|
|
5
|
+
} from '@platformatic/foundation'
|
|
6
|
+
import { prepareApplication } from './config.js'
|
|
7
|
+
|
|
8
|
+
const allOperations = [
|
|
9
|
+
'getRuntimeStatus',
|
|
10
|
+
'getRuntimeMetadata',
|
|
11
|
+
'getRuntimeConfig',
|
|
12
|
+
'getRuntimeEnv',
|
|
13
|
+
'getApplicationsIds',
|
|
14
|
+
'getApplications',
|
|
15
|
+
'getWorkers',
|
|
16
|
+
'getApplicationDetails',
|
|
17
|
+
'getApplicationConfig',
|
|
18
|
+
'getApplicationEnv',
|
|
19
|
+
'getApplicationOpenapiSchema',
|
|
20
|
+
'getApplicationGraphqlSchema',
|
|
21
|
+
'getMetrics',
|
|
22
|
+
'startApplication',
|
|
23
|
+
'stopApplication',
|
|
24
|
+
'restartApplication',
|
|
25
|
+
'restart',
|
|
26
|
+
'addApplications',
|
|
27
|
+
'removeApplications',
|
|
28
|
+
'inject'
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
export function createManagementHandlers (runtime, allowedOperations) {
|
|
32
|
+
const allowed = allowedOperations
|
|
33
|
+
? new Set(allowedOperations)
|
|
34
|
+
: new Set(allOperations)
|
|
35
|
+
|
|
36
|
+
const handlers = new Map()
|
|
37
|
+
|
|
38
|
+
function register (name, fn) {
|
|
39
|
+
if (allowed.has(name)) {
|
|
40
|
+
handlers.set('management:' + name, fn)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Read operations - no arguments
|
|
45
|
+
register('getRuntimeStatus', async () => {
|
|
46
|
+
return runtime.getRuntimeStatus()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
register('getRuntimeMetadata', async () => {
|
|
50
|
+
return runtime.getRuntimeMetadata()
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
register('getRuntimeConfig', async () => {
|
|
54
|
+
return runtime.getRuntimeConfig()
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
register('getRuntimeEnv', async () => {
|
|
58
|
+
return runtime.getRuntimeEnv()
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
register('getApplicationsIds', async () => {
|
|
62
|
+
return runtime.getApplicationsIds()
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
register('getApplications', async () => {
|
|
66
|
+
return runtime.getApplications()
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
register('getWorkers', async () => {
|
|
70
|
+
return runtime.getWorkers()
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// Read operations - with application id
|
|
74
|
+
register('getApplicationDetails', async ({ id }) => {
|
|
75
|
+
return runtime.getApplicationDetails(id)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
register('getApplicationConfig', async ({ id }) => {
|
|
79
|
+
return runtime.getApplicationConfig(id)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
register('getApplicationEnv', async ({ id }) => {
|
|
83
|
+
return runtime.getApplicationEnv(id)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
register('getApplicationOpenapiSchema', async ({ id }) => {
|
|
87
|
+
return runtime.getApplicationOpenapiSchema(id)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
register('getApplicationGraphqlSchema', async ({ id }) => {
|
|
91
|
+
return runtime.getApplicationGraphqlSchema(id)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
// Metrics
|
|
95
|
+
register('getMetrics', async ({ format } = {}) => {
|
|
96
|
+
return runtime.getMetrics(format)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
// Write operations
|
|
100
|
+
register('startApplication', async ({ id }) => {
|
|
101
|
+
await runtime.startApplication(id)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
register('stopApplication', async ({ id }) => {
|
|
105
|
+
await runtime.stopApplication(id)
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
register('restartApplication', async ({ id }) => {
|
|
109
|
+
await runtime.restartApplication(id)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
register('restart', async ({ applications } = {}) => {
|
|
113
|
+
return runtime.restart(applications)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
register('addApplications', async ({ applications, start }) => {
|
|
117
|
+
const config = runtime.getRuntimeConfig(true)
|
|
118
|
+
|
|
119
|
+
validate(applicationSchema, applications, {}, true, config[kMetadata].root)
|
|
120
|
+
|
|
121
|
+
for (let i = 0; i < applications.length; i++) {
|
|
122
|
+
applications[i] = await prepareApplication(config, applications[i], config.workers)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return runtime.addApplications(applications, start)
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
register('removeApplications', async ({ ids }) => {
|
|
129
|
+
return runtime.removeApplications(ids)
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
register('inject', async ({ id, injectParams }) => {
|
|
133
|
+
return runtime.inject(id, injectParams)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
return handlers
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export { allOperations }
|
package/lib/runtime.js
CHANGED
|
@@ -42,11 +42,12 @@ import {
|
|
|
42
42
|
} from './errors.js'
|
|
43
43
|
import { abstractLogger, createLogger } from './logger.js'
|
|
44
44
|
import { startManagementApi } from './management-api.js'
|
|
45
|
+
import { createManagementHandlers } from './management-handlers.js'
|
|
45
46
|
import { createChannelCreationHook } from './policies.js'
|
|
46
47
|
import { startPrometheusServer } from './prom-server.js'
|
|
47
48
|
import { startScheduler } from './scheduler.js'
|
|
48
49
|
import { createSharedStore } from './shared-http-cache.js'
|
|
49
|
-
import { topologicalSort } from './utils.js'
|
|
50
|
+
import { topologicalLevels, topologicalSort } from './utils.js'
|
|
50
51
|
import { version } from './version.js'
|
|
51
52
|
import { DynamicWorkersScaler } from './worker-scaler.js'
|
|
52
53
|
import { HealthSignalsQueue } from './worker/health-signals.js'
|
|
@@ -560,12 +561,15 @@ export class Runtime extends EventEmitter {
|
|
|
560
561
|
// If circular dependencies are detected, an error with proper error code is thrown.
|
|
561
562
|
applications = topologicalSort(dependencies)
|
|
562
563
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
564
|
+
// Group into dependency levels so that each level's dependencies are all
|
|
565
|
+
// in previous levels. Levels are started sequentially, but applications
|
|
566
|
+
// within the same level start in parallel.
|
|
567
|
+
const levels = topologicalLevels(applications, dependencies)
|
|
567
568
|
|
|
568
|
-
|
|
569
|
+
for (const level of levels) {
|
|
570
|
+
const startInvocations = level.map(app => [app, silent])
|
|
571
|
+
await executeInParallel(this.startApplication.bind(this), startInvocations, this.#concurrency)
|
|
572
|
+
}
|
|
569
573
|
}
|
|
570
574
|
|
|
571
575
|
async stopApplications (applicationsToStop, silent = false, skipDependencies = false) {
|
|
@@ -1792,6 +1796,25 @@ export class Runtime extends EventEmitter {
|
|
|
1792
1796
|
port: worker,
|
|
1793
1797
|
handlers: this.#workerITCHandlers
|
|
1794
1798
|
})
|
|
1799
|
+
|
|
1800
|
+
// Register management ITC handlers for privileged applications
|
|
1801
|
+
if (applicationConfig.management) {
|
|
1802
|
+
const mgmtEnabled = typeof applicationConfig.management === 'boolean'
|
|
1803
|
+
? applicationConfig.management
|
|
1804
|
+
: applicationConfig.management.enabled !== false
|
|
1805
|
+
|
|
1806
|
+
if (mgmtEnabled) {
|
|
1807
|
+
const allowedOps = typeof applicationConfig.management === 'object'
|
|
1808
|
+
? applicationConfig.management.operations
|
|
1809
|
+
: undefined
|
|
1810
|
+
|
|
1811
|
+
const handlers = createManagementHandlers(this, allowedOps)
|
|
1812
|
+
for (const [name, handler] of handlers) {
|
|
1813
|
+
worker[kITC].handle(name, handler)
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1795
1818
|
worker[kITC].listen()
|
|
1796
1819
|
|
|
1797
1820
|
// Forward events from the worker
|
package/lib/utils.js
CHANGED
|
@@ -19,6 +19,35 @@ export function getRuntimeTmpDir (runtimeDir) {
|
|
|
19
19
|
return join(platformaticTmpDir, runtimeDirHash)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
// Given a topologically sorted list and the dependency graph,
|
|
23
|
+
// group nodes into levels where each level's dependencies are all in previous levels.
|
|
24
|
+
// This allows starting each level in parallel while respecting dependency order.
|
|
25
|
+
export function topologicalLevels (sorted, graph) {
|
|
26
|
+
const levels = []
|
|
27
|
+
const levelOf = new Map()
|
|
28
|
+
|
|
29
|
+
for (const node of sorted) {
|
|
30
|
+
const deps = graph.get(node) ?? []
|
|
31
|
+
let level = 0
|
|
32
|
+
|
|
33
|
+
for (const dep of deps) {
|
|
34
|
+
if (levelOf.has(dep)) {
|
|
35
|
+
level = Math.max(level, levelOf.get(dep) + 1)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
levelOf.set(node, level)
|
|
40
|
+
|
|
41
|
+
while (levels.length <= level) {
|
|
42
|
+
levels.push([])
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
levels[level].push(node)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return levels
|
|
49
|
+
}
|
|
50
|
+
|
|
22
51
|
// Graph: Map<string, string[]>
|
|
23
52
|
export function topologicalSort (graph) {
|
|
24
53
|
const result = []
|
|
@@ -19,6 +19,7 @@ export async function setDispatcher (runtimeConfig) {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
let userInterceptors = []
|
|
22
|
+
|
|
22
23
|
if (Array.isArray(runtimeConfig.undici?.interceptors)) {
|
|
23
24
|
const _require = createRequire(join(workerData.dirname, 'package.json'))
|
|
24
25
|
userInterceptors = await loadInterceptors(_require, runtimeConfig.undici.interceptors)
|
|
@@ -104,7 +105,7 @@ async function loadInterceptor (_require, interceptorConfig, key) {
|
|
|
104
105
|
|
|
105
106
|
const url = pathToFileURL(_require.resolve(module))
|
|
106
107
|
const createInterceptor = (await import(url)).default
|
|
107
|
-
const interceptor = createInterceptor(options)
|
|
108
|
+
const interceptor = await createInterceptor(options)
|
|
108
109
|
|
|
109
110
|
const { updatableInterceptor, updateInterceptor } = createUpdatableInterceptor(interceptor)
|
|
110
111
|
|
package/lib/worker/main.js
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
ensureLoggableError,
|
|
6
6
|
getPrivateSymbol
|
|
7
7
|
} from '@platformatic/foundation'
|
|
8
|
+
import { addPinoInstrumentation } from '@platformatic/telemetry'
|
|
8
9
|
import { subscribe } from 'node:diagnostics_channel'
|
|
9
10
|
import { EventEmitter } from 'node:events'
|
|
10
11
|
import { ServerResponse } from 'node:http'
|
|
@@ -93,6 +94,10 @@ function createLogger () {
|
|
|
93
94
|
pinoOptions.timestamp = buildPinoTimestamp(pinoOptions.timestamp)
|
|
94
95
|
}
|
|
95
96
|
|
|
97
|
+
if (workerData.config.logger?.openTelemetryExporter && workerData.applicationConfig.telemetry?.enabled !== false) {
|
|
98
|
+
addPinoInstrumentation(pinoOptions)
|
|
99
|
+
}
|
|
100
|
+
|
|
96
101
|
return pino(pinoOptions)
|
|
97
102
|
}
|
|
98
103
|
|
|
@@ -270,6 +275,21 @@ async function main () {
|
|
|
270
275
|
globalThis[kITC] = itc
|
|
271
276
|
globalThis.platformatic.itc = itc
|
|
272
277
|
|
|
278
|
+
// Setup management client for privileged applications
|
|
279
|
+
if (applicationConfig.management) {
|
|
280
|
+
const mgmtEnabled = typeof applicationConfig.management === 'boolean'
|
|
281
|
+
? applicationConfig.management
|
|
282
|
+
: applicationConfig.management.enabled !== false
|
|
283
|
+
|
|
284
|
+
if (mgmtEnabled) {
|
|
285
|
+
const { ManagementClient } = await import('./management.js')
|
|
286
|
+
const ops = typeof applicationConfig.management === 'object'
|
|
287
|
+
? applicationConfig.management.operations
|
|
288
|
+
: undefined
|
|
289
|
+
globalThis.platformatic.management = new ManagementClient(ops)
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
273
293
|
initHealthSignalsApi({
|
|
274
294
|
workerId: workerData.worker.id,
|
|
275
295
|
applicationId: applicationConfig.id
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { kITC } from './symbols.js'
|
|
2
|
+
|
|
3
|
+
export class ManagementClient {
|
|
4
|
+
#allowedOperations
|
|
5
|
+
|
|
6
|
+
constructor (allowedOperations) {
|
|
7
|
+
this.#allowedOperations = allowedOperations
|
|
8
|
+
? new Set(allowedOperations)
|
|
9
|
+
: null
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
#send (operation, data) {
|
|
13
|
+
if (this.#allowedOperations && !this.#allowedOperations.has(operation)) {
|
|
14
|
+
throw new Error(`Operation "${operation}" is not allowed`)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return globalThis[kITC].send('management:' + operation, data)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
getRuntimeStatus () {
|
|
21
|
+
return this.#send('getRuntimeStatus')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getRuntimeMetadata () {
|
|
25
|
+
return this.#send('getRuntimeMetadata')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getRuntimeConfig () {
|
|
29
|
+
return this.#send('getRuntimeConfig')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getRuntimeEnv () {
|
|
33
|
+
return this.#send('getRuntimeEnv')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getApplicationsIds () {
|
|
37
|
+
return this.#send('getApplicationsIds')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
getApplications () {
|
|
41
|
+
return this.#send('getApplications')
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getWorkers () {
|
|
45
|
+
return this.#send('getWorkers')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getApplicationDetails (id) {
|
|
49
|
+
return this.#send('getApplicationDetails', { id })
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getApplicationConfig (id) {
|
|
53
|
+
return this.#send('getApplicationConfig', { id })
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
getApplicationEnv (id) {
|
|
57
|
+
return this.#send('getApplicationEnv', { id })
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getApplicationOpenapiSchema (id) {
|
|
61
|
+
return this.#send('getApplicationOpenapiSchema', { id })
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
getApplicationGraphqlSchema (id) {
|
|
65
|
+
return this.#send('getApplicationGraphqlSchema', { id })
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
getMetrics (format) {
|
|
69
|
+
return this.#send('getMetrics', { format })
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
startApplication (id) {
|
|
73
|
+
return this.#send('startApplication', { id })
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
stopApplication (id) {
|
|
77
|
+
return this.#send('stopApplication', { id })
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
restartApplication (id) {
|
|
81
|
+
return this.#send('restartApplication', { id })
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
restart (applications) {
|
|
85
|
+
return this.#send('restart', { applications })
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
addApplications (applications, start) {
|
|
89
|
+
return this.#send('addApplications', { applications, start })
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
removeApplications (ids) {
|
|
93
|
+
return this.#send('removeApplications', { ids })
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
inject (id, injectParams) {
|
|
97
|
+
return this.#send('inject', { id, injectParams })
|
|
98
|
+
}
|
|
99
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.40.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -35,14 +35,14 @@
|
|
|
35
35
|
"typescript": "^5.5.4",
|
|
36
36
|
"undici-oidc-interceptor": "^0.5.0",
|
|
37
37
|
"why-is-node-running": "^2.2.2",
|
|
38
|
-
"@platformatic/
|
|
39
|
-
"@platformatic/
|
|
40
|
-
"@platformatic/
|
|
41
|
-
"@platformatic/
|
|
42
|
-
"@platformatic/
|
|
43
|
-
"@platformatic/
|
|
44
|
-
"@platformatic/sql-
|
|
45
|
-
"@platformatic/
|
|
38
|
+
"@platformatic/composer": "3.40.0",
|
|
39
|
+
"@platformatic/service": "3.40.0",
|
|
40
|
+
"@platformatic/gateway": "3.40.0",
|
|
41
|
+
"@platformatic/db": "3.40.0",
|
|
42
|
+
"@platformatic/sql-mapper": "3.40.0",
|
|
43
|
+
"@platformatic/wattpm-pprof-capture": "3.40.0",
|
|
44
|
+
"@platformatic/sql-graphql": "3.40.0",
|
|
45
|
+
"@platformatic/node": "3.40.0"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@fastify/accepts": "^5.0.0",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"@fastify/error": "^4.0.0",
|
|
51
51
|
"@fastify/websocket": "^11.0.0",
|
|
52
52
|
"@opentelemetry/api": "^1.9.0",
|
|
53
|
+
"@platformatic/prom-client": "^1.0.0",
|
|
53
54
|
"@platformatic/undici-cache-memory": "^0.8.1",
|
|
54
55
|
"@watchable/unpromise": "^1.0.2",
|
|
55
56
|
"change-case-all": "^2.1.0",
|
|
@@ -63,20 +64,20 @@
|
|
|
63
64
|
"help-me": "^5.0.0",
|
|
64
65
|
"minimist": "^1.2.8",
|
|
65
66
|
"pino": "^9.9.0",
|
|
67
|
+
"pino-opentelemetry-transport": "^2.0.0",
|
|
66
68
|
"pino-pretty": "^13.0.0",
|
|
67
|
-
"@platformatic/prom-client": "^1.0.0",
|
|
68
69
|
"semgrator": "^0.3.0",
|
|
69
70
|
"sonic-boom": "^4.2.0",
|
|
70
71
|
"systeminformation": "^5.27.11",
|
|
71
72
|
"undici": "^7.0.0",
|
|
72
73
|
"undici-thread-interceptor": "^1.3.1",
|
|
73
74
|
"ws": "^8.16.0",
|
|
74
|
-
"@platformatic/
|
|
75
|
-
"@platformatic/
|
|
76
|
-
"@platformatic/
|
|
77
|
-
"@platformatic/
|
|
78
|
-
"@platformatic/
|
|
79
|
-
"@platformatic/telemetry": "3.
|
|
75
|
+
"@platformatic/foundation": "3.40.0",
|
|
76
|
+
"@platformatic/generators": "3.40.0",
|
|
77
|
+
"@platformatic/basic": "3.40.0",
|
|
78
|
+
"@platformatic/itc": "3.40.0",
|
|
79
|
+
"@platformatic/metrics": "3.40.0",
|
|
80
|
+
"@platformatic/telemetry": "3.40.0"
|
|
80
81
|
},
|
|
81
82
|
"engines": {
|
|
82
83
|
"node": ">=22.19.0"
|
package/schema.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.
|
|
2
|
+
"$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.40.0.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
4
|
"title": "Platformatic Runtime Config",
|
|
5
5
|
"type": "object",
|
|
@@ -354,6 +354,29 @@
|
|
|
354
354
|
"additionalProperties": false
|
|
355
355
|
}
|
|
356
356
|
]
|
|
357
|
+
},
|
|
358
|
+
"management": {
|
|
359
|
+
"anyOf": [
|
|
360
|
+
{
|
|
361
|
+
"type": "boolean"
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
"type": "object",
|
|
365
|
+
"properties": {
|
|
366
|
+
"enabled": {
|
|
367
|
+
"type": "boolean",
|
|
368
|
+
"default": true
|
|
369
|
+
},
|
|
370
|
+
"operations": {
|
|
371
|
+
"type": "array",
|
|
372
|
+
"items": {
|
|
373
|
+
"type": "string"
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
"additionalProperties": false
|
|
378
|
+
}
|
|
379
|
+
]
|
|
357
380
|
}
|
|
358
381
|
}
|
|
359
382
|
}
|
|
@@ -690,6 +713,29 @@
|
|
|
690
713
|
"additionalProperties": false
|
|
691
714
|
}
|
|
692
715
|
]
|
|
716
|
+
},
|
|
717
|
+
"management": {
|
|
718
|
+
"anyOf": [
|
|
719
|
+
{
|
|
720
|
+
"type": "boolean"
|
|
721
|
+
},
|
|
722
|
+
{
|
|
723
|
+
"type": "object",
|
|
724
|
+
"properties": {
|
|
725
|
+
"enabled": {
|
|
726
|
+
"type": "boolean",
|
|
727
|
+
"default": true
|
|
728
|
+
},
|
|
729
|
+
"operations": {
|
|
730
|
+
"type": "array",
|
|
731
|
+
"items": {
|
|
732
|
+
"type": "string"
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
},
|
|
736
|
+
"additionalProperties": false
|
|
737
|
+
}
|
|
738
|
+
]
|
|
693
739
|
}
|
|
694
740
|
}
|
|
695
741
|
}
|
|
@@ -1024,6 +1070,29 @@
|
|
|
1024
1070
|
"additionalProperties": false
|
|
1025
1071
|
}
|
|
1026
1072
|
]
|
|
1073
|
+
},
|
|
1074
|
+
"management": {
|
|
1075
|
+
"anyOf": [
|
|
1076
|
+
{
|
|
1077
|
+
"type": "boolean"
|
|
1078
|
+
},
|
|
1079
|
+
{
|
|
1080
|
+
"type": "object",
|
|
1081
|
+
"properties": {
|
|
1082
|
+
"enabled": {
|
|
1083
|
+
"type": "boolean",
|
|
1084
|
+
"default": true
|
|
1085
|
+
},
|
|
1086
|
+
"operations": {
|
|
1087
|
+
"type": "array",
|
|
1088
|
+
"items": {
|
|
1089
|
+
"type": "string"
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
},
|
|
1093
|
+
"additionalProperties": false
|
|
1094
|
+
}
|
|
1095
|
+
]
|
|
1027
1096
|
}
|
|
1028
1097
|
}
|
|
1029
1098
|
}
|
|
@@ -1358,6 +1427,29 @@
|
|
|
1358
1427
|
"additionalProperties": false
|
|
1359
1428
|
}
|
|
1360
1429
|
]
|
|
1430
|
+
},
|
|
1431
|
+
"management": {
|
|
1432
|
+
"anyOf": [
|
|
1433
|
+
{
|
|
1434
|
+
"type": "boolean"
|
|
1435
|
+
},
|
|
1436
|
+
{
|
|
1437
|
+
"type": "object",
|
|
1438
|
+
"properties": {
|
|
1439
|
+
"enabled": {
|
|
1440
|
+
"type": "boolean",
|
|
1441
|
+
"default": true
|
|
1442
|
+
},
|
|
1443
|
+
"operations": {
|
|
1444
|
+
"type": "array",
|
|
1445
|
+
"items": {
|
|
1446
|
+
"type": "string"
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
},
|
|
1450
|
+
"additionalProperties": false
|
|
1451
|
+
}
|
|
1452
|
+
]
|
|
1361
1453
|
}
|
|
1362
1454
|
}
|
|
1363
1455
|
}
|
|
@@ -1578,6 +1670,26 @@
|
|
|
1578
1670
|
"type": "object",
|
|
1579
1671
|
"additionalProperties": true
|
|
1580
1672
|
},
|
|
1673
|
+
"openTelemetryExporter": {
|
|
1674
|
+
"type": "object",
|
|
1675
|
+
"properties": {
|
|
1676
|
+
"protocol": {
|
|
1677
|
+
"type": "string",
|
|
1678
|
+
"enum": [
|
|
1679
|
+
"grpc",
|
|
1680
|
+
"http"
|
|
1681
|
+
]
|
|
1682
|
+
},
|
|
1683
|
+
"url": {
|
|
1684
|
+
"type": "string"
|
|
1685
|
+
}
|
|
1686
|
+
},
|
|
1687
|
+
"required": [
|
|
1688
|
+
"protocol",
|
|
1689
|
+
"url"
|
|
1690
|
+
],
|
|
1691
|
+
"additionalProperties": false
|
|
1692
|
+
},
|
|
1581
1693
|
"captureStdio": {
|
|
1582
1694
|
"type": "boolean",
|
|
1583
1695
|
"default": true
|
|
@@ -2081,6 +2193,29 @@
|
|
|
2081
2193
|
],
|
|
2082
2194
|
"default": true
|
|
2083
2195
|
},
|
|
2196
|
+
"management": {
|
|
2197
|
+
"anyOf": [
|
|
2198
|
+
{
|
|
2199
|
+
"type": "boolean"
|
|
2200
|
+
},
|
|
2201
|
+
{
|
|
2202
|
+
"type": "object",
|
|
2203
|
+
"properties": {
|
|
2204
|
+
"enabled": {
|
|
2205
|
+
"type": "boolean",
|
|
2206
|
+
"default": true
|
|
2207
|
+
},
|
|
2208
|
+
"operations": {
|
|
2209
|
+
"type": "array",
|
|
2210
|
+
"items": {
|
|
2211
|
+
"type": "string"
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
},
|
|
2215
|
+
"additionalProperties": false
|
|
2216
|
+
}
|
|
2217
|
+
]
|
|
2218
|
+
},
|
|
2084
2219
|
"metrics": {
|
|
2085
2220
|
"anyOf": [
|
|
2086
2221
|
{
|