veryfront 0.1.73 → 0.1.75

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.
Files changed (120) hide show
  1. package/esm/cli/commands/knowledge/command-help.d.ts.map +1 -1
  2. package/esm/cli/commands/knowledge/command-help.js +3 -1
  3. package/esm/cli/commands/knowledge/command.d.ts +34 -5
  4. package/esm/cli/commands/knowledge/command.d.ts.map +1 -1
  5. package/esm/cli/commands/knowledge/command.js +151 -22
  6. package/esm/cli/commands/knowledge/parser-source.d.ts.map +1 -1
  7. package/esm/cli/commands/knowledge/parser-source.js +110 -5
  8. package/esm/deno.d.ts +2 -0
  9. package/esm/deno.js +3 -1
  10. package/esm/src/data/data-fetcher.d.ts +11 -1
  11. package/esm/src/data/data-fetcher.d.ts.map +1 -1
  12. package/esm/src/data/data-fetcher.js +5 -2
  13. package/esm/src/data/index.d.ts +1 -1
  14. package/esm/src/data/index.d.ts.map +1 -1
  15. package/esm/src/data/server-data-fetcher.d.ts +14 -1
  16. package/esm/src/data/server-data-fetcher.d.ts.map +1 -1
  17. package/esm/src/data/server-data-fetcher.js +49 -3
  18. package/esm/src/rendering/orchestrator/lifecycle.d.ts +4 -0
  19. package/esm/src/rendering/orchestrator/lifecycle.d.ts.map +1 -1
  20. package/esm/src/rendering/orchestrator/lifecycle.js +8 -0
  21. package/esm/src/rendering/orchestrator/pipeline.d.ts.map +1 -1
  22. package/esm/src/rendering/orchestrator/pipeline.js +6 -1
  23. package/esm/src/rendering/orchestrator/ssr-orchestrator.d.ts +26 -1
  24. package/esm/src/rendering/orchestrator/ssr-orchestrator.d.ts.map +1 -1
  25. package/esm/src/rendering/orchestrator/ssr-orchestrator.js +77 -1
  26. package/esm/src/routing/api/handler.d.ts.map +1 -1
  27. package/esm/src/routing/api/handler.js +6 -2
  28. package/esm/src/routing/api/route-executor.d.ts +8 -2
  29. package/esm/src/routing/api/route-executor.d.ts.map +1 -1
  30. package/esm/src/routing/api/route-executor.js +131 -3
  31. package/esm/src/security/deno-permissions.d.ts +6 -0
  32. package/esm/src/security/deno-permissions.d.ts.map +1 -1
  33. package/esm/src/security/deno-permissions.js +10 -0
  34. package/esm/src/security/sandbox/project-worker.d.ts +61 -0
  35. package/esm/src/security/sandbox/project-worker.d.ts.map +1 -0
  36. package/esm/src/security/sandbox/project-worker.js +318 -0
  37. package/esm/src/security/sandbox/worker-permissions.d.ts +30 -0
  38. package/esm/src/security/sandbox/worker-permissions.d.ts.map +1 -0
  39. package/esm/src/security/sandbox/worker-permissions.js +60 -0
  40. package/esm/src/security/sandbox/worker-pool.d.ts +87 -0
  41. package/esm/src/security/sandbox/worker-pool.d.ts.map +1 -0
  42. package/esm/src/security/sandbox/worker-pool.js +356 -0
  43. package/esm/src/security/sandbox/worker-types.d.ts +165 -0
  44. package/esm/src/security/sandbox/worker-types.d.ts.map +1 -0
  45. package/esm/src/security/sandbox/worker-types.js +17 -0
  46. package/esm/src/server/handlers/request/ssr/ssr.handler.d.ts +2 -0
  47. package/esm/src/server/handlers/request/ssr/ssr.handler.d.ts.map +1 -1
  48. package/esm/src/server/handlers/request/ssr/ssr.handler.js +6 -2
  49. package/esm/src/server/project-env/storage.d.ts +6 -0
  50. package/esm/src/server/project-env/storage.d.ts.map +1 -1
  51. package/esm/src/server/project-env/storage.js +8 -0
  52. package/esm/src/server/runtime-handler/adapter-factory.d.ts +3 -0
  53. package/esm/src/server/runtime-handler/adapter-factory.d.ts.map +1 -1
  54. package/esm/src/server/runtime-handler/adapter-factory.js +6 -5
  55. package/esm/src/server/runtime-handler/index.d.ts +33 -0
  56. package/esm/src/server/runtime-handler/index.d.ts.map +1 -1
  57. package/esm/src/server/runtime-handler/index.js +103 -37
  58. package/esm/src/server/runtime-handler/local-project-discovery.d.ts +32 -4
  59. package/esm/src/server/runtime-handler/local-project-discovery.d.ts.map +1 -1
  60. package/esm/src/server/runtime-handler/local-project-discovery.js +46 -16
  61. package/esm/src/server/runtime-handler/project-isolation.d.ts +5 -0
  62. package/esm/src/server/runtime-handler/project-isolation.d.ts.map +1 -1
  63. package/esm/src/server/runtime-handler/project-isolation.js +44 -0
  64. package/esm/src/server/services/rendering/ssr.service.d.ts +19 -1
  65. package/esm/src/server/services/rendering/ssr.service.d.ts.map +1 -1
  66. package/esm/src/server/services/rendering/ssr.service.js +9 -1
  67. package/esm/src/server/shared/renderer/adapter.d.ts +25 -0
  68. package/esm/src/server/shared/renderer/adapter.d.ts.map +1 -1
  69. package/esm/src/server/shared/renderer/adapter.js +83 -10
  70. package/esm/src/server/shared/renderer/index.d.ts +1 -1
  71. package/esm/src/server/shared/renderer/index.d.ts.map +1 -1
  72. package/esm/src/server/shared/renderer/index.js +1 -1
  73. package/esm/src/server/shared/renderer/memory/pressure.d.ts +7 -0
  74. package/esm/src/server/shared/renderer/memory/pressure.d.ts.map +1 -1
  75. package/esm/src/server/shared/renderer/memory/pressure.js +7 -0
  76. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/path-resolver.d.ts +4 -4
  77. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/path-resolver.d.ts.map +1 -1
  78. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/path-resolver.js +15 -15
  79. package/esm/src/utils/index.d.ts +10 -1
  80. package/esm/src/utils/index.d.ts.map +1 -1
  81. package/esm/src/utils/index.js +9 -1
  82. package/esm/src/utils/logger/index.d.ts +1 -1
  83. package/esm/src/utils/logger/index.d.ts.map +1 -1
  84. package/esm/src/utils/logger/index.js +1 -1
  85. package/esm/src/utils/logger/logger.d.ts +14 -0
  86. package/esm/src/utils/logger/logger.d.ts.map +1 -1
  87. package/esm/src/utils/logger/logger.js +17 -0
  88. package/esm/src/workflow/claude-code/tool.d.ts +5 -5
  89. package/package.json +4 -1
  90. package/src/cli/commands/knowledge/command-help.ts +3 -1
  91. package/src/cli/commands/knowledge/command.ts +180 -22
  92. package/src/cli/commands/knowledge/parser-source.ts +110 -5
  93. package/src/deno.js +3 -1
  94. package/src/src/data/data-fetcher.ts +18 -2
  95. package/src/src/data/index.ts +1 -1
  96. package/src/src/data/server-data-fetcher.ts +78 -3
  97. package/src/src/rendering/orchestrator/lifecycle.ts +11 -0
  98. package/src/src/rendering/orchestrator/pipeline.ts +7 -2
  99. package/src/src/rendering/orchestrator/ssr-orchestrator.ts +119 -0
  100. package/src/src/routing/api/handler.ts +16 -3
  101. package/src/src/routing/api/route-executor.ts +222 -1
  102. package/src/src/security/deno-permissions.ts +11 -0
  103. package/src/src/security/sandbox/project-worker.ts +416 -0
  104. package/src/src/security/sandbox/worker-permissions.ts +74 -0
  105. package/src/src/security/sandbox/worker-pool.ts +451 -0
  106. package/src/src/security/sandbox/worker-types.ts +209 -0
  107. package/src/src/server/handlers/request/ssr/ssr.handler.ts +11 -2
  108. package/src/src/server/project-env/storage.ts +9 -0
  109. package/src/src/server/runtime-handler/adapter-factory.ts +13 -5
  110. package/src/src/server/runtime-handler/index.ts +132 -39
  111. package/src/src/server/runtime-handler/local-project-discovery.ts +51 -17
  112. package/src/src/server/runtime-handler/project-isolation.ts +53 -0
  113. package/src/src/server/services/rendering/ssr.service.ts +34 -3
  114. package/src/src/server/shared/renderer/adapter.ts +107 -8
  115. package/src/src/server/shared/renderer/index.ts +7 -1
  116. package/src/src/server/shared/renderer/memory/pressure.ts +8 -0
  117. package/src/src/transforms/pipeline/stages/ssr-vf-modules/path-resolver.ts +18 -12
  118. package/src/src/utils/index.ts +11 -0
  119. package/src/src/utils/logger/index.ts +1 -0
  120. package/src/src/utils/logger/logger.ts +34 -0
