@platformatic/runtime 3.31.0 → 3.32.0-alpha.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 CHANGED
@@ -42,6 +42,7 @@ export type PlatformaticRuntimeConfig = {
42
42
  maxHeapTotal?: number | string;
43
43
  maxYoungGeneration?: number | string;
44
44
  codeRangeSize?: number | string;
45
+ noHeapCheck?: boolean | string;
45
46
  };
46
47
  dependencies?: string[];
47
48
  arguments?: string[];
@@ -78,18 +79,6 @@ export type PlatformaticRuntimeConfig = {
78
79
  )[];
79
80
  [k: string]: unknown;
80
81
  };
81
- compileCache?:
82
- | boolean
83
- | {
84
- /**
85
- * Enable Node.js module compile cache for faster startup
86
- */
87
- enabled?: boolean;
88
- /**
89
- * Directory to store compile cache. Defaults to .plt/compile-cache in app root
90
- */
91
- directory?: string;
92
- };
93
82
  };
94
83
  };
95
84
  };
@@ -120,7 +109,7 @@ export type PlatformaticRuntimeConfig = {
120
109
  };
121
110
  workersRestartDelay?: number | string;
122
111
  logger?: {
123
- level?: (
112
+ level: (
124
113
  | ("fatal" | "error" | "warn" | "info" | "debug" | "trace" | "silent")
125
114
  | {
126
115
  [k: string]: unknown;
@@ -224,6 +213,7 @@ export type PlatformaticRuntimeConfig = {
224
213
  maxHeapTotal?: number | string;
225
214
  maxYoungGeneration?: number | string;
226
215
  codeRangeSize?: number | string;
216
+ noHeapCheck?: boolean | string;
227
217
  };
228
218
  undici?: {
229
219
  agentOptions?: {
@@ -513,16 +503,4 @@ export type PlatformaticRuntimeConfig = {
513
503
  [k: string]: string | [string, ...string[]];
514
504
  };
515
505
  };
516
- compileCache?:
517
- | boolean
518
- | {
519
- /**
520
- * Enable Node.js module compile cache for faster startup
521
- */
522
- enabled?: boolean;
523
- /**
524
- * Directory to store compile cache. Defaults to .plt/compile-cache in app root
525
- */
526
- directory?: string;
527
- };
528
506
  };
package/lib/runtime.js CHANGED
@@ -10,7 +10,6 @@ import {
10
10
  parseMemorySize
11
11
  } from '@platformatic/foundation'
12
12
  import { ITC } from '@platformatic/itc'
13
- import { client as metricsClient, collectProcessMetrics } from '@platformatic/metrics'
14
13
  import fastify from 'fastify'
15
14
  import { EventEmitter, once } from 'node:events'
16
15
  import { existsSync } from 'node:fs'
@@ -120,8 +119,6 @@ export class Runtime extends EventEmitter {
120
119
 
121
120
  #channelCreationHook
122
121
 
123
- #processMetricsRegistry
124
-
125
122
  constructor (config, context) {
126
123
  super()
127
124
  this.setMaxListeners(MAX_LISTENERS_COUNT)
@@ -200,14 +197,6 @@ export class Runtime extends EventEmitter {
200
197
  this.#metricsLabelName = 'applicationId'
201
198
  }
202
199
 
203
- // Initialize process-level metrics registry in the main thread if metrics or management API is enabled
204
- // These metrics are the same across all workers and only need to be collected once
205
- // We need this for management API as it can request metrics even without explicit metrics config
206
- if (config.metrics || config.managementApi) {
207
- this.#processMetricsRegistry = new metricsClient.Registry()
208
- collectProcessMetrics(this.#processMetricsRegistry)
209
- }
210
-
211
200
  // Create the logger
212
201
  const [logger, destination, context] = await createLogger(config)
213
202
  this.logger = logger
@@ -357,12 +346,6 @@ export class Runtime extends EventEmitter {
357
346
  await this.#prometheusServer.close()
358
347
  }
359
348
 
360
- // Clean up process metrics registry
361
- if (this.#processMetricsRegistry) {
362
- this.#processMetricsRegistry.clear()
363
- this.#processMetricsRegistry = null
364
- }
365
-
366
349
  if (this.#sharedHttpCache?.close) {
367
350
  await this.#sharedHttpCache.close()
368
351
  }
@@ -1076,12 +1059,6 @@ export class Runtime extends EventEmitter {
1076
1059
  async getMetrics (format = 'json') {
1077
1060
  let metrics = null
1078
1061
 
1079
- // Get process-level metrics once from main thread registry (if available)
1080
- let processMetricsJson = null
1081
- if (this.#processMetricsRegistry) {
1082
- processMetricsJson = await this.#processMetricsRegistry.getMetricsAsJSON()
1083
- }
1084
-
1085
1062
  for (const worker of this.#workers.values()) {
1086
1063
  try {
1087
1064
  // The application might be temporarily unavailable
@@ -1089,7 +1066,6 @@ export class Runtime extends EventEmitter {
1089
1066
  continue
1090
1067
  }
1091
1068
 
1092
- // Get thread-specific metrics from worker
1093
1069
  const applicationMetrics = await executeWithTimeout(
1094
1070
  sendViaITC(worker, 'getMetrics', format),
1095
1071
  this.#config.metrics?.timeout ?? 10000
@@ -1100,30 +1076,9 @@ export class Runtime extends EventEmitter {
1100
1076
  metrics = format === 'json' ? [] : ''
1101
1077
  }
1102
1078
 
1103
- // Build worker labels including custom labels from metrics config
1104
- const workerLabels = {
1105
- ...this.#config.metrics?.labels,
1106
- [this.#metricsLabelName]: worker[kApplicationId]
1107
- }
1108
- const workerId = worker[kWorkerId]
1109
- if (workerId >= 0) {
1110
- workerLabels.workerId = workerId
1111
- }
1112
-
1113
1079
  if (format === 'json') {
1114
- // Duplicate process metrics with worker labels and add to output
1115
- if (processMetricsJson) {
1116
- this.#applyLabelsToMetrics(processMetricsJson, workerLabels, metrics)
1117
- }
1118
- // Add worker's thread-specific metrics
1119
- for (let i = 0; i < applicationMetrics.length; i++) {
1120
- metrics.push(applicationMetrics[i])
1121
- }
1080
+ metrics.push(...applicationMetrics)
1122
1081
  } else {
1123
- // Text format: format process metrics with worker labels
1124
- if (processMetricsJson) {
1125
- metrics += this.#formatProcessMetricsText(processMetricsJson, workerLabels)
1126
- }
1127
1082
  metrics += applicationMetrics
1128
1083
  }
1129
1084
  }
@@ -1144,65 +1099,6 @@ export class Runtime extends EventEmitter {
1144
1099
  return { metrics }
1145
1100
  }
1146
1101
 
1147
- // Apply labels to process metrics and push to output array (for JSON format)
1148
- #applyLabelsToMetrics (processMetrics, labels, outputArray) {
1149
- for (let i = 0; i < processMetrics.length; i++) {
1150
- const metric = processMetrics[i]
1151
- const newValues = []
1152
- const values = metric.values
1153
- for (let j = 0; j < values.length; j++) {
1154
- const v = values[j]
1155
- newValues.push({
1156
- value: v.value,
1157
- labels: { ...labels, ...v.labels },
1158
- metricName: v.metricName
1159
- })
1160
- }
1161
- outputArray.push({
1162
- name: metric.name,
1163
- help: metric.help,
1164
- type: metric.type,
1165
- aggregator: metric.aggregator,
1166
- values: newValues
1167
- })
1168
- }
1169
- }
1170
-
1171
- // Format process metrics as Prometheus text format with labels
1172
- #formatProcessMetricsText (processMetricsJson, labels) {
1173
- let output = ''
1174
-
1175
- for (let i = 0; i < processMetricsJson.length; i++) {
1176
- const metric = processMetricsJson[i]
1177
- const name = metric.name
1178
- const help = metric.help
1179
- const type = metric.type
1180
-
1181
- // Add HELP and TYPE lines
1182
- output += `# HELP ${name} ${help}\n`
1183
- output += `# TYPE ${name} ${type}\n`
1184
-
1185
- const values = metric.values
1186
- for (let j = 0; j < values.length; j++) {
1187
- const v = values[j]
1188
- const combinedLabels = { ...labels, ...v.labels }
1189
- const labelParts = []
1190
-
1191
- for (const [key, val] of Object.entries(combinedLabels)) {
1192
- // Escape label values for Prometheus format
1193
- const escapedVal = String(val).replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n')
1194
- labelParts.push(`${key}="${escapedVal}"`)
1195
- }
1196
-
1197
- const labelStr = labelParts.length > 0 ? `{${labelParts.join(',')}}` : ''
1198
- const metricName = v.metricName || name
1199
- output += `${metricName}${labelStr} ${v.value}\n`
1200
- }
1201
- }
1202
-
1203
- return output
1204
- }
1205
-
1206
1102
  async getFormattedMetrics () {
1207
1103
  try {
1208
1104
  const { metrics } = await this.getMetrics()
@@ -1453,7 +1349,7 @@ export class Runtime extends EventEmitter {
1453
1349
  elu = worker.performance.eventLoopUtilization(elu, previousELU)
1454
1350
  }
1455
1351
 
1456
- if (!features.node.worker.getHeapStatistics) {
1352
+ if (!features.node.worker.getHeapStatistics || options.noHeapCheck) {
1457
1353
  return { elu: elu.utilization, currentELU }
1458
1354
  }
1459
1355
 
@@ -1668,8 +1564,7 @@ export class Runtime extends EventEmitter {
1668
1564
  codeRangeSizeMb
1669
1565
  },
1670
1566
  stdout: true,
1671
- stderr: true,
1672
- name: workerId
1567
+ stderr: true
1673
1568
  })
1674
1569
 
1675
1570
  this.#handleWorkerStandardStreams(worker, applicationId, index)
@@ -1858,7 +1753,8 @@ export class Runtime extends EventEmitter {
1858
1753
  let health = null
1859
1754
  try {
1860
1755
  health = await this.getWorkerHealth(worker, {
1861
- previousELU: worker[kLastHealthCheckELU]
1756
+ previousELU: worker[kLastHealthCheckELU],
1757
+ noHeapCheck: worker[kConfig]?.health?.noHeapCheck
1862
1758
  })
1863
1759
  } catch (err) {
1864
1760
  this.logger.error({ err }, `Failed to get health for ${errorLabel}.`)
@@ -1902,7 +1798,7 @@ export class Runtime extends EventEmitter {
1902
1798
 
1903
1799
  const healthConfig = worker[kConfig].health
1904
1800
 
1905
- let { maxELU, maxHeapUsed, maxHeapTotal, maxUnhealthyChecks, interval } = worker[kConfig].health
1801
+ let { maxELU, maxHeapUsed, maxHeapTotal, maxUnhealthyChecks, interval, noHeapCheck } = worker[kConfig].health
1906
1802
 
1907
1803
  if (typeof maxHeapTotal === 'string') {
1908
1804
  maxHeapTotal = parseMemorySize(maxHeapTotal)
@@ -1933,8 +1829,8 @@ export class Runtime extends EventEmitter {
1933
1829
 
1934
1830
  if (lastHealthMetrics) {
1935
1831
  const health = lastHealthMetrics.currentHealth
1936
- const memoryUsage = health.heapUsed / maxHeapTotal
1937
- const unhealthy = health.elu > maxELU || memoryUsage > maxHeapUsed
1832
+ const memoryUsage = noHeapCheck ? 0 : health.heapUsed / maxHeapTotal
1833
+ const unhealthy = health.elu > maxELU || (!noHeapCheck && memoryUsage > maxHeapUsed)
1938
1834
 
1939
1835
  this.emit('application:worker:health', {
1940
1836
  id: worker[kId],
@@ -1952,7 +1848,7 @@ export class Runtime extends EventEmitter {
1952
1848
  )
1953
1849
  }
1954
1850
 
1955
- if (memoryUsage > maxHeapUsed) {
1851
+ if (!noHeapCheck && memoryUsage > maxHeapUsed) {
1956
1852
  this.logger.error(
1957
1853
  `The ${errorLabel} is using ${(memoryUsage * 100).toFixed(2)} % of the memory, ` +
1958
1854
  `above the maximum allowed usage of ${(maxHeapUsed * 100).toFixed(2)} %.`
@@ -9,7 +9,7 @@ import { EventEmitter } from 'node:events'
9
9
  import { ServerResponse } from 'node:http'
10
10
  import inspector from 'node:inspector'
11
11
  import { hostname } from 'node:os'
12
- import { join, resolve } from 'node:path'
12
+ import { resolve } from 'node:path'
13
13
  import { pathToFileURL } from 'node:url'
14
14
  import { threadId, workerData } from 'node:worker_threads'
15
15
  import pino from 'pino'
@@ -85,57 +85,6 @@ async function performPreloading (...sources) {
85
85
  }
86
86
  }
87
87
 
88
- // Enable compile cache if configured (Node.js 22.1.0+)
89
- async function setupCompileCache (runtimeConfig, applicationConfig, logger) {
90
- // Normalize boolean shorthand: true -> { enabled: true }
91
- const normalizeConfig = cfg => {
92
- if (cfg === true) return { enabled: true }
93
- if (cfg === false) return { enabled: false }
94
- return cfg
95
- }
96
-
97
- // Merge runtime and app-level config (app overrides runtime)
98
- const runtimeCache = normalizeConfig(runtimeConfig.compileCache)
99
- const appCache = normalizeConfig(applicationConfig.compileCache)
100
- const config = { ...runtimeCache, ...appCache }
101
-
102
- if (!config.enabled) {
103
- return
104
- }
105
-
106
- // Check if API is available (Node.js 22.1.0+)
107
- let moduleApi
108
- try {
109
- moduleApi = await import('node:module')
110
- if (typeof moduleApi.enableCompileCache !== 'function') {
111
- return
112
- }
113
- } catch {
114
- return
115
- }
116
-
117
- // Determine cache directory - use applicationConfig.path for the app root
118
- const cacheDir = config.directory ?? join(applicationConfig.path, '.plt', 'compile-cache')
119
-
120
- try {
121
- const result = moduleApi.enableCompileCache(cacheDir)
122
-
123
- const { compileCacheStatus } = moduleApi.constants ?? {}
124
-
125
- if (result.status === compileCacheStatus?.ENABLED) {
126
- logger.debug({ directory: result.directory }, 'Module compile cache enabled')
127
- } else if (result.status === compileCacheStatus?.ALREADY_ENABLED) {
128
- logger.debug({ directory: result.directory }, 'Module compile cache already enabled')
129
- } else if (result.status === compileCacheStatus?.FAILED) {
130
- logger.warn({ message: result.message }, 'Failed to enable module compile cache')
131
- } else if (result.status === compileCacheStatus?.DISABLED) {
132
- logger.debug('Module compile cache disabled via NODE_DISABLE_COMPILE_CACHE')
133
- }
134
- } catch (err) {
135
- logger.warn({ err }, 'Error enabling module compile cache')
136
- }
137
- }
138
-
139
88
  async function main () {
140
89
  globalThis.fetch = fetch
141
90
  globalThis[kId] = threadId
@@ -145,12 +94,10 @@ async function main () {
145
94
  })
146
95
 
147
96
  const runtimeConfig = workerData.config
148
- const applicationConfig = workerData.applicationConfig
149
97
 
150
- // Enable compile cache early before loading user modules
151
- await setupCompileCache(runtimeConfig, applicationConfig, globalThis.platformatic.logger)
98
+ await performPreloading(runtimeConfig, workerData.applicationConfig)
152
99
 
153
- await performPreloading(runtimeConfig, applicationConfig)
100
+ const applicationConfig = workerData.applicationConfig
154
101
 
155
102
  // Load env file and mixin env vars from application config
156
103
  let envfile
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "3.31.0",
3
+ "version": "3.32.0-alpha.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/composer": "3.31.0",
39
- "@platformatic/db": "3.31.0",
40
- "@platformatic/gateway": "3.31.0",
41
- "@platformatic/node": "3.31.0",
42
- "@platformatic/sql-graphql": "3.31.0",
43
- "@platformatic/service": "3.31.0",
44
- "@platformatic/wattpm-pprof-capture": "3.31.0",
45
- "@platformatic/sql-mapper": "3.31.0"
38
+ "@platformatic/composer": "3.32.0-alpha.0",
39
+ "@platformatic/db": "3.32.0-alpha.0",
40
+ "@platformatic/node": "3.32.0-alpha.0",
41
+ "@platformatic/service": "3.32.0-alpha.0",
42
+ "@platformatic/gateway": "3.32.0-alpha.0",
43
+ "@platformatic/sql-graphql": "3.32.0-alpha.0",
44
+ "@platformatic/wattpm-pprof-capture": "3.32.0-alpha.0",
45
+ "@platformatic/sql-mapper": "3.32.0-alpha.0"
46
46
  },
47
47
  "dependencies": {
48
48
  "@fastify/accepts": "^5.0.0",
@@ -71,12 +71,12 @@
71
71
  "undici": "^7.0.0",
72
72
  "undici-thread-interceptor": "^1.0.0",
73
73
  "ws": "^8.16.0",
74
- "@platformatic/generators": "3.31.0",
75
- "@platformatic/basic": "3.31.0",
76
- "@platformatic/foundation": "3.31.0",
77
- "@platformatic/itc": "3.31.0",
78
- "@platformatic/metrics": "3.31.0",
79
- "@platformatic/telemetry": "3.31.0"
74
+ "@platformatic/basic": "3.32.0-alpha.0",
75
+ "@platformatic/foundation": "3.32.0-alpha.0",
76
+ "@platformatic/generators": "3.32.0-alpha.0",
77
+ "@platformatic/itc": "3.32.0-alpha.0",
78
+ "@platformatic/metrics": "3.32.0-alpha.0",
79
+ "@platformatic/telemetry": "3.32.0-alpha.0"
80
80
  },
81
81
  "engines": {
82
82
  "node": ">=22.19.0"
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.31.0.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.32.0-alpha.0.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "title": "Platformatic Runtime Config",
5
5
  "type": "object",
@@ -208,6 +208,16 @@
208
208
  "type": "string"
209
209
  }
210
210
  ]
211
+ },
212
+ "noHeapCheck": {
213
+ "anyOf": [
214
+ {
215
+ "type": "boolean"
216
+ },
217
+ {
218
+ "type": "string"
219
+ }
220
+ ]
211
221
  }
212
222
  },
213
223
  "additionalProperties": false
@@ -332,28 +342,6 @@
332
342
  }
333
343
  }
334
344
  }
335
- },
336
- "compileCache": {
337
- "anyOf": [
338
- {
339
- "type": "boolean"
340
- },
341
- {
342
- "type": "object",
343
- "properties": {
344
- "enabled": {
345
- "type": "boolean",
346
- "default": true,
347
- "description": "Enable Node.js module compile cache for faster startup"
348
- },
349
- "directory": {
350
- "type": "string",
351
- "description": "Directory to store compile cache. Defaults to .plt/compile-cache in app root"
352
- }
353
- },
354
- "additionalProperties": false
355
- }
356
- ]
357
345
  }
358
346
  }
359
347
  }
@@ -544,6 +532,16 @@
544
532
  "type": "string"
545
533
  }
546
534
  ]
535
+ },
536
+ "noHeapCheck": {
537
+ "anyOf": [
538
+ {
539
+ "type": "boolean"
540
+ },
541
+ {
542
+ "type": "string"
543
+ }
544
+ ]
547
545
  }
548
546
  },
549
547
  "additionalProperties": false
@@ -668,28 +666,6 @@
668
666
  }
669
667
  }
670
668
  }
671
- },
672
- "compileCache": {
673
- "anyOf": [
674
- {
675
- "type": "boolean"
676
- },
677
- {
678
- "type": "object",
679
- "properties": {
680
- "enabled": {
681
- "type": "boolean",
682
- "default": true,
683
- "description": "Enable Node.js module compile cache for faster startup"
684
- },
685
- "directory": {
686
- "type": "string",
687
- "description": "Directory to store compile cache. Defaults to .plt/compile-cache in app root"
688
- }
689
- },
690
- "additionalProperties": false
691
- }
692
- ]
693
669
  }
694
670
  }
695
671
  }
