@platformatic/runtime 3.32.0-alpha.0 → 3.32.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,7 +42,6 @@ export type PlatformaticRuntimeConfig = {
42
42
  maxHeapTotal?: number | string;
43
43
  maxYoungGeneration?: number | string;
44
44
  codeRangeSize?: number | string;
45
- noHeapCheck?: boolean | string;
46
45
  };
47
46
  dependencies?: string[];
48
47
  arguments?: string[];
@@ -79,6 +78,18 @@ export type PlatformaticRuntimeConfig = {
79
78
  )[];
80
79
  [k: string]: unknown;
81
80
  };
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
+ };
82
93
  };
83
94
  };
84
95
  };
@@ -109,7 +120,7 @@ export type PlatformaticRuntimeConfig = {
109
120
  };
110
121
  workersRestartDelay?: number | string;
111
122
  logger?: {
112
- level: (
123
+ level?: (
113
124
  | ("fatal" | "error" | "warn" | "info" | "debug" | "trace" | "silent")
114
125
  | {
115
126
  [k: string]: unknown;
@@ -213,7 +224,6 @@ export type PlatformaticRuntimeConfig = {
213
224
  maxHeapTotal?: number | string;
214
225
  maxYoungGeneration?: number | string;
215
226
  codeRangeSize?: number | string;
216
- noHeapCheck?: boolean | string;
217
227
  };
218
228
  undici?: {
219
229
  agentOptions?: {
@@ -265,6 +275,18 @@ export type PlatformaticRuntimeConfig = {
265
275
  maxSize?: number;
266
276
  maxEntrySize?: number;
267
277
  maxCount?: number;
278
+ /**
279
+ * Whitelist of origins to cache. Supports exact strings and regex patterns (e.g., "/https:\\/\\/.*\\.example\\.com/").
280
+ */
281
+ origins?: string[];
282
+ /**
283
+ * Default cache duration in seconds for responses without explicit expiration headers.
284
+ */
285
+ cacheByDefault?: number;
286
+ /**
287
+ * Cache type. "shared" caches may be shared between users, "private" caches are user-specific.
288
+ */
289
+ type?: "shared" | "private";
268
290
  [k: string]: unknown;
269
291
  };
270
292
  watch?: boolean | string;
@@ -503,4 +525,16 @@ export type PlatformaticRuntimeConfig = {
503
525
  [k: string]: string | [string, ...string[]];
504
526
  };
505
527
  };
528
+ compileCache?:
529
+ | boolean
530
+ | {
531
+ /**
532
+ * Enable Node.js module compile cache for faster startup
533
+ */
534
+ enabled?: boolean;
535
+ /**
536
+ * Directory to store compile cache. Defaults to .plt/compile-cache in app root
537
+ */
538
+ directory?: string;
539
+ };
506
540
  };
package/lib/runtime.js CHANGED
@@ -10,6 +10,7 @@ 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'
13
14
  import fastify from 'fastify'
14
15
  import { EventEmitter, once } from 'node:events'
15
16
  import { existsSync } from 'node:fs'
@@ -68,9 +69,26 @@ import {
68
69
 
69
70
  const kWorkerFile = join(import.meta.dirname, 'worker/main.js')
70
71
  const kInspectorOptions = Symbol('plt.runtime.worker.inspectorOptions')
72
+ const kHeapCheckCounter = Symbol('plt.runtime.worker.heapCheckCounter')
73
+ const kLastHeapStats = Symbol('plt.runtime.worker.lastHeapStats')
71
74
 
72
75
  const MAX_LISTENERS_COUNT = 100
73
76
 
77
+ function parseOrigins (origins) {
78
+ if (!origins) return undefined
79
+
80
+ return origins.map(origin => {
81
+ // Check if the origin is a regex pattern (starts and ends with /)
82
+ if (origin.startsWith('/') && origin.lastIndexOf('/') > 0) {
83
+ const lastSlash = origin.lastIndexOf('/')
84
+ const pattern = origin.slice(1, lastSlash)
85
+ const flags = origin.slice(lastSlash + 1)
86
+ return new RegExp(pattern, flags)
87
+ }
88
+ return origin
89
+ })
90
+ }
91
+
74
92
  const MAX_CONCURRENCY = 5
75
93
  const MAX_BOOTSTRAP_ATTEMPTS = 5
76
94
  const IMMEDIATE_RESTART_MAX_THRESHOLD = 10
@@ -119,6 +137,8 @@ export class Runtime extends EventEmitter {
119
137
 
120
138
  #channelCreationHook
121
139
 
140
+ #processMetricsRegistry
141
+
122
142
  constructor (config, context) {
123
143
  super()
124
144
  this.setMaxListeners(MAX_LISTENERS_COUNT)
@@ -197,6 +217,14 @@ export class Runtime extends EventEmitter {
197
217
  this.#metricsLabelName = 'applicationId'
198
218
  }
199
219
 
220
+ // Initialize process-level metrics registry in the main thread if metrics or management API is enabled
221
+ // These metrics are the same across all workers and only need to be collected once
222
+ // We need this for management API as it can request metrics even without explicit metrics config
223
+ if (config.metrics || config.managementApi) {
224
+ this.#processMetricsRegistry = new metricsClient.Registry()
225
+ collectProcessMetrics(this.#processMetricsRegistry)
226
+ }
227
+
200
228
  // Create the logger
201
229
  const [logger, destination, context] = await createLogger(config)
202
230
  this.logger = logger
@@ -346,6 +374,12 @@ export class Runtime extends EventEmitter {
346
374
  await this.#prometheusServer.close()
347
375
  }
348
376
 
377
+ // Clean up process metrics registry
378
+ if (this.#processMetricsRegistry) {
379
+ this.#processMetricsRegistry.clear()
380
+ this.#processMetricsRegistry = null
381
+ }
382
+
349
383
  if (this.#sharedHttpCache?.close) {
350
384
  await this.#sharedHttpCache.close()
351
385
  }
@@ -1059,6 +1093,12 @@ export class Runtime extends EventEmitter {
1059
1093
  async getMetrics (format = 'json') {
1060
1094
  let metrics = null
1061
1095
 
1096
+ // Get process-level metrics once from main thread registry (if available)
1097
+ let processMetricsJson = null
1098
+ if (this.#processMetricsRegistry) {
1099
+ processMetricsJson = await this.#processMetricsRegistry.getMetricsAsJSON()
1100
+ }
1101
+
1062
1102
  for (const worker of this.#workers.values()) {
1063
1103
  try {
1064
1104
  // The application might be temporarily unavailable
@@ -1066,6 +1106,7 @@ export class Runtime extends EventEmitter {
1066
1106
  continue
1067
1107
  }
1068
1108
 
1109
+ // Get thread-specific metrics from worker
1069
1110
  const applicationMetrics = await executeWithTimeout(
1070
1111
  sendViaITC(worker, 'getMetrics', format),
1071
1112
  this.#config.metrics?.timeout ?? 10000
@@ -1076,9 +1117,30 @@ export class Runtime extends EventEmitter {
1076
1117
  metrics = format === 'json' ? [] : ''
1077
1118
  }
1078
1119
 
1120
+ // Build worker labels including custom labels from metrics config
1121
+ const workerLabels = {
1122
+ ...this.#config.metrics?.labels,
1123
+ [this.#metricsLabelName]: worker[kApplicationId]
1124
+ }
1125
+ const workerId = worker[kWorkerId]
1126
+ if (workerId >= 0) {
1127
+ workerLabels.workerId = workerId
1128
+ }
1129
+
1079
1130
  if (format === 'json') {
1080
- metrics.push(...applicationMetrics)
1131
+ // Duplicate process metrics with worker labels and add to output
1132
+ if (processMetricsJson) {
1133
+ this.#applyLabelsToMetrics(processMetricsJson, workerLabels, metrics)
1134
+ }
1135
+ // Add worker's thread-specific metrics
1136
+ for (let i = 0; i < applicationMetrics.length; i++) {
1137
+ metrics.push(applicationMetrics[i])
1138
+ }
1081
1139
  } else {
1140
+ // Text format: format process metrics with worker labels
1141
+ if (processMetricsJson) {
1142
+ metrics += this.#formatProcessMetricsText(processMetricsJson, workerLabels)
1143
+ }
1082
1144
  metrics += applicationMetrics
1083
1145
  }
1084
1146
  }
@@ -1099,6 +1161,65 @@ export class Runtime extends EventEmitter {
1099
1161
  return { metrics }
1100
1162
  }
1101
1163
 
1164
+ // Apply labels to process metrics and push to output array (for JSON format)
1165
+ #applyLabelsToMetrics (processMetrics, labels, outputArray) {
1166
+ for (let i = 0; i < processMetrics.length; i++) {
1167
+ const metric = processMetrics[i]
1168
+ const newValues = []
1169
+ const values = metric.values
1170
+ for (let j = 0; j < values.length; j++) {
1171
+ const v = values[j]
1172
+ newValues.push({
1173
+ value: v.value,
1174
+ labels: { ...labels, ...v.labels },
1175
+ metricName: v.metricName
1176
+ })
1177
+ }
1178
+ outputArray.push({
1179
+ name: metric.name,
1180
+ help: metric.help,
1181
+ type: metric.type,
1182
+ aggregator: metric.aggregator,
1183
+ values: newValues
1184
+ })
1185
+ }
1186
+ }
1187
+
1188
+ // Format process metrics as Prometheus text format with labels
1189
+ #formatProcessMetricsText (processMetricsJson, labels) {
1190
+ let output = ''
1191
+
1192
+ for (let i = 0; i < processMetricsJson.length; i++) {
1193
+ const metric = processMetricsJson[i]
1194
+ const name = metric.name
1195
+ const help = metric.help
1196
+ const type = metric.type
1197
+
1198
+ // Add HELP and TYPE lines
1199
+ output += `# HELP ${name} ${help}\n`
1200
+ output += `# TYPE ${name} ${type}\n`
1201
+
1202
+ const values = metric.values
1203
+ for (let j = 0; j < values.length; j++) {
1204
+ const v = values[j]
1205
+ const combinedLabels = { ...labels, ...v.labels }
1206
+ const labelParts = []
1207
+
1208
+ for (const [key, val] of Object.entries(combinedLabels)) {
1209
+ // Escape label values for Prometheus format
1210
+ const escapedVal = String(val).replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n')
1211
+ labelParts.push(`${key}="${escapedVal}"`)
1212
+ }
1213
+
1214
+ const labelStr = labelParts.length > 0 ? `{${labelParts.join(',')}}` : ''
1215
+ const metricName = v.metricName || name
1216
+ output += `${metricName}${labelStr} ${v.value}\n`
1217
+ }
1218
+ }
1219
+
1220
+ return output
1221
+ }
1222
+
1102
1223
  async getFormattedMetrics () {
1103
1224
  try {
1104
1225
  const { metrics } = await this.getMetrics()
@@ -1349,11 +1470,20 @@ export class Runtime extends EventEmitter {
1349
1470
  elu = worker.performance.eventLoopUtilization(elu, previousELU)
1350
1471
  }
1351
1472
 
1352
- if (!features.node.worker.getHeapStatistics || options.noHeapCheck) {
1473
+ if (!features.node.worker.getHeapStatistics) {
1353
1474
  return { elu: elu.utilization, currentELU }
1354
1475
  }
1355
1476
 
1356
- const { used_heap_size: heapUsed, total_heap_size: heapTotal } = await worker.getHeapStatistics()
1477
+ // Only check heap statistics every 60 health checks (once per minute)
1478
+ const counter = (worker[kHeapCheckCounter] ?? 0) + 1
1479
+ worker[kHeapCheckCounter] = counter >= 60 ? 0 : counter
1480
+
1481
+ if (counter >= 60 || !worker[kLastHeapStats]) {
1482
+ const { used_heap_size: heapUsed, total_heap_size: heapTotal } = await worker.getHeapStatistics()
1483
+ worker[kLastHeapStats] = { heapUsed, heapTotal }
1484
+ }
1485
+
1486
+ const { heapUsed, heapTotal } = worker[kLastHeapStats]
1357
1487
  return { elu: elu.utilization, heapUsed, heapTotal, currentELU }
1358
1488
  }
1359
1489
 
@@ -1396,7 +1526,10 @@ export class Runtime extends EventEmitter {
1396
1526
  interceptors.push(
1397
1527
  undiciInterceptors.cache({
1398
1528
  store: this.#sharedHttpCache,
1399
- methods: config.httpCache.methods ?? ['GET', 'HEAD']
1529
+ methods: config.httpCache.methods ?? ['GET', 'HEAD'],
1530
+ origins: parseOrigins(config.httpCache.origins),
1531
+ cacheByDefault: config.httpCache.cacheByDefault,
1532
+ type: config.httpCache.type
1400
1533
  })
1401
1534
  )
1402
1535
  }
@@ -1564,7 +1697,8 @@ export class Runtime extends EventEmitter {
1564
1697
  codeRangeSizeMb
1565
1698
  },
1566
1699
  stdout: true,
1567
- stderr: true
1700
+ stderr: true,
1701
+ name: workerId
1568
1702
  })
1569
1703
 
1570
1704
  this.#handleWorkerStandardStreams(worker, applicationId, index)
@@ -1753,8 +1887,7 @@ export class Runtime extends EventEmitter {
1753
1887
  let health = null
1754
1888
  try {
1755
1889
  health = await this.getWorkerHealth(worker, {
1756
- previousELU: worker[kLastHealthCheckELU],
1757
- noHeapCheck: worker[kConfig]?.health?.noHeapCheck
1890
+ previousELU: worker[kLastHealthCheckELU]
1758
1891
  })
1759
1892
  } catch (err) {
1760
1893
  this.logger.error({ err }, `Failed to get health for ${errorLabel}.`)
@@ -1798,7 +1931,7 @@ export class Runtime extends EventEmitter {
1798
1931
 
1799
1932
  const healthConfig = worker[kConfig].health
1800
1933
 
1801
- let { maxELU, maxHeapUsed, maxHeapTotal, maxUnhealthyChecks, interval, noHeapCheck } = worker[kConfig].health
1934
+ let { maxELU, maxHeapUsed, maxHeapTotal, maxUnhealthyChecks, interval } = worker[kConfig].health
1802
1935
 
1803
1936
  if (typeof maxHeapTotal === 'string') {
1804
1937
  maxHeapTotal = parseMemorySize(maxHeapTotal)
@@ -1829,8 +1962,8 @@ export class Runtime extends EventEmitter {
1829
1962
 
1830
1963
  if (lastHealthMetrics) {
1831
1964
  const health = lastHealthMetrics.currentHealth
1832
- const memoryUsage = noHeapCheck ? 0 : health.heapUsed / maxHeapTotal
1833
- const unhealthy = health.elu > maxELU || (!noHeapCheck && memoryUsage > maxHeapUsed)
1965
+ const memoryUsage = health.heapUsed / maxHeapTotal
1966
+ const unhealthy = health.elu > maxELU || memoryUsage > maxHeapUsed
1834
1967
 
1835
1968
  this.emit('application:worker:health', {
1836
1969
  id: worker[kId],
@@ -1848,7 +1981,7 @@ export class Runtime extends EventEmitter {
1848
1981
  )
1849
1982
  }
1850
1983
 
1851
- if (!noHeapCheck && memoryUsage > maxHeapUsed) {
1984
+ if (memoryUsage > maxHeapUsed) {
1852
1985
  this.logger.error(
1853
1986
  `The ${errorLabel} is using ${(memoryUsage * 100).toFixed(2)} % of the memory, ` +
1854
1987
  `above the maximum allowed usage of ${(maxHeapUsed * 100).toFixed(2)} %.`
@@ -178,7 +178,23 @@ function createThreadInterceptor (runtimeConfig) {
178
178
  return threadDispatcher
179
179
  }
180
180
 
181
+ function parseOrigins (origins) {
182
+ if (!origins) return undefined
183
+
184
+ return origins.map(origin => {
185
+ // Check if the origin is a regex pattern (starts and ends with /)
186
+ if (origin.startsWith('/') && origin.lastIndexOf('/') > 0) {
187
+ const lastSlash = origin.lastIndexOf('/')
188
+ const pattern = origin.slice(1, lastSlash)
189
+ const flags = origin.slice(lastSlash + 1)
190
+ return new RegExp(pattern, flags)
191
+ }
192
+ return origin
193
+ })
194
+ }
195
+
181
196
  function createHttpCacheInterceptor (runtimeConfig) {
197
+ const httpCache = runtimeConfig.httpCache
182
198
  const cacheInterceptor = httpCacheInterceptor({
183
199
  store: new RemoteCacheStore({
184
200
  onRequest: opts => {
@@ -192,7 +208,10 @@ function createHttpCacheInterceptor (runtimeConfig) {
192
208
  },
193
209
  logger: globalThis.platformatic.logger
194
210
  }),
195
- methods: runtimeConfig.httpCache.methods ?? ['GET', 'HEAD'],
211
+ methods: httpCache.methods ?? ['GET', 'HEAD'],
212
+ origins: parseOrigins(httpCache.origins),
213
+ cacheByDefault: httpCache.cacheByDefault,
214
+ type: httpCache.type,
196
215
  logger: globalThis.platformatic.logger
197
216
  })
198
217
  return cacheInterceptor
@@ -9,11 +9,11 @@ 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 { resolve } from 'node:path'
12
+ import { join, 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'
16
- import { fetch } from 'undici'
16
+ import { install as installUndiciGlobals } from 'undici'
17
17
  import { Controller } from './controller.js'
18
18
  import { setDispatcher } from './interceptors.js'
19
19
  import { setupITC } from './itc.js'
@@ -85,8 +85,59 @@ 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
+
88
139
  async function main () {
89
- globalThis.fetch = fetch
140
+ installUndiciGlobals(globalThis)
90
141
  globalThis[kId] = threadId
91
142
  globalThis.platformatic = Object.assign(globalThis.platformatic ?? {}, {
92
143
  logger: createLogger(),
@@ -94,10 +145,12 @@ async function main () {
94
145
  })
95
146
 
96
147
  const runtimeConfig = workerData.config
148
+ const applicationConfig = workerData.applicationConfig
97
149
 
98
- await performPreloading(runtimeConfig, workerData.applicationConfig)
150
+ // Enable compile cache early before loading user modules
151
+ await setupCompileCache(runtimeConfig, applicationConfig, globalThis.platformatic.logger)
99
152
 
100
- const applicationConfig = workerData.applicationConfig
153
+ await performPreloading(runtimeConfig, applicationConfig)
101
154
 
102
155
  // Load env file and mixin env vars from application config
103
156
  let envfile
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "3.32.0-alpha.0",
3
+ "version": "3.32.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.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"
38
+ "@platformatic/composer": "3.32.0",
39
+ "@platformatic/db": "3.32.0",
40
+ "@platformatic/gateway": "3.32.0",
41
+ "@platformatic/node": "3.32.0",
42
+ "@platformatic/sql-graphql": "3.32.0",
43
+ "@platformatic/service": "3.32.0",
44
+ "@platformatic/sql-mapper": "3.32.0",
45
+ "@platformatic/wattpm-pprof-capture": "3.32.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/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"
74
+ "@platformatic/basic": "3.32.0",
75
+ "@platformatic/foundation": "3.32.0",
76
+ "@platformatic/generators": "3.32.0",
77
+ "@platformatic/itc": "3.32.0",
78
+ "@platformatic/metrics": "3.32.0",
79
+ "@platformatic/telemetry": "3.32.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.32.0-alpha.0.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.32.0.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "title": "Platformatic Runtime Config",
5
5
  "type": "object",
@@ -208,16 +208,6 @@
208
208
  "type": "string"
209
209
  }
210
210
  ]
211
- },
212
- "noHeapCheck": {
213
- "anyOf": [
214
- {
215
- "type": "boolean"
216
- },
217
- {
218
- "type": "string"
219
- }
220
- ]
221
211
  }
222
212
  },
223
213
  "additionalProperties": false
@@ -342,6 +332,28 @@
342
332
  }
343
333
  }
344
334
  }
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
+ ]
345
357
  }
346
358
  }
347
359
  }
@@ -532,16 +544,6 @@
532
544
  "type": "string"
533
545
  }
534
546
  ]
535
- },
536
- "noHeapCheck": {
537
- "anyOf": [
538
- {
539
- "type": "boolean"
540
- },
541
- {
542
- "type": "string"
543
- }
544
- ]
545
547
  }
546
548
  },
547
549
  "additionalProperties": false
@@ -666,6 +668,28 @@
666
668
  }
667
669
  }
668
670
  }
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
+ ]
669
693
  }
670
694
  }
671
695
  }
@@ -854,16 +878,6 @@
854
878
  "type": "string"
855
879
  }
856
880
  ]
857
- },
858
- "noHeapCheck": {
859
- "anyOf": [
860
- {
861
- "type": "boolean"
862
- },
863
- {
864
- "type": "string"
865
- }
866
- ]
867
881
  }
868
882
  },