@@ -12,7 +12,7 @@ import { runtime } from "../../platform/adapters/detect.js";
12
12
  import { isExtendedFSAdapter } from "../../platform/adapters/fs/wrapper.js";
13
13
  import { getConfig } from "../../config/loader.js";
14
14
  import { timeAsync } from "./request-lifecycle.js";
15
- import { findLocalProjectPath, localAdapterCache } from "./local-project-discovery.js";
15
+ import { defaultDiscoveryCache, findLocalProjectPath, } from "./local-project-discovery.js";
16
16
  const baseLogger = getBaseLogger("SERVER");
17
17
  const logger = baseLogger.component("adapter-factory");
18
18
  /**
@@ -22,6 +22,7 @@ const logger = baseLogger.component("adapter-factory");
22
22
  * For proxy mode: Uses VeryFront API adapter with project context.
23
23
  */
24
24
  export async function resolveAdapter(opts) {
25
+ const cache = opts.cache ?? defaultDiscoveryCache;
25
26
  let effectiveProjectDir = opts.projectDir;
26
27
  let effectiveAdapter = opts.adapter;
27
28
  let effectiveConfig = opts.config;
@@ -31,7 +32,7 @@ export async function resolveAdapter(opts) {
31
32
  const trustedHeaderProjectPath = opts.isProxyMode ? opts.headerProjectPath : undefined;
32
33
  const shouldCheckLocalPath = opts.projectSlug && (!opts.isProxyMode || trustedHeaderProjectPath);
33
34
  const localProjectPath = shouldCheckLocalPath
34
- ? await findLocalProjectPath(opts.projectSlug, opts.adapter, trustedHeaderProjectPath)
35
+ ? await findLocalProjectPath(opts.projectSlug, opts.adapter, trustedHeaderProjectPath, cache)
35
36
  : undefined;
36
37
  const isLocalProject = !!localProjectPath;
37
38
  if (isLocalProject && localProjectPath) {
@@ -41,15 +42,15 @@ export async function resolveAdapter(opts) {
41
42
  projectDir: effectiveProjectDir,
42
43
  });
43
44
  // Get or create local adapter
44
- if (!localAdapterCache.has(effectiveProjectDir)) {
45
+ if (!cache.adapters.has(effectiveProjectDir)) {
45
46
  const baseAdapter = await runtime.get();
46
- localAdapterCache.set(effectiveProjectDir, baseAdapter);
47
+ cache.adapters.set(effectiveProjectDir, baseAdapter);
47
48
  logger.debug("Created local adapter for project", {
48
49
  projectSlug: opts.projectSlug,
49
50
  projectDir: effectiveProjectDir,
50
51
  });
51
52
  }
52
- effectiveAdapter = localAdapterCache.get(effectiveProjectDir);
53
+ effectiveAdapter = cache.adapters.get(effectiveProjectDir);
53
54
  // Load project-specific config
54
55
  try {
55
56
  effectiveConfig = await timeAsync("config:load-project", () => getConfig(effectiveProjectDir, effectiveAdapter));
@@ -9,7 +9,40 @@
9
9
  import * as dntShim from "../../../_dnt.shims.js";
10
10
  import type { RuntimeAdapter } from "../../platform/adapters/base.js";
11
11
  import type { VeryfrontConfig } from "../../config/index.js";
12
+ import { RouteRegistry } from "../../routing/registry/index.js";
13
+ import type { Handler } from "../../types/index.js";
14
+ import { ApiHandlerWrapper } from "../handlers/request/api/index.js";
12
15
  export { parseProxyEnvironment, type ProxyEnvironment } from "./proxy-environment.js";
16
+ /** Handler names in registration order. */
17
+ export declare const HANDLER_NAMES: readonly ["AuthHandler", "CsrfHandler", "HMRHandler", "CorsHandler", "HealthHandler", "MetricsHandler", "MemoryDebugHandler", "ClientLogHandler", "DevEndpointsHandler", "StylesCSSHandler", "DebugContextHandler", "OpenAPIHandler", "OpenAPIDocsHandler", "InternalAgentsListHandler", "AgentStreamHandler", "AgentRunResumeHandler", "AgentRunCancelHandler", "ChannelInvokeHandler", "DevDashboardHandler", "ProjectsHandler", "StudioBridgeModulesHandler", "CSSHandler", "DevFileHandler", "SnippetHandler", "StaticHandler", "LibModulesHandler", "RSCHandler", "ModuleHandler", "ApiHandlerWrapper", "MarkdownPreviewHandler", "SSRHandler", "NotFoundHandler"];
18
+ /** Union of all registered handler names. */
19
+ export type HandlerName = (typeof HANDLER_NAMES)[number];
20
+ /**
21
+ * Dependencies for handler registry creation.
22
+ * All fields are optional — when omitted, the real handler implementation is used.
23
+ * This allows tests to inject mock handlers for specific slots.
24
+ */
25
+ export interface HandlerDependencies {
26
+ /** Override any handler by its typed name. */
27
+ overrides?: Partial<Record<HandlerName, Handler>>;
28
+ /** When true, log handler registration details. */
29
+ debug?: boolean;
30
+ }
31
+ /**
32
+ * Creates a RouteRegistry populated with the standard handler chain.
33
+ *
34
+ * Handlers are instantiated lazily — overridden slots skip construction
35
+ * of the default handler entirely.
36
+ *
37
+ * @param projectDir - Root project directory
38
+ * @param adapter - Runtime adapter for environment access
39
+ * @param deps - Optional dependency overrides for testing
40
+ * @returns Object containing the registry and the api handler (for initialization)
41
+ */
42
+ export declare function createHandlerRegistry(projectDir: string, adapter: RuntimeAdapter, deps?: HandlerDependencies): {
43
+ registry: RouteRegistry;
44
+ apiHandler: ApiHandlerWrapper;
45
+ };
13
46
  export interface RuntimeHandlerOptions {
14
47
  projectDir: string;
15
48
  /** When true, expose additional debug logging. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAQlD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AA6F7D,OAAO,EAAE,qBAAqB,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAMtF,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,oFAAoF;IACpF,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,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;CAC/C;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE,qBAAsC,GAC3C,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CA4anF;AAGD,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAQlD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAK7D,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AA0BpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AA8DrE,OAAO,EAAE,qBAAqB,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAMtF,2CAA2C;AAC3C,eAAO,MAAM,aAAa,yoBAiChB,CAAC;AAEX,6CAA6C;AAC7C,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,8CAA8C;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;IAClD,mDAAmD;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAyCD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE,mBAAwB,GAC7B;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,iBAAiB,CAAA;CAAE,CAuB5D;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,oFAAoF;IACpF,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,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;CAC/C;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE,qBAAsC,GAC3C,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAsYnF;AAGD,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC"}
@@ -67,6 +67,108 @@ import { SCANNER_PATH_PATTERN } from "../../utils/constants/security.js";
67
67
  export { parseProxyEnvironment } from "./proxy-environment.js";
68
68
  const baseLogger = getBaseLogger("SERVER");
69
69
  const logger = baseLogger.component("runtime-handler");
70
+ /** Handler names in registration order. */
71
+ export const HANDLER_NAMES = [
72
+ "AuthHandler",
73
+ "CsrfHandler",
74
+ "HMRHandler",
75
+ "CorsHandler",
76
+ "HealthHandler",
77
+ "MetricsHandler",
78
+ "MemoryDebugHandler",
79
+ "ClientLogHandler",
80
+ "DevEndpointsHandler",
81
+ "StylesCSSHandler",
82
+ "DebugContextHandler",
83
+ "OpenAPIHandler",
84
+ "OpenAPIDocsHandler",
85
+ "InternalAgentsListHandler",
86
+ "AgentStreamHandler",
87
+ "AgentRunResumeHandler",
88
+ "AgentRunCancelHandler",
89
+ "ChannelInvokeHandler",
90
+ "DevDashboardHandler",
91
+ "ProjectsHandler",
92
+ "StudioBridgeModulesHandler",
93
+ "CSSHandler",
94
+ "DevFileHandler",
95
+ "SnippetHandler",
96
+ "StaticHandler",
97
+ "LibModulesHandler",
98
+ "RSCHandler",
99
+ "ModuleHandler",
100
+ "ApiHandlerWrapper",
101
+ "MarkdownPreviewHandler",
102
+ "SSRHandler",
103
+ "NotFoundHandler",
104
+ ];
105
+ /** Factory for each handler. Only called when no override is provided (lazy instantiation). */
106
+ const handlerFactories = {
107
+ AuthHandler: () => new AuthHandler(),
108
+ CsrfHandler: () => new CsrfHandler(),
109
+ HMRHandler: () => new HMRHandler(),
110
+ CorsHandler: () => new CorsHandler(),
111
+ HealthHandler: () => new HealthHandler(),
112
+ MetricsHandler: () => new MetricsHandler(),
113
+ MemoryDebugHandler: () => new MemoryDebugHandler(),
114
+ ClientLogHandler: () => new ClientLogHandler(),
115
+ DevEndpointsHandler: () => new DevEndpointsHandler(),
116
+ StylesCSSHandler: () => new StylesCSSHandler(),
117
+ DebugContextHandler: () => new DebugContextHandler(),
118
+ OpenAPIHandler: () => new OpenAPIHandler(),
119
+ OpenAPIDocsHandler: () => new OpenAPIDocsHandler(),
120
+ InternalAgentsListHandler: () => new InternalAgentsListHandler(),
121
+ AgentStreamHandler: () => new AgentStreamHandler(),
122
+ AgentRunResumeHandler: () => new AgentRunResumeHandler(),
123
+ AgentRunCancelHandler: () => new AgentRunCancelHandler(),
124
+ ChannelInvokeHandler: () => new ChannelInvokeHandler(),
125
+ DevDashboardHandler: () => new DevDashboardHandler(),
126
+ ProjectsHandler: () => new ProjectsHandler(),
127
+ StudioBridgeModulesHandler: () => new StudioBridgeModulesHandler(),
128
+ CSSHandler: () => new CSSHandler(),
129
+ DevFileHandler: () => new DevFileHandler(),
130
+ SnippetHandler: () => new SnippetHandler(),
131
+ StaticHandler: () => new StaticHandler(),
132
+ LibModulesHandler: () => new LibModulesHandler(),
133
+ RSCHandler: () => new RSCHandler(),
134
+ ModuleHandler: () => new ModuleHandler(),
135
+ ApiHandlerWrapper: (projectDir, adapter) => new ApiHandlerWrapper(projectDir, adapter),
136
+ MarkdownPreviewHandler: () => new MarkdownPreviewHandler(),
137
+ SSRHandler: () => new SSRHandler(),
138
+ NotFoundHandler: () => new NotFoundHandler(),
139
+ };
140
+ /**
141
+ * Creates a RouteRegistry populated with the standard handler chain.
142
+ *
143
+ * Handlers are instantiated lazily — overridden slots skip construction
144
+ * of the default handler entirely.
145
+ *
146
+ * @param projectDir - Root project directory
147
+ * @param adapter - Runtime adapter for environment access
148
+ * @param deps - Optional dependency overrides for testing
149
+ * @returns Object containing the registry and the api handler (for initialization)
150
+ */
151
+ export function createHandlerRegistry(projectDir, adapter, deps = {}) {
152
+ const registry = new RouteRegistry({
153
+ debug: deps.debug,
154
+ enableMetrics: true,
155
+ });
156
+ const overrides = deps.overrides ?? {};
157
+ // Create the ApiHandlerWrapper first — it's special because callers need
158
+ // the returned instance for initialization regardless of overrides.
159
+ const apiHandler = overrides.ApiHandlerWrapper
160
+ ? overrides.ApiHandlerWrapper
161
+ : new ApiHandlerWrapper(projectDir, adapter);
162
+ const handlers = HANDLER_NAMES.map((name) => {
163
+ if (name === "ApiHandlerWrapper")
164
+ return apiHandler;
165
+ if (overrides[name])
166
+ return overrides[name];
167
+ return handlerFactories[name](projectDir, adapter);
168
+ });
169
+ registry.registerAll(handlers);
170
+ return { registry, apiHandler };
171
+ }
70
172
  export function createVeryfrontHandler(projectDir, adapter, opts = { projectDir }) {
71
173
  const isDebugEnabled = !!(opts.debug || adapter.env.get("VERYFRONT_DEBUG"));
72
174
  function logDebug(message, extra) {
@@ -109,45 +211,9 @@ export function createVeryfrontHandler(projectDir, adapter, opts = { projectDir
109
211
  return undefined;
110
212
  }
111
213
  })();
112
- const registry = new RouteRegistry({
214
+ const { registry, apiHandler } = createHandlerRegistry(projectDir, adapter, {
113
215
  debug: opts.debug,
114
- enableMetrics: true,
115
216
  });
116
- const apiHandler = new ApiHandlerWrapper(projectDir, adapter);
117
- registry.registerAll([
118
- new AuthHandler(),
119
- new CsrfHandler(),
120
- new HMRHandler(),
121
- new CorsHandler(),
122
- new HealthHandler(),
123
- new MetricsHandler(),
124
- new MemoryDebugHandler(),
125
- new ClientLogHandler(),
126
- new DevEndpointsHandler(),
127
- new StylesCSSHandler(),
128
- new DebugContextHandler(),
129
- new OpenAPIHandler(),
130
- new OpenAPIDocsHandler(),
131
- new InternalAgentsListHandler(),
132
- new AgentStreamHandler(),
133
- new AgentRunResumeHandler(),
134
- new AgentRunCancelHandler(),
135
- new ChannelInvokeHandler(),
136
- new DevDashboardHandler(),
137
- new ProjectsHandler(),
138
- new StudioBridgeModulesHandler(),
139
- new CSSHandler(),
140
- new DevFileHandler(),
141
- new SnippetHandler(),
142
- new StaticHandler(),
143
- new LibModulesHandler(),
144
- new RSCHandler(),
145
- new ModuleHandler(),
146
- apiHandler,
147
- new MarkdownPreviewHandler(),
148
- new SSRHandler(),
149
- new NotFoundHandler(),
150
- ]);
151
217
  const isProxyMode = opts.config?.fs?.veryfront?.proxyMode === true;
152
218
  const readyPromise = isProxyMode ? Promise.resolve() : apiHandler.initialize().catch((error) => {
153
219
  logger.error("API handler initialization failed", {
@@ -8,19 +8,47 @@
8
8
  */
9
9
  import type { RuntimeAdapter } from "../../platform/adapters/base.js";
10
10
  import { LRUCache } from "../../utils/lru-wrapper.js";
11
- /** Cache of local adapters by project directory */
11
+ /**
12
+ * Injectable cache container for project discovery state.
13
+ *
14
+ * Wraps both the project-path cache (slug → absolute path) and the
15
+ * adapter cache (project dir → RuntimeAdapter) so that callers — especially
16
+ * tests — can supply an isolated instance instead of sharing global state.
17
+ */
18
+ export declare class ProjectDiscoveryCache {
19
+ /** Cache of discovered local project paths by slug */
20
+ readonly projects: LRUCache<string, string>;
21
+ /** Cache of local adapters by project directory */
22
+ readonly adapters: LRUCache<string, RuntimeAdapter>;
23
+ constructor(opts?: {
24
+ maxProjects?: number;
25
+ maxAdapters?: number;
26
+ });
27
+ /** Clear both caches */
28
+ clear(): void;
29
+ }
30
+ /** Default module-level cache instance (backward-compatible singleton) */
31
+ export declare const defaultDiscoveryCache: ProjectDiscoveryCache;
32
+ /**
33
+ * @deprecated Use `defaultDiscoveryCache.adapters` instead.
34
+ * Kept for backward compatibility with existing consumers.
35
+ */
12
36
  export declare const localAdapterCache: LRUCache<string, RuntimeAdapter>;
37
+ /**
38
+ * @deprecated Use `defaultDiscoveryCache.projects` instead.
39
+ * Kept for backward compatibility with existing consumers.
40
+ */
41
+ export declare const localProjectCache: LRUCache<string, string>;
13
42
  /** Standard directories to search for local projects */
14
43
  export declare const standardProjectDirs: string[];
15
- /** Cache of discovered local project paths by slug */
16
- export declare const localProjectCache: LRUCache<string, string>;
17
44
  /**
18
45
  * Find the local filesystem path for a project by slug.
19
46
  *
20
47
  * @param slug - The project slug to find
21
48
  * @param adapter - The runtime adapter to use for filesystem operations
22
49
  * @param headerPath - Optional path from x-project-path header (takes precedence)
50
+ * @param cache - Optional cache instance (defaults to module-level singleton)
23
51
  * @returns The absolute path to the project, or undefined if not found
24
52
  */
25
- export declare function findLocalProjectPath(slug: string, adapter: RuntimeAdapter, headerPath?: string): Promise<string | undefined>;
53
+ export declare function findLocalProjectPath(slug: string, adapter: RuntimeAdapter, headerPath?: string, cache?: ProjectDiscoveryCache): Promise<string | undefined>;
26
54
  //# sourceMappingURL=local-project-discovery.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"local-project-discovery.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/local-project-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAOtD,mDAAmD;AACnD,eAAO,MAAM,iBAAiB,kCAE5B,CAAC;AAKH,wDAAwD;AACxD,eAAO,MAAM,mBAAmB,UAAgC,CAAC;AAEjE,sDAAsD;AACtD,eAAO,MAAM,iBAAiB,0BAE5B,CAAC;AAyCH;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,cAAc,EACvB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA+C7B"}
1
+ {"version":3,"file":"local-project-discovery.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/local-project-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAOtD;;;;;;GAMG;AACH,qBAAa,qBAAqB;IAChC,sDAAsD;IACtD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;gBAExC,IAAI,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE;IASjE,wBAAwB;IACxB,KAAK,IAAI,IAAI;CAId;AAED,0EAA0E;AAC1E,eAAO,MAAM,qBAAqB,uBAA8B,CAAC;AAMjE;;;GAGG;AACH,eAAO,MAAM,iBAAiB,kCAAiC,CAAC;AAEhE;;;GAGG;AACH,eAAO,MAAM,iBAAiB,0BAAiC,CAAC;AAEhE,wDAAwD;AACxD,eAAO,MAAM,mBAAmB,UAAgC,CAAC;AAsCjE;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,cAAc,EACvB,UAAU,CAAC,EAAE,MAAM,EACnB,KAAK,GAAE,qBAA6C,GACnD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA+C7B"}
@@ -12,20 +12,49 @@ import { LRUCache } from "../../utils/lru-wrapper.js";
12
12
  import { registerLRUCache } from "../../cache/index.js";
13
13
  const baseLogger = getBaseLogger("SERVER");
14
14
  const logger = baseLogger.component("runtime-handler");
15
- /** Cache of local adapters by project directory */
16
- export const localAdapterCache = new LRUCache({
17
- maxEntries: 50,
18
- });
19
- // Register cache for monitoring
20
- registerLRUCache("local-adapter-cache", localAdapterCache);
15
+ /**
16
+ * Injectable cache container for project discovery state.
17
+ *
18
+ * Wraps both the project-path cache (slug → absolute path) and the
19
+ * adapter cache (project dir → RuntimeAdapter) so that callers — especially
20
+ * tests — can supply an isolated instance instead of sharing global state.
21
+ */
22
+ export class ProjectDiscoveryCache {
23
+ /** Cache of discovered local project paths by slug */
24
+ projects;
25
+ /** Cache of local adapters by project directory */
26
+ adapters;
27
+ constructor(opts) {
28
+ this.projects = new LRUCache({
29
+ maxEntries: opts?.maxProjects ?? 100,
30
+ });
31
+ this.adapters = new LRUCache({
32
+ maxEntries: opts?.maxAdapters ?? 50,
33
+ });
34
+ }
35
+ /** Clear both caches */
36
+ clear() {
37
+ this.projects.clear();
38
+ this.adapters.clear();
39
+ }
40
+ }
41
+ /** Default module-level cache instance (backward-compatible singleton) */
42
+ export const defaultDiscoveryCache = new ProjectDiscoveryCache();
43
+ // Register the default caches for monitoring
44
+ registerLRUCache("local-project-cache", defaultDiscoveryCache.projects);
45
+ registerLRUCache("local-adapter-cache", defaultDiscoveryCache.adapters);
46
+ /**
47
+ * @deprecated Use `defaultDiscoveryCache.adapters` instead.
48
+ * Kept for backward compatibility with existing consumers.
49
+ */
50
+ export const localAdapterCache = defaultDiscoveryCache.adapters;
51
+ /**
52
+ * @deprecated Use `defaultDiscoveryCache.projects` instead.
53
+ * Kept for backward compatibility with existing consumers.
54
+ */
55
+ export const localProjectCache = defaultDiscoveryCache.projects;
21
56
  /** Standard directories to search for local projects */
22
57
  export const standardProjectDirs = ["data/projects", "projects"];
23
- /** Cache of discovered local project paths by slug */
24
- export const localProjectCache = new LRUCache({
25
- maxEntries: 100,
26
- });
27
- // Register cache for monitoring
28
- registerLRUCache("local-project-cache", localProjectCache);
29
58
  function isNotFoundError(error) {
30
59
  if (!(error instanceof Error))
31
60
  return false;
@@ -68,9 +97,10 @@ async function isValidLocalProjectPath(path, adapter) {
68
97
  * @param slug - The project slug to find
69
98
  * @param adapter - The runtime adapter to use for filesystem operations
70
99
  * @param headerPath - Optional path from x-project-path header (takes precedence)
100
+ * @param cache - Optional cache instance (defaults to module-level singleton)
71
101
  * @returns The absolute path to the project, or undefined if not found
72
102
  */
73
- export async function findLocalProjectPath(slug, adapter, headerPath) {
103
+ export async function findLocalProjectPath(slug, adapter, headerPath, cache = defaultDiscoveryCache) {
74
104
  if (headerPath) {
75
105
  try {
76
106
  const normalizedPath = headerPath.trim();
@@ -78,7 +108,7 @@ export async function findLocalProjectPath(slug, adapter, headerPath) {
78
108
  const absolutePath = normalizedPath.startsWith("/")
79
109
  ? normalizedPath
80
110
  : `${cwd()}/${normalizedPath}`;
81
- localProjectCache.set(slug, absolutePath);
111
+ cache.projects.set(slug, absolutePath);
82
112
  return absolutePath;
83
113
  }
84
114
  logger.warn("Ignoring invalid x-project-path override", {
@@ -94,7 +124,7 @@ export async function findLocalProjectPath(slug, adapter, headerPath) {
94
124
  });
95
125
  }
96
126
  }
97
- const cached = localProjectCache.get(slug);
127
+ const cached = cache.projects.get(slug);
98
128
  if (cached)
99
129
  return cached;
100
130
  for (const dir of standardProjectDirs) {
@@ -103,7 +133,7 @@ export async function findLocalProjectPath(slug, adapter, headerPath) {
103
133
  if (!await isValidLocalProjectPath(projectPath, adapter))
104
134
  continue;
105
135
  const absolutePath = projectPath.startsWith("/") ? projectPath : `${cwd()}/${projectPath}`;
106
- localProjectCache.set(slug, absolutePath);
136
+ cache.projects.set(slug, absolutePath);
107
137
  logger.debug("Discovered local project", { slug, path: absolutePath });
108
138
  return absolutePath;
109
139
  }
@@ -19,6 +19,11 @@ export declare class ProjectIsolationManager {
19
19
  checkRequest(projectSlug: string | undefined): IsolationCheckResult;
20
20
  startRequest(projectSlug: string | undefined): void;
21
21
  completeRequest(projectSlug: string | undefined, timedOut: boolean): void;
22
+ /**
23
+ * Record a worker crash for a project. This counts as a failure
24
+ * toward the circuit breaker threshold and evicts the worker.
25
+ */
26
+ recordWorkerCrash(projectSlug: string | undefined): void;
22
27
  getStats(): Record<string, {
23
28
  inFlight: number;
24
29
  recentFailures: number;
@@ -1 +1 @@
1
- {"version":3,"file":"project-isolation.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/project-isolation.ts"],"names":[],"mappings":"AAMA,UAAU,sBAAsB;IAC9B,uBAAuB,EAAE,MAAM,CAAC;IAChC,uBAAuB,EAAE,MAAM,CAAC;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;CACzB;AAUD,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,cAAc,GAAG,gBAAgB,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AASD,qBAAa,uBAAuB;IAClC,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,eAAe,CAAqD;gBAEhE,MAAM,GAAE,OAAO,CAAC,sBAAsB,CAAM;IAKxD,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,gBAAgB;IAgBxB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,oBAAoB;IAsCnE,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAQnD,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI;IA4BzE,QAAQ,IAAI,MAAM,CAChB,MAAM,EACN;QACE,QAAQ,EAAE,MAAM,CAAC;QACjB,cAAc,EAAE,MAAM,CAAC;QACvB,WAAW,EAAE,OAAO,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC;KACvB,CACF;IAyBD,QAAQ,IAAI,IAAI;CAIjB;AAED,eAAO,MAAM,gBAAgB,yBAI3B,CAAC"}
1
+ {"version":3,"file":"project-isolation.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/project-isolation.ts"],"names":[],"mappings":"AAUA,UAAU,sBAAsB;IAC9B,uBAAuB,EAAE,MAAM,CAAC;IAChC,uBAAuB,EAAE,MAAM,CAAC;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;CACzB;AAUD,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,cAAc,GAAG,gBAAgB,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AASD,qBAAa,uBAAuB;IAClC,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,eAAe,CAAqD;gBAEhE,MAAM,GAAE,OAAO,CAAC,sBAAsB,CAAM;IAKxD,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,gBAAgB;IAgBxB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,oBAAoB;IAsCnE,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAQnD,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI;IA4BzE;;;OAGG;IACH,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAoCxD,QAAQ,IAAI,MAAM,CAChB,MAAM,EACN;QACE,QAAQ,EAAE,MAAM,CAAC;QACjB,cAAc,EAAE,MAAM,CAAC;QACvB,WAAW,EAAE,OAAO,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC;KACvB,CACF;IAyBD,QAAQ,IAAI,IAAI;CAajB;AAED,eAAO,MAAM,gBAAgB,yBAI3B,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import * as dntShim from "../../../_dnt.shims.js";
2
2
  import { serverLogger } from "../../utils/index.js";
3
3
  import { getEnvNumber, unrefTimer } from "../../platform/compat/process.js";
4
+ import { getWorkerPool, isWorkerIsolationEnabled, } from "../../security/sandbox/worker-pool.js";
4
5
  const logger = serverLogger.component("project-isolation");
5
6
  const DEFAULT_CONFIG = {
6
7
  maxConcurrentPerProject: 20,
@@ -106,6 +107,40 @@ export class ProjectIsolationManager {
106
107
  resetAfterMs: this.config.circuitResetTimeMs,
107
108
  });
108
109
  }
110
+ /**
111
+ * Record a worker crash for a project. This counts as a failure
112
+ * toward the circuit breaker threshold and evicts the worker.
113
+ */
114
+ recordWorkerCrash(projectSlug) {
115
+ if (!projectSlug)
116
+ return;
117
+ const state = this.getOrCreateState(projectSlug);
118
+ const now = Date.now();
119
+ state.failures.push(now);
120
+ state.failures = state.failures.filter((t) => now - t < this.config.failureWindowMs);
121
+ logger.warn("Worker crash recorded", {
122
+ projectSlug,
123
+ recentFailures: state.failures.length,
124
+ });
125
+ // Evict the crashed worker from the pool
126
+ if (isWorkerIsolationEnabled()) {
127
+ try {
128
+ getWorkerPool().evictWorker(projectSlug);
129
+ }
130
+ catch {
131
+ // Pool may not be initialized
132
+ }
133
+ }
134
+ if (state.failures.length < this.config.circuitBreakerThreshold)
135
+ return;
136
+ state.circuitOpenedAt = now;
137
+ logger.error("Circuit opened due to worker crashes", {
138
+ projectSlug,
139
+ recentFailures: state.failures.length,
140
+ threshold: this.config.circuitBreakerThreshold,
141
+ resetAfterMs: this.config.circuitResetTimeMs,
142
+ });
143
+ }
109
144
  getStats() {
110
145
  const stats = {};
111
146
  for (const [slug, state] of this.projects.entries()) {
@@ -123,6 +158,15 @@ export class ProjectIsolationManager {
123
158
  if (this.cleanupInterval)
124
159
  clearInterval(this.cleanupInterval);
125
160
  this.projects.clear();
161
+ // Shut down the worker pool if isolation is enabled
162
+ if (isWorkerIsolationEnabled()) {
163
+ try {
164
+ getWorkerPool().shutdown();
165
+ }
166
+ catch {
167
+ // Pool may not be initialized
168
+ }
169
+ }
126
170
  }
127
171
  }
128
172
  export const projectIsolation = new ProjectIsolationManager({
@@ -2,6 +2,22 @@ import * as dntShim from "../../../../_dnt.shims.js";
2
2
  import type { HandlerContext } from "../../handlers/types.js";
3
3
  import { type RendererAdapter } from "../../shared/renderer-factory.js";
4
4
  import type { CacheRepository } from "../../../repositories/types.js";
5
+ /**
6
+ * Provides a renderer for a given handler context.
7
+ * Extracted to allow dependency injection in tests.
8
+ */
9
+ export interface RendererProvider {
10
+ getRenderer(ctx: HandlerContext): Promise<RendererAdapter>;
11
+ }
12
+ /**
13
+ * Minimal interface for SSRService consumers (e.g., SSRHandler).
14
+ * Allows dependency injection and mocking in tests.
15
+ */
16
+ export interface SSRServiceLike {
17
+ checkMemoryPressure(): MemoryStatus;
18
+ renderPage(ctx: HandlerContext, options: SSRRenderOptions): Promise<SSRRenderResult>;
19
+ createMemoryPressureResult(slug: string): SSRRenderResult;
20
+ }
5
21
  export interface SSRRenderResult {
6
22
  status: number;
7
23
  html?: string;
@@ -31,10 +47,12 @@ export interface MemoryStatus {
31
47
  heapLimitMB: number;
32
48
  heapUsedPercent: number;
33
49
  }
34
- export declare class SSRService {
50
+ export declare class SSRService implements SSRServiceLike {
35
51
  private readonly cacheRepo?;
52
+ private readonly rendererProvider;
36
53
  constructor(options?: {
37
54
  cacheRepo?: CacheRepository<string>;
55
+ rendererProvider?: RendererProvider;
38
56
  });
39
57
  checkMemoryPressure(): MemoryStatus;
40
58
  getRenderer(ctx: HandlerContext): Promise<RendererAdapter>;
@@ -1 +1 @@
1
- {"version":3,"file":"ssr.service.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/services/rendering/ssr.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,kCAAkC,CAAC;AAmB1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAItE,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACpC,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,UAAU,GAAG,OAAO,CAAC;IACpC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,SAAS,CAAC,EAAE,WAAW,GAAG,YAAY,GAAG,cAAc,GAAG,SAAS,CAAC;IACpE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;IACzB,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAA0B;gBAEzC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,eAAe,CAAC,MAAM,CAAC,CAAA;KAAE;IAI7D,mBAAmB,IAAI,YAAY;IAW7B,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAI1D,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAiG1F,OAAO,CAAC,iBAAiB;IA4FzB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe;CAS1D"}
1
+ {"version":3,"file":"ssr.service.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/services/rendering/ssr.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,kCAAkC,CAAC;AAmB1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAItE;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAC5D;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,mBAAmB,IAAI,YAAY,CAAC;IACpC,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACrF,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAC;CAC3D;AAUD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACpC,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,UAAU,GAAG,OAAO,CAAC;IACpC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,SAAS,CAAC,EAAE,WAAW,GAAG,YAAY,GAAG,cAAc,GAAG,SAAS,CAAC;IACpE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;IACzB,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,UAAW,YAAW,cAAc;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAA0B;IACrD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;gBAExC,OAAO,CAAC,EAAE;QACpB,SAAS,CAAC,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;QACpC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;KACrC;IAKD,mBAAmB,IAAI,YAAY;IAW7B,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAI1D,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAiG1F,OAAO,CAAC,iBAAiB;IA4FzB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe;CAS1D"}
@@ -10,10 +10,18 @@ import { ErrorOverlay, parseErrorLocation } from "../../dev-server/error-overlay
10
10
  import { ErrorPages } from "../../utils/error-html.js";
11
11
  import { HTTP_INTERNAL_SERVER_ERROR, HTTP_NOT_FOUND, HTTP_OK, HTTP_UNAVAILABLE, } from "../../../utils/constants/index.js";
12
12
  const logger = serverLogger.component("ssr-service");
13
+ /**
14
+ * Default RendererProvider that delegates to the real getRendererForProject.
15
+ */
16
+ const defaultRendererProvider = {
17
+ getRenderer: (ctx) => timeAsync("renderer-init", () => getRendererForProject(ctx)),
18
+ };
13
19
  export class SSRService {
14
20
  cacheRepo;
21
+ rendererProvider;
15
22
  constructor(options) {
16
23
  this.cacheRepo = options?.cacheRepo;
24
+ this.rendererProvider = options?.rendererProvider ?? defaultRendererProvider;
17
25
  }
18
26
  checkMemoryPressure() {
19
27
  const stats = getHeapStats();
@@ -25,7 +33,7 @@ export class SSRService {
25
33
  };
26
34
  }
27
35
  async getRenderer(ctx) {
28
- return timeAsync("renderer-init", () => getRendererForProject(ctx));
36
+ return this.rendererProvider.getRenderer(ctx);
29
37
  }
30
38
  async renderPage(ctx, options) {
31
39
  const { request, url, slug, nonce, studioEmbed, projectId, pageId, noHmr, useNoCache } = options;
@@ -9,6 +9,7 @@
9
9
  **************************/
10
10
  import * as dntShim from "../../../../_dnt.shims.js";
11
11
  import type { HandlerContext } from "../../handlers/types.js";
12
+ import { type Renderer, type RendererOptions } from "../../../rendering/renderer.js";
12
13
  import type { PageDataResponse, RenderOptions, RenderResult } from "../../../rendering/orchestrator/types.js";
13
14
  import type { MdxBundle } from "../../../types/index.js";
14
15
  export interface RendererAdapter {
@@ -28,6 +29,30 @@ export interface RendererAdapter {
28
29
  compileMDX(content: string, frontmatter?: Record<string, unknown>, filePath?: string): Promise<MdxBundle>;
29
30
  destroy(): Promise<void>;
30
31
  }
32
+ /**
33
+ * Abstraction over renderer initialization, allowing tests to inject
34
+ * a mock renderer without pulling in the full rendering subsystem.
35
+ */
36
+ export interface RendererInitializer {
37
+ initialize(options: RendererOptions): Promise<Renderer>;
38
+ isInitialized(): boolean;
39
+ get(): Renderer;
40
+ destroy(): Promise<void>;
41
+ }
42
+ /**
43
+ * Replace the renderer initializer used by the adapter layer.
44
+ * Pass `undefined` to restore the default (real) initializer.
45
+ *
46
+ * Returns a disposer that restores the previous initializer — use in
47
+ * `afterEach` or with `using` to prevent test pollution:
48
+ *
49
+ * ```ts
50
+ * afterEach(() => setRendererInitializer(undefined));
51
+ * ```
52
+ *
53
+ * @internal Test-only — not part of the public API.
54
+ */
55
+ export declare function setRendererInitializer(initializer?: RendererInitializer): void;
31
56
  export declare function getRendererForProject(ctx: HandlerContext): Promise<RendererAdapter>;
32
57
  export declare function destroyRendererAdapter(): Promise<void>;
33
58
  //# sourceMappingURL=adapter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/shared/renderer/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;4BAQ4B;AAC5B,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAMrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAY9D,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,YAAY,EACb,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAYzD,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACzE,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAClF,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjC,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,IAAI,IAAI,CAAC;IACtB,sBAAsB,IAAI;QACxB,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;QAC7D,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1E,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAChF,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;QAC/B,KAAK,IAAI,IAAI,CAAC;KACf,CAAC;IACF,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,UAAU,CACR,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,SAAS,CAAC,CAAC;IACtB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAkND,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAiCzF;AAED,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAG5D"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/shared/renderer/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;4BAQ4B;AAC5B,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAMrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,OAAO,EAOL,KAAK,QAAQ,EACb,KAAK,eAAe,EACrB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,YAAY,EACb,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAYzD,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACzE,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAClF,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjC,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,IAAI,IAAI,CAAC;IACtB,sBAAsB,IAAI;QACxB,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;QAC7D,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1E,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAChF,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;QAC/B,KAAK,IAAI,IAAI,CAAC;KACf,CAAC;IACF,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,UAAU,CACR,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,SAAS,CAAC,CAAC;IACtB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxD,aAAa,IAAI,OAAO,CAAC;IACzB,GAAG,IAAI,QAAQ,CAAC;IAChB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AA0CD;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,CAAC,EAAE,mBAAmB,GAChC,IAAI,CAgBN;AAyND,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAiCzF;AAED,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAW5D"}