veryfront 0.1.1057 → 0.1.1059

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.1057",
3
+ "version": "0.1.1059",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "minimumDependencyAge": {
@@ -1 +1 @@
1
- {"version":3,"file":"cache-invalidation.d.ts","sourceRoot":"","sources":["../../../../src/src/server/context/cache-invalidation.ts"],"names":[],"mappings":"AAsBA,UAAU,mBAAmB;IAC3B,qEAAqE;IACrE,WAAW,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACvC,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,MAAM,EAAE,EACvB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAmHf"}
1
+ {"version":3,"file":"cache-invalidation.d.ts","sourceRoot":"","sources":["../../../../src/src/server/context/cache-invalidation.ts"],"names":[],"mappings":"AAuBA,UAAU,mBAAmB;IAC3B,qEAAqE;IACrE,WAAW,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACvC,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,MAAM,EAAE,EACvB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,IAAI,CAAC,CA0Hf"}
@@ -8,6 +8,7 @@ import { clearRouterDetectionCache, clearRouterDetectionCacheForProject, } from
8
8
  import { clearSnippetCacheForProject } from "../../rendering/snippet-renderer.js";
9
9
  import { resetApiHandlerForProject } from "../handlers/request/api/pages-api-handler.js";
10
10
  import { clearSourceMissCache } from "../../modules/server/module-source-resolution-cache.js";
11
+ import { invalidateProjectMiddlewareCache } from "../runtime-handler/project-middleware.js";
11
12
  const logger = serverLogger.component("cache-invalidation");
12
13
  /**
13
14
  * Invalidate project caches with optional environment scoping.
@@ -36,6 +37,12 @@ export async function invalidateProjectCaches(projectSlug, changedPaths, options
36
37
  clearModulePathCache();
37
38
  }
38
39
  clearSourceMissCache();
40
+ const middlewareEntries = invalidateProjectMiddlewareCache(projectSlug, projectId);
41
+ logger.debug("Clearing project middleware cache", {
42
+ projectSlug,
43
+ projectId,
44
+ entriesDeleted: middlewareEntries,
45
+ });
39
46
  logger.debug("Clearing SSR module cache", {
40
47
  projectSlug,
41
48
  projectId,
@@ -1,10 +1,12 @@
1
1
  import { MiddlewarePipeline } from "../../middleware/core/pipeline/index.js";
2
+ import type { MiddlewareHandler } from "../../middleware/core/types.js";
2
3
  import type { RuntimeAdapter } from "../../platform/adapters/base.js";
3
4
  import type { VeryfrontConfig } from "../../config/index.js";
4
- export type MiddlewareFunction = (c: {
5
- req: Request;
6
- var: Record<string, unknown>;
7
- }, next: () => Promise<Response | undefined> | Response) => Promise<Response | undefined> | Response | undefined;
8
- export declare function loadMiddlewareFile(projectDir: string, adapter: RuntimeAdapter): Promise<MiddlewareFunction[]>;
5
+ export type MiddlewareFunction = MiddlewareHandler;
6
+ interface MiddlewareLoadOptions {
7
+ throwOnError?: boolean;
8
+ }
9
+ export declare function loadMiddlewareFile(projectDir: string, adapter: RuntimeAdapter, options?: MiddlewareLoadOptions): Promise<MiddlewareFunction[]>;
9
10
  export declare function setupMiddleware(pipeline: MiddlewarePipeline, config: VeryfrontConfig, requestHandler: (req: Request) => Promise<Response>, projectDir?: string, adapter?: RuntimeAdapter): Promise<void>;
11
+ export {};
10
12
  //# sourceMappingURL=middleware.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../../src/src/server/dev-server/middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAG7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAGtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAU7D,MAAM,MAAM,kBAAkB,GAAG,CAC/B,CAAC,EAAE;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EACjD,IAAI,EAAE,MAAM,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,GAAG,QAAQ,KACjD,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,GAAG,QAAQ,GAAG,SAAS,CAAC;AAkF1D,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAwB/B;AAgED,wBAAsB,eAAe,CACnC,QAAQ,EAAE,kBAAkB,EAC5B,MAAM,EAAE,eAAe,EACvB,cAAc,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,EACnD,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../../src/src/server/dev-server/middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAGxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAGtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAU7D,MAAM,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AAEnD,UAAU,qBAAqB;IAC7B,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAkFD,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CA6B/B;AAkFD,wBAAsB,eAAe,CACnC,QAAQ,EAAE,kBAAkB,EAC5B,MAAM,EAAE,eAAe,EACvB,cAAc,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,EACnD,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
@@ -78,7 +78,7 @@ function createRequestLoggerMiddleware() {
78
78
  });
79
79
  };
80
80
  }
81
- export async function loadMiddlewareFile(projectDir, adapter) {
81
+ export async function loadMiddlewareFile(projectDir, adapter, options = {}) {
82
82
  const middlewareFiles = ["middleware.ts", "middleware.js", "middleware.mjs"];
83
83
  for (const middlewareFile of middlewareFiles) {
84
84
  const middlewarePath = join(projectDir, middlewareFile);
@@ -87,20 +87,22 @@ export async function loadMiddlewareFile(projectDir, adapter) {
87
87
  try {
88
88
  logger.debug(`Loading ${middlewareFile}`);
89
89
  if (isVirtualFilesystem(adapter.fs)) {
90
- return await loadMiddlewareFromVirtualFS(middlewarePath, adapter);
90
+ return await loadMiddlewareFromVirtualFS(middlewarePath, adapter, options.throwOnError === true);
91
91
  }
92
92
  const middlewareUrl = `file://${middlewarePath}?t=${Date.now()}-${dntShim.crypto.randomUUID()}`;
93
93
  const middlewareModule = await import(middlewareUrl);
94
- return normalizeMiddlewareExport(middlewareModule);
94
+ return normalizeMiddlewareExport(middlewareModule, options.throwOnError === true);
95
95
  }
96
96
  catch (error) {
97
97
  const errorMessage = error instanceof Error ? error.message : String(error);
98
98
  logger.warn(`Failed to load ${middlewareFile}: ${errorMessage}`);
99
+ if (options.throwOnError)
100
+ throw error;
99
101
  }
100
102
  }
101
103
  return [];
102
104
  }
103
- async function loadMiddlewareFromVirtualFS(middlewarePath, adapter) {
105
+ async function loadMiddlewareFromVirtualFS(middlewarePath, adapter, strictExport) {
104
106
  const fs = createFileSystem();
105
107
  const content = await adapter.fs.readFile(middlewarePath);
106
108
  const source = typeof content === "string" ? content : new TextDecoder().decode(content);
@@ -129,24 +131,30 @@ async function loadMiddlewareFromVirtualFS(middlewarePath, adapter) {
129
131
  try {
130
132
  await fs.writeTextFile(tempFile, js);
131
133
  const middlewareModule = await import(`file://${tempFile}?v=${Date.now()}`);
132
- return normalizeMiddlewareExport(middlewareModule);
134
+ return normalizeMiddlewareExport(middlewareModule, strictExport);
133
135
  }
134
136
  finally {
135
137
  await fs.remove(tempDir, { recursive: true });
136
138
  }
137
139
  }
138
- function normalizeMiddlewareExport(middlewareModule) {
139
- if (middlewareModule && typeof middlewareModule === "object" && "default" in middlewareModule) {
140
- const exported = middlewareModule.default;
141
- if (Array.isArray(exported)) {
142
- return exported.filter((m) => typeof m === "function");
140
+ function normalizeMiddlewareExport(middlewareModule, strict = false) {
141
+ const exported = middlewareModule && typeof middlewareModule === "object" &&
142
+ "default" in middlewareModule
143
+ ? middlewareModule.default
144
+ : middlewareModule;
145
+ if (Array.isArray(exported)) {
146
+ if (strict && (exported.length === 0 || exported.some((value) => typeof value !== "function"))) {
147
+ throw new TypeError("Invalid middleware export: expected a function or non-empty array of functions");
143
148
  }
144
- return typeof exported === "function" ? [exported] : [];
149
+ return exported.filter((middleware) => typeof middleware === "function");
150
+ }
151
+ if (typeof exported === "function") {
152
+ return [exported];
145
153
  }
146
- if (Array.isArray(middlewareModule)) {
147
- return middlewareModule.filter((m) => typeof m === "function");
154
+ if (strict) {
155
+ throw new TypeError("Invalid middleware export: expected a function or non-empty array of functions");
148
156
  }
149
- return typeof middlewareModule === "function" ? [middlewareModule] : [];
157
+ return [];
150
158
  }
151
159
  export async function setupMiddleware(pipeline, config, requestHandler, projectDir, adapter) {
152
160
  pipeline.use(createRequestLoggerMiddleware());
@@ -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;AAKnE,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AA4BrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AA4EtE,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,8FAA8F;IAC9F,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,CAiLvB"}
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;AAKnE,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AA4BrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AA4EtE,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,8FAA8F;IAC9F,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,CAmLvB"}
@@ -144,11 +144,13 @@ export function startProductionServer(options) {
144
144
  defaultEnvironment,
145
145
  localProjects,
146
146
  });
147
- // Project middleware (root middleware.ts) runs in production with the
148
- // same semantics as in dev: middleware executes before routing and can
149
- // short-circuit by returning a Response. Requests keep their identity
150
- // when middleware calls next(), so WebSocket upgrades stay intact.
151
- const projectMiddleware = await loadMiddlewareFile(projectDir, adapter);
147
+ // Shared proxy filesystems need tenant context from the request, so
148
+ // startup cannot discover a root middleware file. Standalone runtimes
149
+ // load project middleware with the same semantics as the dev server.
150
+ const isProxyMode = bootstrap.config.fs?.veryfront?.proxyMode === true;
151
+ const projectMiddleware = isProxyMode
152
+ ? []
153
+ : await loadMiddlewareFile(projectDir, adapter, { throwOnError: true });
152
154
  let coreHandler = baseHandler;
153
155
  if (projectMiddleware.length > 0) {
154
156
  const pipeline = new MiddlewarePipeline();
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * @module server/project-env
5
5
  */
6
- export { getProjectEnv, isProjectEnvActive, runWithProjectEnv } from "./storage.js";
6
+ export { getProjectEnv, getProjectEnvSnapshot, isProjectEnvActive, runWithProjectEnv, } from "./storage.js";
7
7
  export { EnvironmentVariableCache } from "./cache.js";
8
8
  export { filterRuntimeProjectEnv, filterSharedRuntimeProjectEnv } from "./reserved-env.js";
9
9
  export { fetchProjectEnvVars } from "./fetcher.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/server/project-env/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/server/project-env/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * @module server/project-env
5
5
  */
6
- export { getProjectEnv, isProjectEnvActive, runWithProjectEnv } from "./storage.js";
6
+ export { getProjectEnv, getProjectEnvSnapshot, isProjectEnvActive, runWithProjectEnv, } from "./storage.js";
7
7
  export { EnvironmentVariableCache } from "./cache.js";
8
8
  export { filterRuntimeProjectEnv, filterSharedRuntimeProjectEnv } from "./reserved-env.js";
9
9
  export { fetchProjectEnvVars } from "./fetcher.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,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;AAmCpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAqErE,OAAO,EAAE,qBAAqB,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAMtF,2CAA2C;AAC3C,eAAO,MAAM,aAAa,4vBAqChB,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;AA6CD;;;;;;;;;;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,8FAA8F;IAC9F,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,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CA8cnE;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;AAOH,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;AAmCpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAsErE,OAAO,EAAE,qBAAqB,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAMtF,2CAA2C;AAC3C,eAAO,MAAM,aAAa,4vBAqChB,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;AA6CD;;;;;;;;;;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,8FAA8F;IAC9F,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,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAodnE;AAGD,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC"}