869
883
  "additionalProperties": false
@@ -988,6 +1002,28 @@
988
1002
  }
989
1003
  }
990
1004
  }
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
+ ]
991
1027
  }
992
1028
  }
993
1029
  }
@@ -1176,16 +1212,6 @@
1176
1212
  "type": "string"
1177
1213
  }
1178
1214
  ]
1179
- },
1180
- "noHeapCheck": {
1181
- "anyOf": [
1182
- {
1183
- "type": "boolean"
1184
- },
1185
- {
1186
- "type": "string"
1187
- }
1188
- ]
1189
1215
  }
1190
1216
  },
1191
1217
  "additionalProperties": false
@@ -1310,6 +1336,28 @@
1310
1336
  }
1311
1337
  }
1312
1338
  }
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
+ ]
1313
1361
  }
1314
1362
  }
1315
1363
  }
@@ -1389,7 +1437,6 @@
1389
1437
  "properties": {
1390
1438
  "level": {
1391
1439
  "type": "string",
1392
- "default": "info",
1393
1440
  "oneOf": [
1394
1441
  {
1395
1442
  "enum": [
@@ -1536,9 +1583,6 @@
1536
1583
  "default": true
1537
1584
  }
1538
1585
  },
1539
- "required": [
1540
- "level"
1541
- ],
1542
1586
  "default": {},
1543
1587
  "additionalProperties": true
1544
1588
  },
@@ -1834,17 +1878,6 @@
1834
1878
  }
1835
1879
  ],
