@platformatic/runtime 3.68.0 → 3.70.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 +48 -7
- package/lib/runtime.js +22 -2
- package/lib/worker/controller.js +35 -9
- package/lib/worker/main.js +15 -1
- package/package.json +17 -17
- package/schema.json +79 -17
package/config.d.ts
CHANGED
|
@@ -160,13 +160,10 @@ export type PlatformaticRuntimeConfig = {
|
|
|
160
160
|
};
|
|
161
161
|
workersRestartDelay?: number | string;
|
|
162
162
|
logger?: {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
) &
|
|
169
|
-
string;
|
|
163
|
+
/**
|
|
164
|
+
* The log level. It must be one of the standard pino levels (fatal, error, warn, info, debug, trace, silent) or, when customLevels is set, one of the custom levels.
|
|
165
|
+
*/
|
|
166
|
+
level?: string;
|
|
170
167
|
transport?:
|
|
171
168
|
| {
|
|
172
169
|
target?: string;
|
|
@@ -199,6 +196,10 @@ export type PlatformaticRuntimeConfig = {
|
|
|
199
196
|
redact?: {
|
|
200
197
|
paths: string[];
|
|
201
198
|
censor?: string;
|
|
199
|
+
/**
|
|
200
|
+
* Remove the redacted keys entirely instead of replacing their values with the censor. Defaults to false.
|
|
201
|
+
*/
|
|
202
|
+
remove?: boolean;
|
|
202
203
|
};
|
|
203
204
|
base?: {
|
|
204
205
|
[k: string]: unknown;
|
|
@@ -207,6 +208,46 @@ export type PlatformaticRuntimeConfig = {
|
|
|
207
208
|
customLevels?: {
|
|
208
209
|
[k: string]: unknown;
|
|
209
210
|
};
|
|
211
|
+
/**
|
|
212
|
+
* The numeric value of the level defined in level, when it is not one of the standard pino levels.
|
|
213
|
+
*/
|
|
214
|
+
levelVal?: number;
|
|
215
|
+
/**
|
|
216
|
+
* Only use the levels defined in customLevels and omit the standard pino ones.
|
|
217
|
+
*/
|
|
218
|
+
useOnlyCustomLevels?: boolean;
|
|
219
|
+
/**
|
|
220
|
+
* How log levels are compared to the logger level. Use DESC when lower values are more severe. Defaults to ASC.
|
|
221
|
+
*/
|
|
222
|
+
levelComparison?: "ASC" | "DESC";
|
|
223
|
+
/**
|
|
224
|
+
* A string prefixed to every message, including the ones of child loggers.
|
|
225
|
+
*/
|
|
226
|
+
msgPrefix?: string;
|
|
227
|
+
/**
|
|
228
|
+
* The key under which any logged object is placed.
|
|
229
|
+
*/
|
|
230
|
+
nestedKey?: string;
|
|
231
|
+
/**
|
|
232
|
+
* The key used for the serialized error in the log object. Defaults to err.
|
|
233
|
+
*/
|
|
234
|
+
errorKey?: string;
|
|
235
|
+
/**
|
|
236
|
+
* The stringification limit at a specific nesting depth when logging circular objects. Defaults to 5.
|
|
237
|
+
*/
|
|
238
|
+
depthLimit?: number;
|
|
239
|
+
/**
|
|
240
|
+
* The stringification limit of properties or elements when logging a circular object or array. Defaults to 100.
|
|
241
|
+
*/
|
|
242
|
+
edgeLimit?: number;
|
|
243
|
+
/**
|
|
244
|
+
* Terminate each log line with \r\n instead of \n. Defaults to false.
|
|
245
|
+
*/
|
|
246
|
+
crlf?: boolean;
|
|
247
|
+
/**
|
|
248
|
+
* Set to false to disable logging entirely. Defaults to true.
|
|
249
|
+
*/
|
|
250
|
+
enabled?: boolean;
|
|
210
251
|
openTelemetryExporter?: {
|
|
211
252
|
protocol: "grpc" | "http";
|
|
212
253
|
url: string;
|
package/lib/runtime.js
CHANGED
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
kEnvFileFallbackKeys,
|
|
9
9
|
kMetadata,
|
|
10
10
|
kTimeout,
|
|
11
|
-
parseMemorySize
|
|
11
|
+
parseMemorySize,
|
|
12
|
+
scheduleCompileCacheFlush
|
|
12
13
|
} from '@platformatic/foundation'
|
|
13
14
|
import { getExecutable } from '@platformatic/globals'
|
|
14
15
|
import { ITC } from '@platformatic/itc'
|
|
@@ -449,6 +450,11 @@ export class Runtime extends EventEmitter {
|
|
|
449
450
|
|
|
450
451
|
this.#updateStatus('started')
|
|
451
452
|
|
|
453
|
+
// The CLI enables the module compile cache for this process. Node.js would only write it when
|
|
454
|
+
// the process terminates, so flush it now that the boot is complete to not lose it when the
|
|
455
|
+
// process is killed abruptly. This is a no-op when the compile cache is not enabled.
|
|
456
|
+
scheduleCompileCacheFlush()
|
|
457
|
+
|
|
452
458
|
// Start the global health metrics timer for all workers if needed
|
|
453
459
|
this.#startHealthMetricsCollectionIfNeeded()
|
|
454
460
|
|
|
@@ -2865,7 +2871,21 @@ export class Runtime extends EventEmitter {
|
|
|
2865
2871
|
// Setup the interceptor
|
|
2866
2872
|
// kInterceptorReadyPromise resolves when the worker
|
|
2867
2873
|
// is ready to receive requests: after calling the replaceServer method
|
|
2868
|
-
|
|
2874
|
+
//
|
|
2875
|
+
// It is stored, not awaited: #startWorker awaits it later, and only if the
|
|
2876
|
+
// worker is actually started. A worker that is discarded or torn down
|
|
2877
|
+
// before that — a replacement abandoned because the runtime stopped
|
|
2878
|
+
// mid-restart, for instance — leaves the promise with nobody to observe
|
|
2879
|
+
// it. Closing the mesh interceptor rejects any routing still in flight
|
|
2880
|
+
// ('The dispatcher has been closed.'), so that is a routine shutdown
|
|
2881
|
+
// outcome, not an exotic one, and it surfaced as an unhandledRejection
|
|
2882
|
+
// that could take the process down before graceful shutdown finished.
|
|
2883
|
+
//
|
|
2884
|
+
// Attaching a no-op handler marks the rejection observed WITHOUT
|
|
2885
|
+
// swallowing it: the await in #startWorker still sees and reports it.
|
|
2886
|
+
const interceptorReady = this.#meshInterceptor.route(applicationId, worker)
|
|
2887
|
+
interceptorReady.catch(() => {})
|
|
2888
|
+
worker[kInterceptorReadyPromise] = interceptorReady
|
|
2869
2889
|
|
|
2870
2890
|
// Wait for initialization
|
|
2871
2891
|
try {
|
package/lib/worker/controller.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
convertApplicationNameToPrefix,
|
|
2
3
|
ensureLoggableError,
|
|
3
4
|
FileWatcher,
|
|
4
5
|
kHandledError,
|
|
@@ -28,12 +29,27 @@ import { ApplicationAlreadyStartedError, exitCodes, RuntimeNotStartedError } fro
|
|
|
28
29
|
import { getApplicationUrl } from '../utils.js'
|
|
29
30
|
import { markAsPlatformaticDispatcher, refreshGlobalDispatcher } from './interceptors.js'
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Resolves {PLT_<APPLICATION>_URL} placeholders that no environment variable defines, so that
|
|
34
|
+
* applications can reference each other without the user having to set a variable per pair.
|
|
35
|
+
*
|
|
36
|
+
* The mapping is built forwards, from the ids of the applications that actually exist in the runtime
|
|
37
|
+
* to the variable name each of them owns. Parsing the variable name instead would be ambiguous, both
|
|
38
|
+
* because the id to prefix conversion is not reversible ("with-logger" and "with_logger" share a
|
|
39
|
+
* prefix) and because plenty of _URL variables do not name an application at all: a connection string
|
|
40
|
+
* fragment like {VALKEY_URL} or a DSN like {PLT_DATABASE_URL} must keep resolving to nothing rather
|
|
41
|
+
* than silently becoming an HTTP URL.
|
|
42
|
+
*/
|
|
43
|
+
function buildApplicationUrlResolver (applications) {
|
|
44
|
+
const urls = new Map()
|
|
45
|
+
|
|
46
|
+
for (const { id } of applications ?? []) {
|
|
47
|
+
if (id) {
|
|
48
|
+
urls.set(`PLT_${convertApplicationNameToPrefix(id)}_URL`, getApplicationUrl(id))
|
|
49
|
+
}
|
|
34
50
|
}
|
|
35
51
|
|
|
36
|
-
return
|
|
52
|
+
return key => urls.get(key) ?? null
|
|
37
53
|
}
|
|
38
54
|
|
|
39
55
|
function handleUnhandled (app, event, listeners, timeout, err, ...args) {
|
|
@@ -53,7 +69,11 @@ function handleUnhandled (app, event, listeners, timeout, err, ...args) {
|
|
|
53
69
|
}
|
|
54
70
|
}
|
|
55
71
|
|
|
56
|
-
|
|
72
|
+
// stop() rejects while the controller is not started. Left unobserved, that rejection re-enters
|
|
73
|
+
// this handler forever and starves the event loop, so the exit scheduled above never runs.
|
|
74
|
+
app.stop().catch(stopError => {
|
|
75
|
+
logger.debug({ err: ensureLoggableError(stopError) }, `Stopping the ${label} after the ${event} event failed.`)
|
|
76
|
+
})
|
|
57
77
|
}
|
|
58
78
|
|
|
59
79
|
export class Controller extends EventEmitter {
|
|
@@ -78,6 +98,8 @@ export class Controller extends EventEmitter {
|
|
|
78
98
|
this.capability = null
|
|
79
99
|
this.#fileWatcher = null
|
|
80
100
|
|
|
101
|
+
const onMissingEnv = buildApplicationUrlResolver(runtimeConfig.applications)
|
|
102
|
+
|
|
81
103
|
this.#context = {
|
|
82
104
|
controller: this,
|
|
83
105
|
runtimeConfig: this.runtimeConfig,
|
|
@@ -95,7 +117,10 @@ export class Controller extends EventEmitter {
|
|
|
95
117
|
worker: workerData?.worker,
|
|
96
118
|
resourceLimits: workerData?.resourceLimits,
|
|
97
119
|
hasManagementApi: !!runtimeConfig.managementApi,
|
|
98
|
-
fetchApplicationUrl:
|
|
120
|
+
fetchApplicationUrl: onMissingEnv,
|
|
121
|
+
// Capabilities spread the whole context into their loadConfiguration call, which is what makes
|
|
122
|
+
// the configuration they load resolve application references like the throwaway load below.
|
|
123
|
+
onMissingEnv,
|
|
99
124
|
strictEnv: runtimeConfig.strictEnv
|
|
100
125
|
}
|
|
101
126
|
}
|
|
@@ -143,10 +168,11 @@ export class Controller extends EventEmitter {
|
|
|
143
168
|
// Parse the configuration file the first time to obtain the schema. This load is thrown away:
|
|
144
169
|
// the capability loads the configuration again below and that is the configuration the
|
|
145
170
|
// application actually runs on. This one only has to yield $schema and module, so it must not
|
|
146
|
-
// diverge from the second load in any way the user can observe: it
|
|
147
|
-
//
|
|
148
|
-
//
|
|
171
|
+
// diverge from the second load in any way the user can observe: it resolves environment
|
|
172
|
+
// variables identically, and leaves the strictEnv report to the load the application is
|
|
173
|
+
// built from, which would otherwise be duplicated for every application.
|
|
149
174
|
const unvalidatedConfig = await loadConfiguration(appConfig.config, null, {
|
|
175
|
+
onMissingEnv: this.#context.onMissingEnv,
|
|
150
176
|
strictEnv: false
|
|
151
177
|
})
|
|
152
178
|
const pkg = await loadConfigurationModule(appConfig.path, unvalidatedConfig)
|
package/lib/worker/main.js
CHANGED
|
@@ -4,7 +4,8 @@ import {
|
|
|
4
4
|
disablePinoDirectWrite,
|
|
5
5
|
ensureLoggableError,
|
|
6
6
|
getPrivateSymbol,
|
|
7
|
-
parseMemorySize
|
|
7
|
+
parseMemorySize,
|
|
8
|
+
scheduleCompileCacheFlush
|
|
8
9
|
} from '@platformatic/foundation'
|
|
9
10
|
import { getITC, getLogger, updateGlobals } from '@platformatic/globals'
|
|
10
11
|
import { addPinoInstrumentation } from '@platformatic/telemetry'
|
|
@@ -149,6 +150,9 @@ function setupDefaultHighWaterMark (runtimeConfig, applicationConfig, logger) {
|
|
|
149
150
|
}
|
|
150
151
|
}
|
|
151
152
|
|
|
153
|
+
// Whether the module compile cache has been enabled in this worker.
|
|
154
|
+
let compileCacheEnabled = false
|
|
155
|
+
|
|
152
156
|
// Enable compile cache if configured (Node.js 22.1.0+)
|
|
153
157
|
async function setupCompileCache (runtimeConfig, applicationConfig, logger) {
|
|
154
158
|
// Normalize boolean shorthand: true -> { enabled: true }
|
|
@@ -187,8 +191,10 @@ async function setupCompileCache (runtimeConfig, applicationConfig, logger) {
|
|
|
187
191
|
const { compileCacheStatus } = moduleApi.constants ?? {}
|
|
188
192
|
|
|
189
193
|
if (result.status === compileCacheStatus?.ENABLED) {
|
|
194
|
+
compileCacheEnabled = true
|
|
190
195
|
logger.debug({ directory: result.directory }, 'Module compile cache enabled')
|
|
191
196
|
} else if (result.status === compileCacheStatus?.ALREADY_ENABLED) {
|
|
197
|
+
compileCacheEnabled = true
|
|
192
198
|
logger.debug({ directory: result.directory }, 'Module compile cache already enabled')
|
|
193
199
|
} else if (result.status === compileCacheStatus?.FAILED) {
|
|
194
200
|
logger.warn({ message: result.message }, 'Failed to enable module compile cache')
|
|
@@ -319,6 +325,14 @@ async function main () {
|
|
|
319
325
|
|
|
320
326
|
await controller.init(cleanup)
|
|
321
327
|
|
|
328
|
+
// Make the compile cache accumulated while booting durable, as Node.js would otherwise only write
|
|
329
|
+
// it when the worker terminates.
|
|
330
|
+
controller.on('started', () => {
|
|
331
|
+
if (compileCacheEnabled) {
|
|
332
|
+
scheduleCompileCacheFlush(logger)
|
|
333
|
+
}
|
|
334
|
+
})
|
|
335
|
+
|
|
322
336
|
if (applicationConfig.entrypoint && runtimeConfig.basePath) {
|
|
323
337
|
const meta = await controller.capability.getMeta()
|
|
324
338
|
if (!meta.gateway.wantsAbsoluteUrls) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.70.0",
|
|
4
4
|
"description": "Platformatic runtime",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -35,18 +35,18 @@
|
|
|
35
35
|
"pino-abstract-transport": "^2.0.0",
|
|
36
36
|
"pino-sentry-transport": "^1.6.0",
|
|
37
37
|
"split2": "^4.2.0",
|
|
38
|
-
"tstyche": "^
|
|
38
|
+
"tstyche": "^7.0.0",
|
|
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": "3.
|
|
43
|
-
"@platformatic/db": "3.
|
|
44
|
-
"@platformatic/gateway": "3.
|
|
45
|
-
"@platformatic/node": "3.
|
|
46
|
-
"@platformatic/service": "3.
|
|
47
|
-
"@platformatic/sql-graphql": "3.
|
|
48
|
-
"@platformatic/sql-mapper": "3.
|
|
49
|
-
"@platformatic/wattpm-pprof-capture": "3.
|
|
42
|
+
"@platformatic/composer": "3.70.0",
|
|
43
|
+
"@platformatic/db": "3.70.0",
|
|
44
|
+
"@platformatic/gateway": "3.70.0",
|
|
45
|
+
"@platformatic/node": "3.70.0",
|
|
46
|
+
"@platformatic/service": "3.70.0",
|
|
47
|
+
"@platformatic/sql-graphql": "3.70.0",
|
|
48
|
+
"@platformatic/sql-mapper": "3.70.0",
|
|
49
|
+
"@platformatic/wattpm-pprof-capture": "3.70.0"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@fastify/accepts": "^5.0.0",
|
|
@@ -77,13 +77,13 @@
|
|
|
77
77
|
"undici": "^7.27.2",
|
|
78
78
|
"undici-thread-interceptor": "^1.3.1",
|
|
79
79
|
"ws": "^8.16.0",
|
|
80
|
-
"@platformatic/
|
|
81
|
-
"@platformatic/
|
|
82
|
-
"@platformatic/
|
|
83
|
-
"@platformatic/
|
|
84
|
-
"@platformatic/
|
|
85
|
-
"@platformatic/
|
|
86
|
-
"@platformatic/
|
|
80
|
+
"@platformatic/foundation": "3.70.0",
|
|
81
|
+
"@platformatic/basic": "3.70.0",
|
|
82
|
+
"@platformatic/generators": "3.70.0",
|
|
83
|
+
"@platformatic/itc": "3.70.0",
|
|
84
|
+
"@platformatic/metrics": "3.70.0",
|
|
85
|
+
"@platformatic/telemetry": "3.70.0",
|
|
86
|
+
"@platformatic/globals": "3.70.0"
|
|
87
87
|
},
|
|
88
88
|
"engines": {
|
|
89
89
|
"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.70.0.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
4
|
"title": "Platformatic Runtime Config",
|
|
5
5
|
"type": "object",
|
|
@@ -1894,22 +1894,7 @@
|
|
|
1894
1894
|
"properties": {
|
|
1895
1895
|
"level": {
|
|
1896
1896
|
"type": "string",
|
|
1897
|
-
"
|
|
1898
|
-
{
|
|
1899
|
-
"enum": [
|
|
1900
|
-
"fatal",
|
|
1901
|
-
"error",
|
|
1902
|
-
"warn",
|
|
1903
|
-
"info",
|
|
1904
|
-
"debug",
|
|
1905
|
-
"trace",
|
|
1906
|
-
"silent"
|
|
1907
|
-
]
|
|
1908
|
-
},
|
|
1909
|
-
{
|
|
1910
|
-
"pattern": "^\\{.+\\}$"
|
|
1911
|
-
}
|
|
1912
|
-
]
|
|
1897
|
+
"description": "The log level. It must be one of the standard pino levels (fatal, error, warn, info, debug, trace, silent) or, when customLevels is set, one of the custom levels."
|
|
1913
1898
|
},
|
|
1914
1899
|
"transport": {
|
|
1915
1900
|
"anyOf": [
|
|
@@ -2010,6 +1995,10 @@
|
|
|
2010
1995
|
"censor": {
|
|
2011
1996
|
"type": "string",
|
|
2012
1997
|
"default": "[redacted]"
|
|
1998
|
+
},
|
|
1999
|
+
"remove": {
|
|
2000
|
+
"type": "boolean",
|
|
2001
|
+
"description": "Remove the redacted keys entirely instead of replacing their values with the censor. Defaults to false."
|
|
2013
2002
|
}
|
|
2014
2003
|
},
|
|
2015
2004
|
"required": [
|
|
@@ -2035,6 +2024,50 @@
|
|
|
2035
2024
|
"type": "object",
|
|
2036
2025
|
"additionalProperties": true
|
|
2037
2026
|
},
|
|
2027
|
+
"levelVal": {
|
|
2028
|
+
"type": "integer",
|
|
2029
|
+
"description": "The numeric value of the level defined in level, when it is not one of the standard pino levels."
|
|
2030
|
+
},
|
|
2031
|
+
"useOnlyCustomLevels": {
|
|
2032
|
+
"type": "boolean",
|
|
2033
|
+
"description": "Only use the levels defined in customLevels and omit the standard pino ones."
|
|
2034
|
+
},
|
|
2035
|
+
"levelComparison": {
|
|
2036
|
+
"type": "string",
|
|
2037
|
+
"enum": [
|
|
2038
|
+
"ASC",
|
|
2039
|
+
"DESC"
|
|
2040
|
+
],
|
|
2041
|
+
"description": "How log levels are compared to the logger level. Use DESC when lower values are more severe. Defaults to ASC."
|
|
2042
|
+
},
|
|
2043
|
+
"msgPrefix": {
|
|
2044
|
+
"type": "string",
|
|
2045
|
+
"description": "A string prefixed to every message, including the ones of child loggers."
|
|
2046
|
+
},
|
|
2047
|
+
"nestedKey": {
|
|
2048
|
+
"type": "string",
|
|
2049
|
+
"description": "The key under which any logged object is placed."
|
|
2050
|
+
},
|
|
2051
|
+
"errorKey": {
|
|
2052
|
+
"type": "string",
|
|
2053
|
+
"description": "The key used for the serialized error in the log object. Defaults to err."
|
|
2054
|
+
},
|
|
2055
|
+
"depthLimit": {
|
|
2056
|
+
"type": "integer",
|
|
2057
|
+
"description": "The stringification limit at a specific nesting depth when logging circular objects. Defaults to 5."
|
|
2058
|
+
},
|
|
2059
|
+
"edgeLimit": {
|
|
2060
|
+
"type": "integer",
|
|
2061
|
+
"description": "The stringification limit of properties or elements when logging a circular object or array. Defaults to 100."
|
|
2062
|
+
},
|
|
2063
|
+
"crlf": {
|
|
2064
|
+
"type": "boolean",
|
|
2065
|
+
"description": "Terminate each log line with \\r\\n instead of \\n. Defaults to false."
|
|
2066
|
+
},
|
|
2067
|
+
"enabled": {
|
|
2068
|
+
"type": "boolean",
|
|
2069
|
+
"description": "Set to false to disable logging entirely. Defaults to true."
|
|
2070
|
+
},
|
|
2038
2071
|
"openTelemetryExporter": {
|
|
2039
2072
|
"type": "object",
|
|
2040
2073
|
"properties": {
|
|
@@ -2079,6 +2112,35 @@
|
|
|
2079
2112
|
"additionalProperties": false
|
|
2080
2113
|
}
|
|
2081
2114
|
},
|
|
2115
|
+
"if": {
|
|
2116
|
+
"not": {
|
|
2117
|
+
"required": [
|
|
2118
|
+
"customLevels"
|
|
2119
|
+
]
|
|
2120
|
+
}
|
|
2121
|
+
},
|
|
2122
|
+
"then": {
|
|
2123
|
+
"properties": {
|
|
2124
|
+
"level": {
|
|
2125
|
+
"oneOf": [
|
|
2126
|
+
{
|
|
2127
|
+
"enum": [
|
|
2128
|
+
"fatal",
|
|
2129
|
+
"error",
|
|
2130
|
+
"warn",
|
|
2131
|
+
"info",
|
|
2132
|
+
"debug",
|
|
2133
|
+
"trace",
|
|
2134
|
+
"silent"
|
|
2135
|
+
]
|
|
2136
|
+
},
|
|
2137
|
+
{
|
|
2138
|
+
"pattern": "^\\{.+\\}$"
|
|
2139
|
+
}
|
|
2140
|
+
]
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
},
|
|
2082
2144
|
"default": {},
|
|
2083
2145
|
"additionalProperties": true
|
|
2084
2146
|
},
|