@@ -878,6 +854,16 @@
878
854
  "type": "string"
879
855
  }
880
856
  ]
857
+ },
858
+ "noHeapCheck": {
859
+ "anyOf": [
860
+ {
861
+ "type": "boolean"
862
+ },
863
+ {
864
+ "type": "string"
865
+ }
866
+ ]
881
867
  }
882
868
  },
883
869
  "additionalProperties": false
@@ -1002,28 +988,6 @@
1002
988
  }
1003
989
  }
1004
990
  }
1005
- },
1006
- "compileCache": {
1007
- "anyOf": [
1008
- {
1009
- "type": "boolean"
1010
- },
1011
- {
1012
- "type": "object",
1013
- "properties": {
1014
- "enabled": {
1015
- "type": "boolean",
1016
- "default": true,
1017
- "description": "Enable Node.js module compile cache for faster startup"
1018
- },
1019
- "directory": {
1020
- "type": "string",
1021
- "description": "Directory to store compile cache. Defaults to .plt/compile-cache in app root"
1022
- }
1023
- },
1024
- "additionalProperties": false
1025
- }
1026
- ]
1027
991
  }
1028
992
  }
1029
993
  }
@@ -1212,6 +1176,16 @@
1212
1176
  "type": "string"
1213
1177
  }