1836
1880
  "default": 268435456
1837
- },
1838
- "noHeapCheck": {
1839
- "anyOf": [
1840
- {
1841
- "type": "boolean"
1842
- },
1843
- {
1844
- "type": "string"
1845
- }
1846
- ],
1847
- "default": false
1848
1881
  }
1849
1882
  },
1850
1883
  "additionalProperties": false
@@ -1976,6 +2009,26 @@
1976
2009
  },
1977
2010
  "maxCount": {
1978
2011
  "type": "integer"
2012
+ },
2013
+ "origins": {
2014
+ "type": "array",
2015
+ "items": {
2016
+ "type": "string"
2017
+ },
2018
+ "description": "Whitelist of origins to cache. Supports exact strings and regex patterns (e.g., \"/https:\\\\/\\\\/.*\\\\.example\\\\.com/\")."
2019
+ },
2020
+ "cacheByDefault": {
2021
+ "type": "integer",
2022
+ "description": "Default cache duration in seconds for responses without explicit expiration headers."
2023
+ },
2024
+ "type": {
2025
+ "type": "string",
2026
+ "enum": [
2027
+ "shared",
2028
+ "private"
2029
+ ],
2030
+ "default": "shared",
2031
+ "description": "Cache type. \"shared\" caches may be shared between users, \"private\" caches are user-specific."
1979
2032
  }
1980
2033
  }
1981
2034
  }
@@ -2621,6 +2674,28 @@
2621
2674
  "deny"
2622
2675
  ],
2623
2676
  "additionalProperties": false
2677
+ },
2678
+ "compileCache": {
2679
+ "anyOf": [
2680
+ {
2681
+ "type": "boolean"
2682
+ },
2683
+ {
2684
+ "type": "object",
2685
+ "properties": {
2686
+ "enabled": {
2687
+ "type": "boolean",
2688
+ "default": true,
2689
+ "description": "Enable Node.js module compile cache for faster startup"
2690
+ },
2691
+ "directory": {
2692
+ "type": "string",
2693
+ "description": "Directory to store compile cache. Defaults to .plt/compile-cache in app root"
2694
+ }
2695
+ },
2696
+ "additionalProperties": false
2697
+ }
2698
+ ]
2624
2699
  }
2625
2700
  },
2626
2701
  "anyOf": [