veryfront 0.1.583 → 0.1.584

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/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.583",
3
+ "version": "0.1.584",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "workspace": [
@@ -1 +1 @@
1
- {"version":3,"file":"production-server.d.ts","sourceRoot":"","sources":["../../../src/src/server/production-server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAInE,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AA4BrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAmFtE,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,aAAa;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sFAAsF;IACtF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uGAAuG;IACvG,kBAAkB,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;IAC9C;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE,oFAAoF;IACpF,eAAe,CAAC,EAAE,gBAAgB,CAAC;IACnC,sFAAsF;IACtF,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED,6CAA6C;AAC7C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,mDAAmD;AACnD,MAAM,WAAW,4BAA6B,SAAQ,aAAa;IACjE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,8FAA8F;IAC9F,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAED,gCAAgC;AAChC,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,YAAY,CAAC,CAkJvB"}
1
+ {"version":3,"file":"production-server.d.ts","sourceRoot":"","sources":["../../../src/src/server/production-server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAInE,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AA2BrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAgFtE,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,aAAa;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sFAAsF;IACtF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uGAAuG;IACvG,kBAAkB,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;IAC9C;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE,oFAAoF;IACpF,eAAe,CAAC,EAAE,gBAAgB,CAAC;IACnC,sFAAsF;IACtF,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED,6CAA6C;AAC7C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,mDAAmD;AACnD,MAAM,WAAW,4BAA6B,SAAQ,aAAa;IACjE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,8FAA8F;IAC9F,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAED,gCAAgC;AAChC,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,YAAY,CAAC,CA0JvB"}
@@ -6,7 +6,7 @@ import { bootstrapProd } from "./bootstrap.js";
6
6
  import { cwd, onGlobalError, onSignal } from "../platform/compat/process.js";
7
7
  import { isDebugEnabled } from "../utils/constants/env.js";
8
8
  import { initializeOTLPWithApis, shutdownOTLP, withSpan, } from "../observability/tracing/otlp-setup.js";
9
- import { getMemorySnapshot, startMemoryMonitoring, stopMemoryMonitoring, } from "../utils/memory/index.js";
9
+ import { startConfiguredMemoryMonitoring, stopMemoryMonitoring, } from "../utils/memory/index.js";
10
10
  import { initializeDistributedCaches } from "../cache/distributed-cache-init.js";
11
11
  import { getConfig } from "../config/index.js";
12
12
  import { resolveStyleContentVersion } from "../html/styles-builder/content-version.js";
@@ -16,8 +16,6 @@ import { setServerInitialized } from "./handlers/monitoring/health.handler.js";
16
16
  import { enableSSRClientOnlyFetching, enableSSRFetchInterception, setSSRServerPort, } from "../rendering/ssr-globals.js";
17
17
  const serverLog = logger.component("server");
18
18
  const globalLog = logger.component("global");
19
- /** Default interval for periodic memory usage snapshots */
20
- const DEFAULT_MEMORY_MONITORING_INTERVAL_MS = 30_000;
21
19
  /** Default time to wait for in-flight requests to drain during shutdown.
22
20
  * K8s default terminationGracePeriodSeconds is 30s, so 25s leaves headroom. */
23
21
  const DEFAULT_SHUTDOWN_DRAIN_TIMEOUT_MS = 25_000;
@@ -82,105 +80,116 @@ export function startProductionServer(options) {
82
80
  return withSpan("server.startProductionServer", async () => {
83
81
  const { projectDir, port, bindAddress = "0.0.0.0", signal, debug, defaultProjectSlug, defaultProjectId, defaultEnvironment, requestInterceptor, bootstrapResult, discoveryConfig, localProjects, } = options;
84
82
  const baseAdapter = options.adapter ?? (await runtime.get());
85
- // Use pre-computed bootstrap result if provided, otherwise bootstrap here
86
- const bootstrap = bootstrapResult ?? await bootstrapProd(projectDir, baseAdapter);
87
- const adapter = bootstrap.adapter;
88
- if (bootstrap.usingFSAdapter) {
89
- logger.debug("FSAdapter initialized", { type: bootstrap.fsAdapterType });
90
- }
91
- await prewarmLocalProductionCSSArtifacts(bootstrap.adapter, {
92
- projectDir,
93
- defaultProjectSlug,
94
- defaultProjectId,
95
- defaultEnvironment,
96
- localProjects,
97
- });
98
- // Enable SSR fetch interception to handle relative URLs during SSR
99
- setSSRServerPort(port);
100
- enableSSRFetchInterception();
101
- // Enable client-only fetching for /api/* routes in production.
102
- // This returns empty mock responses during SSR (instead of failing with
103
- // "Invalid URL" or "Connection refused"). React Query will refetch
104
- // the actual data client-side after hydration.
105
- enableSSRClientOnlyFetching();
106
- // Run primitive discovery before serving (registries must be populated before first request)
107
- if (discoveryConfig) {
108
- try {
109
- const { discoverAll } = await import("../discovery/index.js");
110
- const { isExtendedFSAdapter } = await import("../platform/adapters/fs/wrapper.js");
111
- if (discoveryConfig.projectSlug && discoveryConfig.apiToken &&
112
- discoveryConfig.fsAdapter && isExtendedFSAdapter(discoveryConfig.fsAdapter) &&
113
- discoveryConfig.fsAdapter.isMultiProjectMode()) {
114
- // Multi-project proxy: scope discovery to specific project
115
- await discoveryConfig.fsAdapter.runWithContext(discoveryConfig.projectSlug, discoveryConfig.apiToken, () => discoverAll({
116
- baseDir: discoveryConfig.baseDir,
117
- fsAdapter: discoveryConfig.fsAdapter,
118
- verbose: discoveryConfig.verbose ?? false,
119
- }));
83
+ const memoryMonitoringConfig = startConfiguredMemoryMonitoring(baseAdapter.env);
84
+ const ownsMemoryMonitoring = memoryMonitoringConfig.enabled;
85
+ try {
86
+ // Use pre-computed bootstrap result if provided, otherwise bootstrap here
87
+ const bootstrap = bootstrapResult ?? await bootstrapProd(projectDir, baseAdapter);
88
+ const adapter = bootstrap.adapter;
89
+ if (bootstrap.usingFSAdapter) {
90
+ logger.debug("FSAdapter initialized", { type: bootstrap.fsAdapterType });
91
+ }
92
+ await prewarmLocalProductionCSSArtifacts(bootstrap.adapter, {
93
+ projectDir,
94
+ defaultProjectSlug,
95
+ defaultProjectId,
96
+ defaultEnvironment,
97
+ localProjects,
98
+ });
99
+ // Enable SSR fetch interception to handle relative URLs during SSR
100
+ setSSRServerPort(port);
101
+ enableSSRFetchInterception();
102
+ // Enable client-only fetching for /api/* routes in production.
103
+ // This returns empty mock responses during SSR (instead of failing with
104
+ // "Invalid URL" or "Connection refused"). React Query will refetch
105
+ // the actual data client-side after hydration.
106
+ enableSSRClientOnlyFetching();
107
+ // Run primitive discovery before serving (registries must be populated before first request)
108
+ if (discoveryConfig) {
109
+ try {
110
+ const { discoverAll } = await import("../discovery/index.js");
111
+ const { isExtendedFSAdapter } = await import("../platform/adapters/fs/wrapper.js");
112
+ if (discoveryConfig.projectSlug && discoveryConfig.apiToken &&
113
+ discoveryConfig.fsAdapter && isExtendedFSAdapter(discoveryConfig.fsAdapter) &&
114
+ discoveryConfig.fsAdapter.isMultiProjectMode()) {
115
+ // Multi-project proxy: scope discovery to specific project
116
+ await discoveryConfig.fsAdapter.runWithContext(discoveryConfig.projectSlug, discoveryConfig.apiToken, () => discoverAll({
117
+ baseDir: discoveryConfig.baseDir,
118
+ fsAdapter: discoveryConfig.fsAdapter,
119
+ verbose: discoveryConfig.verbose ?? false,
120
+ }));
121
+ }
122
+ else {
123
+ await discoverAll({
124
+ baseDir: discoveryConfig.baseDir,
125
+ fsAdapter: discoveryConfig.fsAdapter,
126
+ verbose: discoveryConfig.verbose ?? false,
127
+ });
128
+ }
120
129
  }
121
- else {
122
- await discoverAll({
123
- baseDir: discoveryConfig.baseDir,
124
- fsAdapter: discoveryConfig.fsAdapter,
125
- verbose: discoveryConfig.verbose ?? false,
130
+ catch (error) {
131
+ serverLog.error("Primitive discovery failed", {
132
+ error: error instanceof Error ? error.message : String(error),
126
133
  });
127
134
  }
128
135
  }
129
- catch (error) {
130
- serverLog.error("Primitive discovery failed", {
131
- error: error instanceof Error ? error.message : String(error),
132
- });
133
- }
136
+ logger.info("Starting production server", { projectDir, port, bindAddress });
137
+ const baseHandler = createVeryfrontHandler(projectDir, adapter, {
138
+ projectDir,
139
+ debug,
140
+ config: bootstrap.config,
141
+ defaultProjectSlug,
142
+ defaultProjectId,
143
+ defaultEnvironment,
144
+ localProjects,
145
+ });
146
+ // Wrap handler with interceptor if provided (for combined mode)
147
+ // WebSocket upgrade requests MUST NOT be intercepted because the interceptor
148
+ // creates a new Request object, which breaks Deno.upgradeWebSocket()
149
+ const handler = requestInterceptor
150
+ ? Object.assign(async (req) => {
151
+ const isWebSocketUpgrade = req.headers.get("upgrade")?.toLowerCase() === "websocket";
152
+ if (isWebSocketUpgrade)
153
+ return baseHandler(req);
154
+ return baseHandler(await requestInterceptor(req));
155
+ }, { ready: baseHandler.ready })
156
+ : baseHandler;
157
+ let resolveListenReady;
158
+ const listenReady = new Promise((resolve) => {
159
+ resolveListenReady = resolve;
160
+ });
161
+ const ready = (async () => {
162
+ await Promise.all([listenReady, handler.ready ?? Promise.resolve()]);
163
+ // Mark server as initialized when ready resolves
164
+ setServerInitialized(true);
165
+ })();
166
+ const server = await adapter.serve(handler, {
167
+ port,
168
+ hostname: bindAddress, // Deno uses "hostname" for bind address
169
+ signal,
170
+ onListen: (params) => {
171
+ resolveListenReady?.();
172
+ logger.info("Production server listening", params);
173
+ },
174
+ });
175
+ const stop = async () => {
176
+ setServerInitialized(false);
177
+ if (ownsMemoryMonitoring)
178
+ stopMemoryMonitoring();
179
+ try {
180
+ await server.stop();
181
+ }
182
+ catch (error) {
183
+ logger.debug("Server stop failed", { error });
184
+ }
185
+ };
186
+ return { ready, stop };
134
187
  }
135
- logger.info("Starting production server", { projectDir, port, bindAddress });
136
- const baseHandler = createVeryfrontHandler(projectDir, adapter, {
137
- projectDir,
138
- debug,
139
- config: bootstrap.config,
140
- defaultProjectSlug,
141
- defaultProjectId,
142
- defaultEnvironment,
143
- localProjects,
144
- });
145
- // Wrap handler with interceptor if provided (for combined mode)
146
- // WebSocket upgrade requests MUST NOT be intercepted because the interceptor
147
- // creates a new Request object, which breaks Deno.upgradeWebSocket()
148
- const handler = requestInterceptor
149
- ? Object.assign(async (req) => {
150
- const isWebSocketUpgrade = req.headers.get("upgrade")?.toLowerCase() === "websocket";
151
- if (isWebSocketUpgrade)
152
- return baseHandler(req);
153
- return baseHandler(await requestInterceptor(req));
154
- }, { ready: baseHandler.ready })
155
- : baseHandler;
156
- let resolveListenReady;
157
- const listenReady = new Promise((resolve) => {
158
- resolveListenReady = resolve;
159
- });
160
- const ready = (async () => {
161
- await Promise.all([listenReady, handler.ready ?? Promise.resolve()]);
162
- // Mark server as initialized when ready resolves
163
- setServerInitialized(true);
164
- })();
165
- const server = await adapter.serve(handler, {
166
- port,
167
- hostname: bindAddress, // Deno uses "hostname" for bind address
168
- signal,
169
- onListen: (params) => {
170
- resolveListenReady?.();
171
- logger.info("Production server listening", params);
172
- },
173
- });
174
- async function stop() {
175
- setServerInitialized(false);
176
- try {
177
- await server.stop();
178
- }
179
- catch (error) {
180
- logger.debug("Server stop failed", { error });
181
- }
188
+ catch (error) {
189
+ if (ownsMemoryMonitoring)
190
+ stopMemoryMonitoring();
191
+ throw error;
182
192
  }
183
- return { ready, stop };
184
193
  }, { "server.port": options.port, "server.bindAddress": options.bindAddress ?? "0.0.0.0" });
185
194
  }
186
195
  if (globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).main) {
@@ -224,21 +233,6 @@ if (globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).main) {
224
233
  });
225
234
  }
226
235
  const adapter = await runtime.get();
227
- // Start memory monitoring if enabled
228
- const enableMemoryMonitoring = adapter.env.get("ENABLE_MEMORY_MONITORING") === "true";
229
- const monitoringIntervalMs = parseInt(adapter.env.get("MEMORY_MONITORING_INTERVAL_MS") ??
230
- String(DEFAULT_MEMORY_MONITORING_INTERVAL_MS), 10);
231
- if (enableMemoryMonitoring) {
232
- startMemoryMonitoring(monitoringIntervalMs);
233
- logger.debug("Memory monitoring enabled", { intervalMs: monitoringIntervalMs });
234
- // Log initial memory state
235
- const initialSnapshot = getMemorySnapshot();
236
- logger.debug("Initial memory state", {
237
- heapUsedMB: initialSnapshot.heap.usedHeapSizeMB,
238
- heapLimitMB: initialSnapshot.heap.heapSizeLimitMB,
239
- cacheCount: initialSnapshot.caches.length,
240
- });
241
- }
242
236
  const shutdownController = new AbortController();
243
237
  const projectDir = cwd();
244
238
  const port = Number(adapter.env.get("PORT") ?? adapter.env.get("VERYFRONT_PORT") ?? DEFAULT_SERVER_PORT);
@@ -284,7 +278,6 @@ if (globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).main) {
284
278
  });
285
279
  }
286
280
  // Phase 3: Stop accepting new connections and clean up
287
- stopMemoryMonitoring();
288
281
  requestTracker.shutdown();
289
282
  await bootstrap.dispose?.();
290
283
  shutdownController.abort();
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * @module utils/memory
5
5
  */
6
- export { type CacheStats, checkMemoryPressure, clearAllCaches, forceGC, type GCStats, getCacheStats, getHeapStats, getMemoryMonitoringLogContext, getMemorySnapshot, getTopCacheStats, type HeapStats, type MemoryMonitoringLogContext, type MemorySnapshot, type MonitoringCacheStats, registerCache, setHeapWarningThreshold, startMemoryMonitoring, stopMemoryMonitoring, unregisterCache, } from "./profiler.js";
6
+ export { type CacheStats, checkMemoryPressure, clearAllCaches, DEFAULT_MEMORY_MONITORING_INTERVAL_MS, forceGC, type GCStats, getCacheStats, getHeapStats, getMemoryMonitoringConfig, getMemoryMonitoringLogContext, getMemoryMonitoringState, getMemorySnapshot, getTopCacheStats, type HeapStats, type MemoryMonitoringConfig, type MemoryMonitoringEnv, type MemoryMonitoringLogContext, type MemoryMonitoringState, type MemorySnapshot, type MonitoringCacheStats, registerCache, setHeapWarningThreshold, startConfiguredMemoryMonitoring, startMemoryMonitoring, stopMemoryMonitoring, unregisterCache, } from "./profiler.js";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/memory/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,UAAU,EACf,mBAAmB,EACnB,cAAc,EACd,OAAO,EACP,KAAK,OAAO,EACZ,aAAa,EACb,YAAY,EACZ,6BAA6B,EAC7B,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,SAAS,EACd,KAAK,0BAA0B,EAC/B,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,aAAa,EACb,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,GAChB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/memory/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,UAAU,EACf,mBAAmB,EACnB,cAAc,EACd,qCAAqC,EACrC,OAAO,EACP,KAAK,OAAO,EACZ,aAAa,EACb,YAAY,EACZ,yBAAyB,EACzB,6BAA6B,EAC7B,wBAAwB,EACxB,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,SAAS,EACd,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,aAAa,EACb,uBAAuB,EACvB,+BAA+B,EAC/B,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,GAChB,MAAM,eAAe,CAAC"}
@@ -3,4 +3,4 @@
3
3
  *
4
4
  * @module utils/memory
5
5
  */
6
- export { checkMemoryPressure, clearAllCaches, forceGC, getCacheStats, getHeapStats, getMemoryMonitoringLogContext, getMemorySnapshot, getTopCacheStats, registerCache, setHeapWarningThreshold, startMemoryMonitoring, stopMemoryMonitoring, unregisterCache, } from "./profiler.js";
6
+ export { checkMemoryPressure, clearAllCaches, DEFAULT_MEMORY_MONITORING_INTERVAL_MS, forceGC, getCacheStats, getHeapStats, getMemoryMonitoringConfig, getMemoryMonitoringLogContext, getMemoryMonitoringState, getMemorySnapshot, getTopCacheStats, registerCache, setHeapWarningThreshold, startConfiguredMemoryMonitoring, startMemoryMonitoring, stopMemoryMonitoring, unregisterCache, } from "./profiler.js";
@@ -1,3 +1,5 @@
1
+ /** Default interval for periodic memory snapshots (30 seconds) */
2
+ export declare const DEFAULT_MEMORY_MONITORING_INTERVAL_MS = 30000;
1
3
  export interface CacheStats {
2
4
  name: string;
3
5
  entries: number;
@@ -37,6 +39,17 @@ export interface MemoryMonitoringLogContext {
37
39
  totalCacheEntries: number;
38
40
  topCaches: MonitoringCacheStats[];
39
41
  }
42
+ export interface MemoryMonitoringEnv {
43
+ get(key: string): string | null | undefined;
44
+ }
45
+ export interface MemoryMonitoringConfig {
46
+ enabled: boolean;
47
+ intervalMs: number;
48
+ }
49
+ export interface MemoryMonitoringState {
50
+ active: boolean;
51
+ intervalMs: number | undefined;
52
+ }
40
53
  export interface GCStats {
41
54
  majorGCs: number;
42
55
  minorGCs: number;
@@ -49,8 +62,11 @@ export declare function getCacheStats(): CacheStats[];
49
62
  export declare function getMemorySnapshot(): MemorySnapshot;
50
63
  export declare function getTopCacheStats(caches: CacheStats[], limit?: number): MonitoringCacheStats[];
51
64
  export declare function getMemoryMonitoringLogContext(snapshot: MemorySnapshot, topCacheLimit?: number): MemoryMonitoringLogContext;
65
+ export declare function getMemoryMonitoringConfig(env: MemoryMonitoringEnv): MemoryMonitoringConfig;
66
+ export declare function getMemoryMonitoringState(): MemoryMonitoringState;
52
67
  export declare function forceGC(): Promise<boolean>;
53
68
  export declare function startMemoryMonitoring(intervalMs?: number): void;
69
+ export declare function startConfiguredMemoryMonitoring(env: MemoryMonitoringEnv): MemoryMonitoringConfig;
54
70
  export declare function stopMemoryMonitoring(): void;
55
71
  export declare function setHeapWarningThreshold(threshold: number): void;
56
72
  export declare function clearAllCaches(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"profiler.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/memory/profiler.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,oBAAoB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAMD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,UAAU,GAAG,IAAI,CAG5E;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,YAAY,IAAI,SAAS,CAiBxC;AAkBD,wBAAgB,aAAa,IAAI,UAAU,EAAE,CAa5C;AAED,wBAAgB,iBAAiB,IAAI,cAAc,CAWlD;AAcD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,KAAK,SAAI,GAAG,oBAAoB,EAAE,CAMxF;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,cAAc,EACxB,aAAa,SAAI,GAChB,0BAA0B,CAY5B;AAED,wBAAsB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAUhD;AAED,wBAAgB,qBAAqB,CAAC,UAAU,SAAwC,GAAG,IAAI,CAiC9F;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAM3C;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE/D;AAED,wBAAgB,cAAc,IAAI,IAAI,CAMrC;AAwBD,wBAAgB,mBAAmB,IAAI;IACrC,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB,CAiBA;AAED,YAAY,EAAE,cAAc,IAAI,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"profiler.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/memory/profiler.ts"],"names":[],"mappings":"AAiBA,kEAAkE;AAClE,eAAO,MAAM,qCAAqC,QAAS,CAAC;AAO5D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,oBAAoB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CAC7C;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAOD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,UAAU,GAAG,IAAI,CAG5E;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,YAAY,IAAI,SAAS,CAiBxC;AAkBD,wBAAgB,aAAa,IAAI,UAAU,EAAE,CAa5C;AAED,wBAAgB,iBAAiB,IAAI,cAAc,CAWlD;AAcD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,KAAK,SAAI,GAAG,oBAAoB,EAAE,CAMxF;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,cAAc,EACxB,aAAa,SAAI,GAChB,0BAA0B,CAY5B;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,mBAAmB,GAAG,sBAAsB,CAY1F;AAED,wBAAgB,wBAAwB,IAAI,qBAAqB,CAKhE;AAED,wBAAsB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAUhD;AAED,wBAAgB,qBAAqB,CAAC,UAAU,SAAwC,GAAG,IAAI,CAkC9F;AAED,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,mBAAmB,GAAG,sBAAsB,CAehG;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAO3C;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE/D;AAED,wBAAgB,cAAc,IAAI,IAAI,CAMrC;AAwBD,wBAAgB,mBAAmB,IAAI;IACrC,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB,CAiBA;AAED,YAAY,EAAE,cAAc,IAAI,kBAAkB,EAAE,CAAC"}
@@ -11,11 +11,12 @@ const logger = rendererLogger.component("memory-profiler");
11
11
  /** Fallback V8 heap limit when no --max-old-space-size flag is set (5 GB) */
12
12
  const DEFAULT_HEAP_LIMIT_MB = 5_120;
13
13
  /** Default interval for periodic memory snapshots (30 seconds) */
14
- const DEFAULT_MEMORY_MONITORING_INTERVAL_MS = 30_000;
14
+ export const DEFAULT_MEMORY_MONITORING_INTERVAL_MS = 30_000;
15
15
  /** Heap growth (MB) per interval that triggers a rapid-growth warning */
16
16
  const HEAP_RAPID_GROWTH_THRESHOLD_MB = 100;
17
17
  const cacheRegistry = new Map();
18
18
  let memoryCheckInterval;
19
+ let memoryCheckIntervalMs;
19
20
  let lastHeapUsed = 0;
20
21
  let heapGrowthWarningThreshold = 0.8;
21
22
  export function registerCache(name, getStats) {
@@ -109,6 +110,21 @@ export function getMemoryMonitoringLogContext(snapshot, topCacheLimit = 8) {
109
110
  topCaches: getTopCacheStats(snapshot.caches, topCacheLimit),
110
111
  };
111
112
  }
113
+ export function getMemoryMonitoringConfig(env) {
114
+ const enabled = env.get("ENABLE_MEMORY_MONITORING") === "true";
115
+ const rawInterval = env.get("MEMORY_MONITORING_INTERVAL_MS");
116
+ const parsedInterval = parseInt(rawInterval ?? String(DEFAULT_MEMORY_MONITORING_INTERVAL_MS), 10);
117
+ const intervalMs = Number.isFinite(parsedInterval) && parsedInterval > 0
118
+ ? parsedInterval
119
+ : DEFAULT_MEMORY_MONITORING_INTERVAL_MS;
120
+ return { enabled, intervalMs };
121
+ }
122
+ export function getMemoryMonitoringState() {
123
+ return {
124
+ active: memoryCheckInterval !== undefined,
125
+ intervalMs: memoryCheckIntervalMs,
126
+ };
127
+ }
112
128
  export async function forceGC() {
113
129
  try {
114
130
  const buffer = new Uint8Array(100 * 1024 * 1024);
@@ -125,6 +141,7 @@ export function startMemoryMonitoring(intervalMs = DEFAULT_MEMORY_MONITORING_INT
125
141
  if (memoryCheckInterval)
126
142
  clearInterval(memoryCheckInterval);
127
143
  logger.info(`Starting memory monitoring (interval: ${intervalMs}ms)`);
144
+ memoryCheckIntervalMs = intervalMs;
128
145
  memoryCheckInterval = dntShim.setInterval(() => {
129
146
  const snapshot = getMemorySnapshot();
130
147
  const { heap } = snapshot;
@@ -150,11 +167,26 @@ export function startMemoryMonitoring(intervalMs = DEFAULT_MEMORY_MONITORING_INT
150
167
  lastHeapUsed = heap.usedHeapSizeMB;
151
168
  }, intervalMs);
152
169
  }
170
+ export function startConfiguredMemoryMonitoring(env) {
171
+ const config = getMemoryMonitoringConfig(env);
172
+ if (!config.enabled)
173
+ return config;
174
+ startMemoryMonitoring(config.intervalMs);
175
+ logger.info("Memory monitoring enabled", { intervalMs: config.intervalMs });
176
+ const initialSnapshot = getMemorySnapshot();
177
+ logger.info("Initial memory state", {
178
+ heapUsedMB: initialSnapshot.heap.usedHeapSizeMB,
179
+ heapLimitMB: initialSnapshot.heap.heapSizeLimitMB,
180
+ cacheCount: initialSnapshot.caches.length,
181
+ });
182
+ return config;
183
+ }
153
184
  export function stopMemoryMonitoring() {
154
185
  if (!memoryCheckInterval)
155
186
  return;
156
187
  clearInterval(memoryCheckInterval);
157
188
  memoryCheckInterval = undefined;
189
+ memoryCheckIntervalMs = undefined;
158
190
  logger.info("Memory monitoring stopped");
159
191
  }
160
192
  export function setHeapWarningThreshold(threshold) {
@@ -1,3 +1,3 @@
1
1
  /** Shared version value. */
2
- export declare const VERSION = "0.1.583";
2
+ export declare const VERSION = "0.1.584";
3
3
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,4 +1,4 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
3
  /** Shared version value. */
4
- export const VERSION = "0.1.583";
4
+ export const VERSION = "0.1.584";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.583",
3
+ "version": "0.1.584",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",