1214
1178
  ]
1179
+ },
1180
+ "noHeapCheck": {
1181
+ "anyOf": [
1182
+ {
1183
+ "type": "boolean"
1184
+ },
1185
+ {
1186
+ "type": "string"
1187
+ }
1188
+ ]
1215
1189
  }
1216
1190
  },
1217
1191
  "additionalProperties": false
@@ -1336,28 +1310,6 @@
1336
1310
  }
1337
1311
  }
1338
1312
  }
1339
- },
1340
- "compileCache": {
1341
- "anyOf": [
1342
- {
1343
- "type": "boolean"
1344
- },
1345
- {
1346
- "type": "object",
1347
- "properties": {
1348
- "enabled": {
1349
- "type": "boolean",
1350
- "default": true,
1351
- "description": "Enable Node.js module compile cache for faster startup"
1352
- },
1353
- "directory": {
1354
- "type": "string",
1355
- "description": "Directory to store compile cache. Defaults to .plt/compile-cache in app root"
1356
- }
1357
- },
1358
- "additionalProperties": false
1359
- }
1360
- ]
1361
1313
  }
1362
1314
  }
1363
1315
  }
@@ -1437,6 +1389,7 @@
1437
1389
  "properties": {
1438
1390
  "level": {
1439
1391
  "type": "string",
1392
+ "default": "info",
1440
1393
  "oneOf": [
1441
1394
  {
1442
1395
  "enum": [
@@ -1583,6 +1536,9 @@
1583
1536
  "default": true
1584
1537
  }
1585
1538
  },
1539
+ "required": [
1540
+ "level"
1541
+ ],
1586
1542
  "default": {},
1587
1543
  "additionalProperties": true
1588
1544
  },
@@ -1878,6 +1834,17 @@
1878
1834
  }
1879
1835
  ],
1880
1836
  "default": 268435456
1837
+ },
1838
+ "noHeapCheck": {
1839
+ "anyOf": [
1840
+ {
1841
+ "type": "boolean"
1842
+ },
1843
+ {
1844
+ "type": "string"
1845
+ }
1846
+ ],
1847
+ "default": false
1881
1848
  }
1882
1849
  },
1883
1850
  "additionalProperties": false
@@ -2654,28 +2621,6 @@
2654
2621
  "deny"
2655
2622
  ],
2656
2623
  "additionalProperties": false
2657
- },
2658
- "compileCache": {
2659
- "anyOf": [
2660
- {
2661
- "type": "boolean"
2662
- },
2663
- {
2664
- "type": "object",
2665
- "properties": {
2666
- "enabled": {
2667
- "type": "boolean",
2668
- "default": true,
2669
- "description": "Enable Node.js module compile cache for faster startup"
2670
- },
2671
- "directory": {
2672
- "type": "string",
2673
- "description": "Directory to store compile cache. Defaults to .plt/compile-cache in app root"
2674
- }
2675
- },
2676
- "additionalProperties": false
2677
- }
2678
- ]
2679
2624
  }
2680
2625
  },
2681
2626
  "anyOf": [