@@ -69,6 +69,7 @@ import { withRequestTimeout } from "./timeout-manager.js";
69
69
  import { EnvironmentVariableCache, fetchProjectEnvVars, filterRuntimeProjectEnv, runWithProjectEnv, } from "../project-env/index.js";
70
70
  import { SCANNER_PATH_PATTERN } from "../../utils/constants/security.js";
71
71
  import { isProxyTrusted } from "../utils/proxy-trust.js";
72
+ import { projectMiddlewareRuntime } from "./project-middleware.js";
72
73
  // Re-export from dedicated module for lightweight imports
73
74
  export { parseProxyEnvironment } from "./proxy-environment.js";
74
75
  const baseLogger = getBaseLogger("SERVER");
@@ -463,7 +464,12 @@ export function createVeryfrontHandler(projectDir, adapter, opts = { projectDir
463
464
  });
464
465
  }
465
466
  await incrementRequestMetrics();
466
- const executeRoute = () => registry.execute(req, ctx);
467
+ const executeRoute = () => projectMiddlewareRuntime.execute({
468
+ request: req,
469
+ handlerContext: ctx,
470
+ isSharedProxy: isProxyMode,
471
+ next: async () => (await registry.execute(req, ctx)) ?? undefined,
472
+ });
467
473
  // Only activate env isolation in proxy mode (multi-tenant).
468
474
  // reqCtx.token indicates the request came through the proxy with auth.
469
475
  // Without it (standalone / test), host env must remain accessible.
@@ -0,0 +1,28 @@
1
+ import type { RuntimeAdapter } from "../../platform/adapters/base.js";
2
+ import { type MiddlewareFunction } from "../dev-server/middleware.js";
3
+ import type { HandlerContext } from "../../types/index.js";
4
+ type MiddlewareLoader = (projectDir: string, adapter: RuntimeAdapter) => Promise<MiddlewareFunction[]>;
5
+ interface ProjectMiddlewareRuntimeOptions {
6
+ maxEntries?: number;
7
+ loadMiddleware?: MiddlewareLoader;
8
+ registryName?: string;
9
+ }
10
+ export interface ProjectMiddlewareRuntimeContext {
11
+ request: Request;
12
+ handlerContext: HandlerContext;
13
+ isSharedProxy: boolean;
14
+ next: () => Promise<Response | undefined>;
15
+ }
16
+ /** Request-scoped root middleware loader for the shared multi-project runtime. */
17
+ export declare class ProjectMiddlewareRuntime {
18
+ #private;
19
+ constructor(options?: ProjectMiddlewareRuntimeOptions);
20
+ get size(): number;
21
+ invalidateProject(projectIdentity: string): number;
22
+ clear(): void;
23
+ execute(input: ProjectMiddlewareRuntimeContext): Promise<Response | undefined>;
24
+ }
25
+ export declare const projectMiddlewareRuntime: ProjectMiddlewareRuntime;
26
+ export declare function invalidateProjectMiddlewareCache(projectSlug: string, projectId?: string): number;
27
+ export {};
28
+ //# sourceMappingURL=project-middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-middleware.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/project-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAMtE,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAO3D,KAAK,gBAAgB,GAAG,CACtB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,KACpB,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;AAEnC,UAAU,+BAA+B;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,IAAI,EAAE,MAAM,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;CAC3C;AAcD,kFAAkF;AAClF,qBAAa,wBAAwB;;gBAIvB,OAAO,GAAE,+BAAoC;IAYzD,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,iBAAiB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM;IAYlD,KAAK,IAAI,IAAI;IAIP,OAAO,CAAC,KAAK,EAAE,+BAA+B,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;CAiGrF;AAED,eAAO,MAAM,wBAAwB,0BAEnC,CAAC;AAEH,wBAAgB,gCAAgC,CAC9C,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAOR"}
@@ -0,0 +1,136 @@
1
+ import { isExtendedFSAdapter } from "../../platform/adapters/fs/wrapper.js";
2
+ import { registerLRUCache } from "../../cache/index.js";
3
+ import { MiddlewareContext } from "../../middleware/core/context.js";
4
+ import { MiddlewarePipeline } from "../../middleware/core/pipeline/index.js";
5
+ import { getProjectEnvSnapshot } from "../project-env/index.js";
6
+ import { loadMiddlewareFile, } from "../dev-server/middleware.js";
7
+ import { LRUCache } from "../../utils/lru-wrapper.js";
8
+ import { serverLogger } from "../../utils/index.js";
9
+ const DEFAULT_MAX_ENTRIES = 100;
10
+ const logger = serverLogger.component("project-middleware");
11
+ function cacheSegment(value) {
12
+ return encodeURIComponent(value);
13
+ }
14
+ function resolvedEnvironment(ctx) {
15
+ return ctx.resolvedEnvironment ?? ctx.requestContext?.mode ?? "preview";
16
+ }
17
+ function resolvedBranch(ctx) {
18
+ return ctx.requestContext?.branch ?? ctx.parsedDomain?.branch ?? null;
19
+ }
20
+ /** Request-scoped root middleware loader for the shared multi-project runtime. */
21
+ export class ProjectMiddlewareRuntime {
22
+ #cache;
23
+ #loadMiddleware;
24
+ constructor(options = {}) {
25
+ this.#cache = new LRUCache({
26
+ maxEntries: options.maxEntries ?? DEFAULT_MAX_ENTRIES,
27
+ });
28
+ this.#loadMiddleware = options.loadMiddleware ??
29
+ ((projectDir, adapter) => loadMiddlewareFile(projectDir, adapter, { throwOnError: true }));
30
+ if (options.registryName) {
31
+ registerLRUCache(options.registryName, this.#cache);
32
+ }
33
+ }
34
+ get size() {
35
+ return this.#cache.size;
36
+ }
37
+ invalidateProject(projectIdentity) {
38
+ const expectedProject = cacheSegment(projectIdentity);
39
+ let deleted = 0;
40
+ for (const key of [...this.#cache.keys()]) {
41
+ if (key.split(":", 1)[0] !== expectedProject)
42
+ continue;
43
+ if (this.#cache.delete(key))
44
+ deleted++;
45
+ }
46
+ return deleted;
47
+ }
48
+ clear() {
49
+ this.#cache.clear();
50
+ }
51
+ async execute(input) {
52
+ const { handlerContext: ctx, isSharedProxy, next, request } = input;
53
+ const fs = ctx.adapter.fs;
54
+ if (!isSharedProxy || ctx.isLocalProject || !ctx.projectSlug || !ctx.proxyToken ||
55
+ !isExtendedFSAdapter(fs) || !fs.isMultiProjectMode()) {
56
+ return next();
57
+ }
58
+ const environment = resolvedEnvironment(ctx);
59
+ const branch = resolvedBranch(ctx);
60
+ return fs.runWithContext(ctx.projectSlug, ctx.proxyToken, async () => {
61
+ const middleware = await this.#getMiddleware(ctx, environment, branch);
62
+ if (middleware.length === 0)
63
+ return next();
64
+ const pipeline = new MiddlewarePipeline();
65
+ for (const handler of middleware)
66
+ pipeline.use(handler);
67
+ const composed = pipeline.compose();
68
+ const middlewareContext = new MiddlewareContext(request, getProjectEnvSnapshot() ?? {});
69
+ return await composed(middlewareContext, next);
70
+ }, ctx.projectId, {
71
+ productionMode: environment === "production",
72
+ releaseId: ctx.releaseId ?? null,
73
+ branch,
74
+ environmentName: ctx.environmentName ?? null,
75
+ });
76
+ }
77
+ async #getMiddleware(ctx, environment, branch) {
78
+ const key = this.#buildCacheKey(ctx, environment, branch);
79
+ if (!key)
80
+ return this.#load(ctx);
81
+ let pending = this.#cache.get(key);
82
+ if (!pending) {
83
+ pending = Promise.resolve().then(() => this.#load(ctx));
84
+ this.#cache.set(key, pending);
85
+ }
86
+ try {
87
+ return await pending;
88
+ }
89
+ catch (error) {
90
+ if (this.#cache.get(key) === pending)
91
+ this.#cache.delete(key);
92
+ throw error;
93
+ }
94
+ }
95
+ #buildCacheKey(ctx, environment, branch) {
96
+ const projectIdentity = ctx.projectId ?? ctx.projectSlug;
97
+ if (!projectIdentity)
98
+ return null;
99
+ const sourceIdentity = environment === "production" ? ctx.releaseId : branch ?? "default";
100
+ if (!sourceIdentity)
101
+ return null;
102
+ const environmentIdentity = ctx.environmentId ?? ctx.environmentName ?? "default";
103
+ return [
104
+ cacheSegment(projectIdentity),
105
+ environment,
106
+ cacheSegment(sourceIdentity),
107
+ cacheSegment(environmentIdentity),
108
+ ].join(":");
109
+ }
110
+ async #load(ctx) {
111
+ try {
112
+ return await this.#loadMiddleware(ctx.projectDir, ctx.adapter);
113
+ }
114
+ catch (error) {
115
+ logger.error("Failed to load project middleware", {
116
+ projectSlug: ctx.projectSlug,
117
+ projectId: ctx.projectId,
118
+ releaseId: ctx.releaseId,
119
+ branch: resolvedBranch(ctx),
120
+ error: error instanceof Error ? error.message : String(error),
121
+ });
122
+ throw error;
123
+ }
124
+ }
125
+ }
126
+ export const projectMiddlewareRuntime = new ProjectMiddlewareRuntime({
127
+ registryName: "project-middleware-cache",
128
+ });
129
+ export function invalidateProjectMiddlewareCache(projectSlug, projectId) {
130
+ const identities = new Set([projectSlug, projectId].filter((value) => !!value));
131
+ let deleted = 0;
132
+ for (const identity of identities) {
133
+ deleted += projectMiddlewareRuntime.invalidateProject(identity);
134
+ }
135
+ return deleted;
136
+ }
@@ -1,3 +1,3 @@
1
1
  /** Shared version value. */
2
- export declare const VERSION = "0.1.1057";
2
+ export declare const VERSION = "0.1.1059";
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.1057";
4
+ export const VERSION = "0.1.1059";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.1057",
3
+ "version": "0.1.1059",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
@@ -328,10 +328,10 @@
328
328
  "@types/react": "19.2.14",
329
329
  "@types/react-dom": "19.2.3",
330
330
  "ws": "8.21.0",
331
- "@veryfront/ext-bundler-esbuild": "0.1.1057",
332
- "@veryfront/ext-content-mdx": "0.1.1057",
333
- "@veryfront/ext-css-tailwind": "0.1.1057",
334
- "@veryfront/ext-parser-babel": "0.1.1057"
331
+ "@veryfront/ext-bundler-esbuild": "0.1.1059",
332
+ "@veryfront/ext-content-mdx": "0.1.1059",
333
+ "@veryfront/ext-css-tailwind": "0.1.1059",
334
+ "@veryfront/ext-parser-babel": "0.1.1059"
335
335
  },
336
336
  "devDependencies": {
337
337
  "@types/node": "20.9.0"