veryfront 0.1.81 → 0.1.83

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 (68) hide show
  1. package/esm/deno.js +1 -1
  2. package/esm/src/platform/adapters/base.d.ts +4 -1
  3. package/esm/src/platform/adapters/base.d.ts.map +1 -1
  4. package/esm/src/platform/adapters/fs/github/adapter.d.ts +2 -1
  5. package/esm/src/platform/adapters/fs/github/adapter.d.ts.map +1 -1
  6. package/esm/src/platform/adapters/fs/github/adapter.js +2 -2
  7. package/esm/src/platform/adapters/fs/github/stat-operations.d.ts +2 -1
  8. package/esm/src/platform/adapters/fs/github/stat-operations.d.ts.map +1 -1
  9. package/esm/src/platform/adapters/fs/github/stat-operations.js +2 -2
  10. package/esm/src/platform/adapters/fs/veryfront/adapter.d.ts +2 -2
  11. package/esm/src/platform/adapters/fs/veryfront/adapter.d.ts.map +1 -1
  12. package/esm/src/platform/adapters/fs/veryfront/adapter.js +17 -2
  13. package/esm/src/platform/adapters/fs/veryfront/multi-project-adapter.d.ts +2 -2
  14. package/esm/src/platform/adapters/fs/veryfront/multi-project-adapter.d.ts.map +1 -1
  15. package/esm/src/platform/adapters/fs/veryfront/multi-project-adapter.js +2 -2
  16. package/esm/src/platform/adapters/fs/veryfront/read-operations.d.ts +1 -0
  17. package/esm/src/platform/adapters/fs/veryfront/read-operations.d.ts.map +1 -1
  18. package/esm/src/platform/adapters/fs/veryfront/stat-operations.d.ts +6 -2
  19. package/esm/src/platform/adapters/fs/veryfront/stat-operations.d.ts.map +1 -1
  20. package/esm/src/platform/adapters/fs/veryfront/stat-operations.js +131 -21
  21. package/esm/src/platform/adapters/fs/veryfront/types.d.ts +2 -1
  22. package/esm/src/platform/adapters/fs/veryfront/types.d.ts.map +1 -1
  23. package/esm/src/platform/adapters/fs/wrapper.d.ts +2 -2
  24. package/esm/src/platform/adapters/fs/wrapper.d.ts.map +1 -1
  25. package/esm/src/platform/adapters/fs/wrapper.js +2 -2
  26. package/esm/src/rendering/app-route-resolver.js +0 -9
  27. package/esm/src/rendering/orchestrator/file-resolver/index.d.ts.map +1 -1
  28. package/esm/src/rendering/orchestrator/file-resolver/index.js +17 -0
  29. package/esm/src/rendering/orchestrator/module-loader/index.d.ts.map +1 -1
  30. package/esm/src/rendering/orchestrator/module-loader/index.js +7 -20
  31. package/esm/src/rendering/page-resolution/page-resolver.d.ts.map +1 -1
  32. package/esm/src/rendering/page-resolution/page-resolver.js +19 -6
  33. package/esm/src/rendering/router-detection.d.ts +1 -0
  34. package/esm/src/rendering/router-detection.d.ts.map +1 -1
  35. package/esm/src/rendering/router-detection.js +3 -0
  36. package/esm/src/transforms/esm/bundle-manifest.d.ts +3 -1
  37. package/esm/src/transforms/esm/bundle-manifest.d.ts.map +1 -1
  38. package/esm/src/transforms/esm/bundle-manifest.js +2 -2
  39. package/esm/src/transforms/esm/cached-bundle-validation.d.ts +9 -0
  40. package/esm/src/transforms/esm/cached-bundle-validation.d.ts.map +1 -0
  41. package/esm/src/transforms/esm/cached-bundle-validation.js +25 -0
  42. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/distributed-cache.d.ts.map +1 -1
  43. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/distributed-cache.js +9 -21
  44. package/esm/src/transforms/pipeline/index.d.ts.map +1 -1
  45. package/esm/src/transforms/pipeline/index.js +8 -24
  46. package/esm/src/types/entities/getEntityInfo.d.ts.map +1 -1
  47. package/esm/src/types/entities/getEntityInfo.js +59 -42
  48. package/package.json +1 -1
  49. package/src/deno.js +1 -1
  50. package/src/src/platform/adapters/base.ts +5 -1
  51. package/src/src/platform/adapters/fs/github/adapter.ts +3 -2
  52. package/src/src/platform/adapters/fs/github/stat-operations.ts +3 -2
  53. package/src/src/platform/adapters/fs/veryfront/adapter.ts +24 -3
  54. package/src/src/platform/adapters/fs/veryfront/multi-project-adapter.ts +6 -3
  55. package/src/src/platform/adapters/fs/veryfront/read-operations.ts +1 -0
  56. package/src/src/platform/adapters/fs/veryfront/stat-operations.ts +161 -25
  57. package/src/src/platform/adapters/fs/veryfront/types.ts +2 -1
  58. package/src/src/platform/adapters/fs/wrapper.ts +10 -3
  59. package/src/src/rendering/app-route-resolver.ts +0 -8
  60. package/src/src/rendering/orchestrator/file-resolver/index.ts +19 -0
  61. package/src/src/rendering/orchestrator/module-loader/index.ts +11 -19
  62. package/src/src/rendering/page-resolution/page-resolver.ts +26 -17
  63. package/src/src/rendering/router-detection.ts +7 -0
  64. package/src/src/transforms/esm/bundle-manifest.ts +6 -3
  65. package/src/src/transforms/esm/cached-bundle-validation.ts +40 -0
  66. package/src/src/transforms/mdx/esm-module-loader/module-fetcher/distributed-cache.ts +13 -24
  67. package/src/src/transforms/pipeline/index.ts +8 -26
  68. package/src/src/types/entities/getEntityInfo.ts +78 -59
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/src/rendering/orchestrator/module-loader/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AA6BzE,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAkJpE,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,cAAc,EAC5B,MAAM,EAAE,kBAAkB,EAC1B,eAAe,UAAQ,GACtB,OAAO,CAAC,MAAM,CAAC,CAkSjB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAyBD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAqClC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/src/rendering/orchestrator/module-loader/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AA2BzE,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAkJpE,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,cAAc,EAC5B,MAAM,EAAE,kBAAkB,EAC1B,eAAe,UAAQ,GACtB,OAAO,CAAC,MAAM,CAAC,CA4RjB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAyBD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAqClC"}
@@ -14,14 +14,12 @@ import { createFileSystem } from "../../../platform/compat/fs.js";
14
14
  import { getProjectTmpDir } from "../../../modules/react-loader/index.js";
15
15
  import { generateCacheKey as generateTransformCacheKey, getOrComputeTransform, initializeTransformCache, setCachedTransformAsync, } from "../../../transforms/esm/transform-cache.js";
16
16
  import { TRANSFORM_DISTRIBUTED_TTL_SEC } from "../../../utils/constants/cache.js";
17
- import { ensureHttpBundlesExist } from "../../../transforms/esm/http-cache.js";
18
- import { validateBundleGroup } from "../../../transforms/esm/bundle-manifest.js";
17
+ import { validateCachedBundlesByManifestOrCode } from "../../../transforms/esm/cached-bundle-validation.js";
19
18
  import { getHttpBundleCacheDir, getMdxEsmCacheDir } from "../../../utils/cache-dir.js";
20
19
  import { dirname, join, normalize } from "../../../platform/compat/path/index.js";
21
20
  import { hashCodeHex } from "../../../utils/hash-utils.js";
22
21
  import { VERSION } from "../../../utils/version.js";
23
22
  import { getModulePathCache, lookupMdxEsmCache, saveModulePathCache, } from "../../../transforms/mdx/esm-module-loader/cache/index.js";
24
- import { extractHttpBundlePaths } from "../../../modules/react-loader/ssr-module-loader/http-bundle-helpers.js";
25
23
  const logger = rendererLogger.component("module-loader");
26
24
  // Re-export utilities
27
25
  export { createEsmCache, createModuleCache, generateHash } from "./cache.js";
@@ -243,30 +241,19 @@ export async function transformModuleWithDeps(filePath, tmpDir, localAdapter, co
243
241
  let transformedCode = transformResult.code;
244
242
  const cacheDir = getHttpBundleCacheDir();
245
243
  let bundlesValid = true;
246
- if (transformResult.cacheHit && transformResult.bundleManifestId) {
247
- const validation = await validateBundleGroup(transformResult.bundleManifestId, cacheDir);
244
+ if (transformResult.cacheHit) {
245
+ const validation = await validateCachedBundlesByManifestOrCode(transformedCode, transformResult.bundleManifestId, cacheDir);
248
246
  if (!validation.valid) {
249
- logger.warn("Bundle manifest validation failed, re-transforming", {
247
+ logger.warn("Cached HTTP bundle validation failed, re-transforming", {
250
248
  filePath,
251
- manifestId: transformResult.bundleManifestId.slice(0, 12),
249
+ manifestId: transformResult.bundleManifestId?.slice(0, 12),
252
250
  failedHashes: validation.failedHashes,
251
+ reason: validation.reason,
252
+ source: validation.source,
253
253
  });
254
254
  bundlesValid = false;
255
255
  }
256
256
  }
257
- else {
258
- const bundlePaths = extractHttpBundlePaths(transformedCode);
259
- if (bundlePaths.length > 0) {
260
- const failed = await ensureHttpBundlesExist(bundlePaths, cacheDir);
261
- if (failed.length > 0) {
262
- logger.warn("HTTP bundle recovery failed, re-transforming", {
263
- filePath,
264
- failed,
265
- });
266
- bundlesValid = false;
267
- }
268
- }
269
- }
270
257
  if (!bundlesValid) {
271
258
  transformedCode = await transformToESM(fileContent, filePath, projectDir, adapter, {
272
259
  projectId: effectiveProjectId,
@@ -1 +1 @@
1
- {"version":3,"file":"page-resolver.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/page-resolution/page-resolver.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAgCvD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,EAAE,cAAc,CAAC;CACzB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,OAAO,CAAiB;gBAEpB,OAAO,EAAE,mBAAmB;IAOxC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAiDxC,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YAoCxB,sBAAsB;IAoD9B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAY1C,aAAa,IAAI,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC;CAShD"}
1
+ {"version":3,"file":"page-resolver.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/page-resolution/page-resolver.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAoCvD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,EAAE,cAAc,CAAC;CACzB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,OAAO,CAAiB;gBAEpB,OAAO,EAAE,mBAAmB;IAOxC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAsDxC,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YAoCxB,sBAAsB;IAoD9B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAY1C,aAAa,IAAI,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC;CAShD"}
@@ -4,7 +4,7 @@ import { VeryfrontError } from "../../errors/index.js";
4
4
  import { FILE_NOT_FOUND } from "../../errors/error-registry.js";
5
5
  import { withSpan } from "../../observability/tracing/otlp-setup.js";
6
6
  import { getEntityBySlug } from "../../types/entities/getEntityInfo.js";
7
- import { detectAppRouter, getAppRouteEntity } from "../router-detection.js";
7
+ import { detectAppRouter, getAppRouteEntity, primeRouterDetectionCache, } from "../router-detection.js";
8
8
  const PAGE_EXTENSIONS = /\.(mdx|md|tsx|jsx|ts|js)$/;
9
9
  const APP_ROUTER_PAGE_PATTERN = /^page\.(mdx|md|tsx|jsx|ts|js)$/;
10
10
  function isPageFile(name) {
@@ -40,20 +40,33 @@ export class PageResolver {
40
40
  }
41
41
  resolvePage(slug) {
42
42
  return withSpan("routing.resolve_page", async () => {
43
- const useAppRouter = await detectAppRouter(this.projectDir, this.config, this.adapter, { projectId: this.projectId });
44
43
  const appDirName = this.config.directories?.app ?? "app";
44
+ const cacheKey = this.projectId ?? this.projectDir;
45
45
  let pageInfo;
46
- if (useAppRouter) {
46
+ if (this.config.router === "app") {
47
+ pageInfo = await getAppRouteEntity(this.projectDir, slug, this.adapter, appDirName);
48
+ if (pageInfo) {
49
+ primeRouterDetectionCache(cacheKey, "app");
50
+ }
51
+ }
52
+ else if (this.config.router === "pages") {
53
+ pageInfo = await getEntityBySlug(this.projectDir, slug, this.adapter);
54
+ if (pageInfo) {
55
+ primeRouterDetectionCache(cacheKey, "pages");
56
+ }
57
+ }
58
+ else {
59
+ // Auto mode stays structural: a single resolved route must not pin router mode
60
+ // for projects that are still transitioning between app/ and pages/.
47
61
  pageInfo = await getAppRouteEntity(this.projectDir, slug, this.adapter, appDirName);
48
62
  if (!pageInfo) {
49
- logger.debug("App Router resolution failed, falling back to Pages Router", { slug });
63
+ pageInfo = await getEntityBySlug(this.projectDir, slug, this.adapter);
50
64
  }
51
65
  }
52
- pageInfo ??= await getEntityBySlug(this.projectDir, slug, this.adapter);
53
66
  if (!pageInfo) {
54
67
  throw FILE_NOT_FOUND.create({
55
68
  detail: `Page not found: ${slug}`,
56
- context: { slug, useAppRouter },
69
+ context: { slug, router: this.config.router ?? "auto" },
57
70
  });
58
71
  }
59
72
  return pageInfo;
@@ -21,6 +21,7 @@ export declare function clearRouterDetectionCache(): void;
21
21
  * @param projectId - The project ID used as cache key. Falls back to projectDir for local dev.
22
22
  */
23
23
  export declare function clearRouterDetectionCacheForProject(projectId: string): void;
24
+ export declare function primeRouterDetectionCache(projectKey: string, mode: "app" | "pages"): void;
24
25
  export interface DetectAppRouterOptions {
25
26
  /** Project ID for cache isolation in multi-tenant deployments */
26
27
  projectId?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"router-detection.d.ts","sourceRoot":"","sources":["../../../src/src/rendering/router-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;4BAO4B;AAK5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAQ1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAY5D;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAED;;;;;GAKG;AACH,wBAAgB,mCAAmC,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE3E;AAED,MAAM,WAAW,sBAAsB;IACrC,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,OAAO,CAAC,CA6BlB"}
1
+ {"version":3,"file":"router-detection.d.ts","sourceRoot":"","sources":["../../../src/src/rendering/router-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;4BAO4B;AAK5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAQ1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAY5D;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAED;;;;;GAKG;AACH,wBAAgB,mCAAmC,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE3E;AAED,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,KAAK,GAAG,OAAO,GACpB,IAAI,CAEN;AAED,MAAM,WAAW,sBAAsB;IACrC,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,OAAO,CAAC,CA6BlB"}
@@ -38,6 +38,9 @@ export function clearRouterDetectionCache() {
38
38
  export function clearRouterDetectionCacheForProject(projectId) {
39
39
  routerDetectionCache.delete(projectId);
40
40
  }
41
+ export function primeRouterDetectionCache(projectKey, mode) {
42
+ routerDetectionCache.set(projectKey, mode === "app");
43
+ }
41
44
  /**
42
45
  * Detect if app router should be used based on config and directory structure.
43
46
  *
@@ -20,10 +20,12 @@ interface BundleManifest {
20
20
  createdAt: number;
21
21
  ttlSeconds: number;
22
22
  }
23
+ export type ManifestValidationReason = "manifest_missing" | "bundle_missing";
23
24
  /** Result of manifest validation. */
24
- interface ManifestValidationResult {
25
+ export interface ManifestValidationResult {
25
26
  valid: boolean;
26
27
  failedHashes: string[];
28
+ reason?: ManifestValidationReason;
27
29
  }
28
30
  /**
29
31
  * Compute a deterministic manifest ID from bundle hashes.
@@ -1 +1 @@
1
- {"version":3,"file":"bundle-manifest.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/bundle-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;4BAQ4B;AAiB5B,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,oEAAoE;AACpE,UAAU,cAAc;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qCAAqC;AACrC,UAAU,wBAAwB;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAgBD;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAEzE;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAc1F;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBjF;AAuBD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,CAAC,CA6CnC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAErE;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB1E"}
1
+ {"version":3,"file":"bundle-manifest.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/bundle-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;4BAQ4B;AAiB5B,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,oEAAoE;AACpE,UAAU,cAAc;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,wBAAwB,GAAG,kBAAkB,GAAG,gBAAgB,CAAC;AAE7E,qCAAqC;AACrC,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,wBAAwB,CAAC;CACnC;AAgBD;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAEzE;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAc1F;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBjF;AAuBD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,CAAC,CA6CnC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAErE;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB1E"}
@@ -106,7 +106,7 @@ export async function validateBundleGroup(manifestId, cacheDir) {
106
106
  logger.debug(`${LOG_PREFIX} Manifest not found in distributed cache`, {
107
107
  manifestId: manifestId.slice(0, 12),
108
108
  });
109
- return { valid: false, failedHashes: [] };
109
+ return { valid: false, failedHashes: [], reason: "manifest_missing" };
110
110
  }
111
111
  const missingBundles = [];
112
112
  await Promise.all(manifest.bundles.map(async ({ hash }) => {
@@ -132,7 +132,7 @@ export async function validateBundleGroup(manifestId, cacheDir) {
132
132
  manifestId: manifestId.slice(0, 12),
133
133
  unrecoverable: unrecoverableHashes,
134
134
  });
135
- return { valid: false, failedHashes: unrecoverableHashes };
135
+ return { valid: false, failedHashes: unrecoverableHashes, reason: "bundle_missing" };
136
136
  }
137
137
  logger.info(`${LOG_PREFIX} All missing bundles recovered successfully`, {
138
138
  manifestId: manifestId.slice(0, 12),
@@ -0,0 +1,9 @@
1
+ import { type ManifestValidationReason } from "./bundle-manifest.js";
2
+ export interface CachedBundleValidationResult {
3
+ valid: boolean;
4
+ failedHashes: string[];
5
+ reason?: ManifestValidationReason;
6
+ source: "manifest" | "code";
7
+ }
8
+ export declare function validateCachedBundlesByManifestOrCode(code: string, bundleManifestId: string | undefined, cacheDir: string): Promise<CachedBundleValidationResult>;
9
+ //# sourceMappingURL=cached-bundle-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cached-bundle-validation.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/cached-bundle-validation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,wBAAwB,EAAuB,MAAM,sBAAsB,CAAC;AAE1F,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAClC,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC;CAC7B;AAED,wBAAsB,qCAAqC,CACzD,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,4BAA4B,CAAC,CAwBvC"}
@@ -0,0 +1,25 @@
1
+ import { extractHttpBundlePaths } from "../../modules/react-loader/ssr-module-loader/http-bundle-helpers.js";
2
+ import { ensureHttpBundlesExist } from "./http-cache.js";
3
+ import { validateBundleGroup } from "./bundle-manifest.js";
4
+ export async function validateCachedBundlesByManifestOrCode(code, bundleManifestId, cacheDir) {
5
+ if (bundleManifestId) {
6
+ const validation = await validateBundleGroup(bundleManifestId, cacheDir);
7
+ if (validation.valid || validation.reason === "bundle_missing") {
8
+ return { ...validation, source: "manifest" };
9
+ }
10
+ }
11
+ const bundlePaths = extractHttpBundlePaths(code);
12
+ if (bundlePaths.length === 0) {
13
+ return { valid: true, failedHashes: [], source: "code" };
14
+ }
15
+ const failedHashes = await ensureHttpBundlesExist(bundlePaths, cacheDir);
16
+ if (failedHashes.length === 0) {
17
+ return { valid: true, failedHashes: [], source: "code" };
18
+ }
19
+ return {
20
+ valid: false,
21
+ failedHashes,
22
+ reason: "bundle_missing",
23
+ source: "code",
24
+ };
25
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"distributed-cache.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/module-fetcher/distributed-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAYjE,OAAO,EAAE,8BAA8B,EAAE,MAAM,iCAAiC,CAAC;AAWjF,qDAAqD;AACrD,KAAK,gBAAgB,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,8BAA8B,CAAC,CAAC,CAAC,CAAC;AAEhG;;;;;GAKG;AACH,UAAU,0BAA0B;IAClC,4EAA4E;IAC5E,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,4DAA4D;IAC5D,gBAAgB,EAAE,gBAAgB,CAAC;CACpC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,oBAAoB,CACxC,iBAAiB,EAAE,MAAM,EACzB,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC,CA4G5C;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,gBAAgB,EAAE,gBAAgB,EAClC,iBAAiB,EAAE,MAAM,EACzB,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,GAAG,EAAE,MAAM,GACV,IAAI,CAqCN"}
1
+ {"version":3,"file":"distributed-cache.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/module-fetcher/distributed-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AASjE,OAAO,EAAE,8BAA8B,EAAE,MAAM,iCAAiC,CAAC;AAWjF,qDAAqD;AACrD,KAAK,gBAAgB,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,8BAA8B,CAAC,CAAC,CAAC,CAAC;AAEhG;;;;;GAKG;AACH,UAAU,0BAA0B;IAClC,4EAA4E;IAC5E,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,4DAA4D;IAC5D,gBAAgB,EAAE,gBAAgB,CAAC;CACpC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,oBAAoB,CACxC,iBAAiB,EAAE,MAAM,EACzB,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC,CAoG5C;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,gBAAgB,EAAE,gBAAgB,EAClC,iBAAiB,EAAE,MAAM,EACzB,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,GAAG,EAAE,MAAM,GACV,IAAI,CAqCN"}
@@ -7,10 +7,11 @@
7
7
  * @module transforms/mdx/esm-module-loader/module-fetcher/distributed-cache
8
8
  */
9
9
  import { detokenizeAllCachePaths, tokenizeAllVeryFrontPaths } from "../../../../cache/index.js";
10
- import { cacheHttpImportsToLocal, ensureHttpBundlesExist } from "../../../esm/http-cache.js";
10
+ import { cacheHttpImportsToLocal } from "../../../esm/http-cache.js";
11
11
  import { loadImportMap } from "../../../../modules/import-map/index.js";
12
12
  import { extractHttpBundlePaths } from "../../../../modules/react-loader/ssr-module-loader/http-bundle-helpers.js";
13
- import { createBundleManifest, storeBundleManifest, validateBundleGroup, } from "../../../esm/bundle-manifest.js";
13
+ import { createBundleManifest, storeBundleManifest } from "../../../esm/bundle-manifest.js";
14
+ import { validateCachedBundlesByManifestOrCode } from "../../../esm/cached-bundle-validation.js";
14
15
  import { getHttpBundleCacheDir } from "../../../../utils/cache-dir.js";
15
16
  import { FRAMEWORK_ROOT, LOG_PREFIX_MDX_LOADER } from "../constants.js";
16
17
  import { getDistributedTransformBackend } from "../../../esm/transform-cache.js";
@@ -50,33 +51,20 @@ export async function readDistributedCache(transformCacheKey, normalizedPath, pr
50
51
  });
51
52
  const bundleManifestKey = `${transformCacheKey}:bm`;
52
53
  const manifestId = await distributedCache.get(bundleManifestKey).catch(() => null);
53
- if (manifestId) {
54
+ if (moduleCode) {
54
55
  const cacheDir = getHttpBundleCacheDir();
55
- const validation = await validateBundleGroup(manifestId, cacheDir);
56
+ const validation = await validateCachedBundlesByManifestOrCode(moduleCode, manifestId ?? undefined, cacheDir);
56
57
  if (!validation.valid) {
57
- log.warn(`${LOG_PREFIX_MDX_LOADER} Bundle manifest validation failed`, {
58
+ log.warn(`${LOG_PREFIX_MDX_LOADER} Cached HTTP bundle validation failed`, {
58
59
  normalizedPath,
59
- manifestId: manifestId.slice(0, 12),
60
+ manifestId: manifestId?.slice(0, 12),
60
61
  failedHashes: validation.failedHashes,
62
+ reason: validation.reason,
63
+ source: validation.source,
61
64
  });
62
65
  moduleCode = null;
63
66
  }
64
67
  }
65
- else {
66
- // Use detokenized code for bundle path extraction
67
- const bundlePaths = extractHttpBundlePaths(moduleCode);
68
- if (bundlePaths.length > 0) {
69
- const cacheDir = getHttpBundleCacheDir();
70
- const failed = await ensureHttpBundlesExist(bundlePaths, cacheDir);
71
- if (failed.length > 0) {
72
- log.warn(`${LOG_PREFIX_MDX_LOADER} Some HTTP bundles could not be recovered`, {
73
- normalizedPath,
74
- failed,
75
- });
76
- moduleCode = null;
77
- }
78
- }
79
- }
80
68
  // Use detokenized code for framework path checks
81
69
  if (moduleCode && await hasIncompatibleFrameworkPaths(moduleCode, log)) {
82
70
  log.warn(`${LOG_PREFIX_MDX_LOADER} Cached code has incompatible framework paths`, {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/pipeline/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAEhB,eAAe,EAChB,MAAM,YAAY,CAAC;AA4IpB,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,gBAAgB,EACzB,MAAM,CAAC,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC,CAoI1B;AAoBD,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,MAAM,CAAC,CASjB;AAmCD,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EACL,sBAAsB,EACtB,0BAA0B,EAC1B,SAAS,EACT,KAAK,EACL,KAAK,EACL,YAAY,GACb,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/pipeline/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAEhB,eAAe,EAChB,MAAM,YAAY,CAAC;AA0HpB,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,gBAAgB,EACzB,MAAM,CAAC,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC,CAoI1B;AAoBD,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,MAAM,CAAC,CASjB;AAmCD,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EACL,sBAAsB,EACtB,0BAA0B,EAC1B,SAAS,EACT,KAAK,EACL,KAAK,EACL,YAAY,GACb,MAAM,cAAc,CAAC"}
@@ -11,10 +11,8 @@ import { computeConfigHash } from "../../cache/config-hash.js";
11
11
  import { computeDepsHash } from "../../cache/dependency-graph.js";
12
12
  import { compilePlugin, cssStripPlugin, finalizePlugin, parsePlugin, resolveImportsPlugin, ssrHttpCachePlugin, ssrHttpStubPlugin, ssrVfModulesPlugin, } from "./stages/index.js";
13
13
  import { createFileSystem, exists } from "../../platform/compat/fs.js";
14
- import { ensureHttpBundlesExist } from "../esm/http-cache.js";
15
- import { extractHttpBundlePaths } from "../../modules/react-loader/ssr-module-loader/http-bundle-helpers.js";
16
14
  import { getHttpBundleCacheDir } from "../../utils/cache-dir.js";
17
- import { validateBundleGroup } from "../esm/bundle-manifest.js";
15
+ import { validateCachedBundlesByManifestOrCode } from "../esm/cached-bundle-validation.js";
18
16
  import { extractFrameworkBundlePaths } from "../shared/framework-bundle-paths.js";
19
17
  const SSR_PIPELINE = [
20
18
  parsePlugin,
@@ -96,29 +94,15 @@ async function validateFrameworkBundles(code, cacheKey) {
96
94
  */
97
95
  async function validateCachedBundles(code, bundleManifestId, cacheKey) {
98
96
  const cacheDir = getHttpBundleCacheDir();
99
- // If we have a manifest ID, use the faster manifest-based validation
100
- if (bundleManifestId) {
101
- const validation = await validateBundleGroup(bundleManifestId, cacheDir);
102
- if (validation.valid)
103
- return true;
104
- logger.debug("Bundle manifest validation failed", {
105
- cacheKey: cacheKey.slice(-40),
106
- manifestId: bundleManifestId.slice(0, 12),
107
- failedCount: validation.failedHashes.length,
108
- });
109
- return false;
110
- }
111
- // Fall back to extracting bundle paths from code and validating each
112
- const bundlePaths = extractHttpBundlePaths(code);
113
- if (bundlePaths.length === 0)
114
- return true;
115
- const failed = await ensureHttpBundlesExist(bundlePaths, cacheDir);
116
- if (failed.length === 0)
97
+ const validation = await validateCachedBundlesByManifestOrCode(code, bundleManifestId, cacheDir);
98
+ if (validation.valid)
117
99
  return true;
118
- logger.debug("HTTP bundle validation failed", {
100
+ logger.debug("Cached HTTP bundle validation failed", {
119
101
  cacheKey: cacheKey.slice(-40),
120
- failedCount: failed.length,
121
- totalBundles: bundlePaths.length,
102
+ manifestId: bundleManifestId?.slice(0, 12),
103
+ failedCount: validation.failedHashes.length,
104
+ reason: validation.reason,
105
+ source: validation.source,
122
106
  });
123
107
  return false;
124
108
  }
@@ -1 +1 @@
1
- {"version":3,"file":"getEntityInfo.d.ts","sourceRoot":"","sources":["../../../../src/src/types/entities/getEntityInfo.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAU,UAAU,EAAe,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAWtE,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA6I5B;AAED,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA+L5B;AAED,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAyE5B"}
1
+ {"version":3,"file":"getEntityInfo.d.ts","sourceRoot":"","sources":["../../../../src/src/types/entities/getEntityInfo.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAU,UAAU,EAAe,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAWtE,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAmJ5B;AAED,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAwM5B;AAED,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAyE5B"}
@@ -29,37 +29,42 @@ export async function getEntityInfo(filePath, adapter) {
29
29
  }
30
30
  }
31
31
  try {
32
+ const shouldReadDirectly = adapter
33
+ ? isExtendedFSAdapter(adapter.fs) && adapter.fs.isVeryfrontAdapter()
34
+ : false;
35
+ let content;
32
36
  if (adapter) {
33
- try {
34
- const stat = await withFallback(() => adapter.fs.stat(normalizedPath), async () => {
35
- const exists = await fs.exists(filePath);
36
- if (!exists) {
37
- throw toError(createError({
38
- type: "file",
39
- message: "File not found",
40
- context: { path: filePath, operation: "read" },
41
- }));
42
- }
43
- return await fs.stat(filePath);
44
- }, { operationName: "stat:getEntityInfo", logError: false });
45
- if (!stat.isFile)
37
+ if (!shouldReadDirectly) {
38
+ try {
39
+ const stat = await withFallback(() => adapter.fs.stat(normalizedPath), async () => {
40
+ const exists = await fs.exists(filePath);
41
+ if (!exists) {
42
+ throw toError(createError({
43
+ type: "file",
44
+ message: "File not found",
45
+ context: { path: filePath, operation: "read" },
46
+ }));
47
+ }
48
+ return await fs.stat(filePath);
49
+ }, { operationName: "stat:getEntityInfo", logError: false });
50
+ if (!stat.isFile)
51
+ return null;
52
+ }
53
+ catch (error) {
54
+ entityInfoScope.runSync(() => {
55
+ throw error;
56
+ }, { path: filePath, details: { reason: "stat-failed" } }, undefined);
46
57
  return null;
58
+ }
47
59
  }
48
- catch (error) {
49
- entityInfoScope.runSync(() => {
50
- throw error;
51
- }, { path: filePath, details: { reason: "stat-failed" } }, undefined);
52
- return null;
53
- }
60
+ content = await withFallback(() => adapter.fs.readFile(normalizedPath), () => fs.readTextFile(filePath), { operationName: "readFile:getEntityInfo", logError: false });
54
61
  }
55
62
  else {
56
63
  const exists = await fs.exists(filePath);
57
64
  if (!exists)
58
65
  return null;
66
+ content = await fs.readTextFile(filePath);
59
67
  }
60
- const content = adapter
61
- ? await withFallback(() => adapter.fs.readFile(normalizedPath), () => fs.readTextFile(filePath), { operationName: "readFile:getEntityInfo", logError: false })
62
- : await fs.readTextFile(filePath);
63
68
  const ext = pathHelper.extname(filePath).toLowerCase();
64
69
  let frontmatter = {};
65
70
  let body = content;
@@ -120,23 +125,27 @@ export async function getEntityInfo(filePath, adapter) {
120
125
  }
121
126
  export async function getEntityBySlug(projectDir, slug, adapter) {
122
127
  return await withSpan("types.getEntityBySlug", async () => {
123
- const isVeryfrontRoute = slug.startsWith(".veryfront/") || slug === ".veryfront";
128
+ const normalizedSlug = normalizeSlug(slug);
129
+ const isVeryfrontRoute = normalizedSlug.startsWith(".veryfront/") ||
130
+ normalizedSlug === ".veryfront";
124
131
  const resolveFile = adapter?.fs.resolveFile;
125
132
  logger.debug("START", {
126
133
  slug,
134
+ normalizedSlug,
127
135
  projectDir,
128
136
  isVeryfrontRoute,
129
137
  hasResolveFile: !!resolveFile,
130
138
  });
131
139
  if (resolveFile) {
132
- const basePaths = [pathHelper.join(projectDir, "pages", slug)];
140
+ const basePaths = [pathHelper.join(projectDir, "pages", normalizedSlug)];
133
141
  if (isVeryfrontRoute)
134
- basePaths.unshift(pathHelper.join(projectDir, slug));
135
- if (slug === "index" || slug === "") {
142
+ basePaths.unshift(pathHelper.join(projectDir, normalizedSlug));
143
+ if (normalizedSlug === "index" || normalizedSlug === "") {
136
144
  basePaths.unshift(pathHelper.join(projectDir, "pages", "index"));
137
145
  }
138
146
  logger.debug("Checking paths (resolveFile branch)", {
139
147
  slug,
148
+ normalizedSlug,
140
149
  basePaths,
141
150
  });
142
151
  const pathResults = await parallelMap(basePaths, async (basePath) => {
@@ -153,12 +162,13 @@ export async function getEntityBySlug(projectDir, slug, adapter) {
153
162
  if (info?.entity.isPage) {
154
163
  logger.debug("Found page via resolveFile", {
155
164
  slug,
165
+ normalizedSlug,
156
166
  path: info.entity.path,
157
167
  });
158
168
  return info;
159
169
  }
160
170
  }
161
- const slugParts = slug.split("/");
171
+ const slugParts = normalizedSlug === "" ? [] : normalizedSlug.split("/");
162
172
  for (let depth = slugParts.length - 1; depth >= 0; depth--) {
163
173
  const parentPath = slugParts.slice(0, depth).join("/");
164
174
  const pagesDir = parentPath
@@ -194,25 +204,25 @@ export async function getEntityBySlug(projectDir, slug, adapter) {
194
204
  /* expected: directory may not exist or readDir may fail */
195
205
  }
196
206
  }
197
- logger.debug("No page found via resolveFile branch", { slug });
207
+ logger.debug("No page found via resolveFile branch", { slug, normalizedSlug });
198
208
  return null;
199
209
  }
200
210
  const possiblePaths = [
201
- pathHelper.join(projectDir, "pages", `${slug}.mdx`),
202
- pathHelper.join(projectDir, "pages", `${slug}.md`),
203
- pathHelper.join(projectDir, "pages", `${slug}.tsx`),
204
- pathHelper.join(projectDir, "pages", `${slug}.jsx`),
205
- pathHelper.join(projectDir, "pages", `${slug}.ts`),
206
- pathHelper.join(projectDir, "pages", `${slug}/index.mdx`),
207
- pathHelper.join(projectDir, "pages", `${slug}/index.md`),
208
- pathHelper.join(projectDir, "pages", `${slug}/index.tsx`),
209
- pathHelper.join(projectDir, "pages", `${slug}/index.jsx`),
210
- pathHelper.join(projectDir, "pages", `${slug}/index.ts`),
211
+ pathHelper.join(projectDir, "pages", `${normalizedSlug}.mdx`),
212
+ pathHelper.join(projectDir, "pages", `${normalizedSlug}.md`),
213
+ pathHelper.join(projectDir, "pages", `${normalizedSlug}.tsx`),
214
+ pathHelper.join(projectDir, "pages", `${normalizedSlug}.jsx`),
215
+ pathHelper.join(projectDir, "pages", `${normalizedSlug}.ts`),
216
+ pathHelper.join(projectDir, "pages", `${normalizedSlug}/index.mdx`),
217
+ pathHelper.join(projectDir, "pages", `${normalizedSlug}/index.md`),
218
+ pathHelper.join(projectDir, "pages", `${normalizedSlug}/index.tsx`),
219
+ pathHelper.join(projectDir, "pages", `${normalizedSlug}/index.jsx`),
220
+ pathHelper.join(projectDir, "pages", `${normalizedSlug}/index.ts`),
211
221
  ];
212
222
  if (isVeryfrontRoute) {
213
- possiblePaths.unshift(pathHelper.join(projectDir, `${slug}.mdx`), pathHelper.join(projectDir, `${slug}.md`), pathHelper.join(projectDir, `${slug}.tsx`), pathHelper.join(projectDir, `${slug}.ts`));
223
+ possiblePaths.unshift(pathHelper.join(projectDir, `${normalizedSlug}.mdx`), pathHelper.join(projectDir, `${normalizedSlug}.md`), pathHelper.join(projectDir, `${normalizedSlug}.tsx`), pathHelper.join(projectDir, `${normalizedSlug}.ts`));
214
224
  }
215
- if (slug === "index" || slug === "") {
225
+ if (normalizedSlug === "index" || normalizedSlug === "") {
216
226
  possiblePaths.unshift(pathHelper.join(projectDir, "pages", "index.mdx"), pathHelper.join(projectDir, "pages", "index.md"), pathHelper.join(projectDir, "pages", "index.tsx"), pathHelper.join(projectDir, "pages", "index.ts"));
217
227
  }
218
228
  const pathResults = await parallelMap(possiblePaths, async (p) => {
@@ -222,7 +232,7 @@ export async function getEntityBySlug(projectDir, slug, adapter) {
222
232
  if (info?.entity.isPage)
223
233
  return info;
224
234
  }
225
- const slugParts = slug.split("/");
235
+ const slugParts = normalizedSlug === "" ? [] : normalizedSlug.split("/");
226
236
  for (let depth = slugParts.length - 1; depth >= 0; depth--) {
227
237
  const parentPath = slugParts.slice(0, depth).join("/");
228
238
  const pagesDir = parentPath
@@ -267,7 +277,11 @@ export async function getEntityBySlug(projectDir, slug, adapter) {
267
277
  }
268
278
  }
269
279
  return null;
270
- }, { "entity.slug": slug, "entity.projectDir": projectDir });
280
+ }, {
281
+ "entity.slug": slug,
282
+ "entity.normalized_slug": normalizeSlug(slug),
283
+ "entity.projectDir": projectDir,
284
+ });
271
285
  }
272
286
  export async function getLayoutEntity(projectDir, layoutName, adapter) {
273
287
  return await withSpan("types.getLayoutEntity", async () => {
@@ -345,3 +359,6 @@ function getSlugFromPath(filePath) {
345
359
  const parentDir = parts[parts.length - 2];
346
360
  return parentDir === "pages" ? "" : parentDir ?? "";
347
361
  }
362
+ function normalizeSlug(slug) {
363
+ return slug === "/" ? "" : slug.replace(/^\/+/, "").replace(/\/+$/, "");
364
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.81",
3
+ "version": "0.1.83",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.81",
3
+ "version": "0.1.83",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -117,7 +117,11 @@ export interface FileSystemAdapter {
117
117
  makeTempDir(prefix: string): Promise<string>;
118
118
  watch(paths: string | string[], options?: WatchOptions): FileWatcher;
119
119
  /** Resolve a file path with extension fallback (e.g., pages/test → pages/test.mdx) */
120
- resolveFile?(basePath: string): Promise<string | null>;
120
+ resolveFile?(basePath: string, options?: ResolveFileOptions): Promise<string | null>;
121
+ }
122
+
123
+ export interface ResolveFileOptions {
124
+ allowPagesPrefix?: boolean;
121
125
  }
122
126
 
123
127
  export interface DirEntry {
@@ -1,6 +1,7 @@
1
1
  import { logger } from "../../../../utils/index.js";
2
2
  import { CONFIG_INVALID } from "../../../../errors/index.js";
3
3
  import { getEnv } from "../../../compat/process.js";
4
+ import type { ResolveFileOptions } from "../../base.js";
4
5
  import { FileCache } from "../cache/file-cache.js";
5
6
  import type { FSAdapter, FSAdapterConfig } from "../veryfront/types.js";
6
7
  import { GitHubApiClient } from "./github-api-client.js";
@@ -115,9 +116,9 @@ export class GitHubFSAdapter implements FSAdapter {
115
116
  return this.dirOps.readdir(path);
116
117
  }
117
118
 
118
- async resolveFile(basePath: string): Promise<string | null> {
119
+ async resolveFile(basePath: string, options?: ResolveFileOptions): Promise<string | null> {
119
120
  await this.ensureInitialized();
120
- return this.statOps.resolveFile(basePath);
121
+ return this.statOps.resolveFile(basePath, options);
121
122
  }
122
123
 
123
124
  getCacheStats(): {
@@ -5,6 +5,7 @@ import {
5
5
  buildGitHubStatCacheKey,
6
6
  buildGitHubTreeCacheKey,
7
7
  } from "../../../../cache/index.js";
8
+ import type { ResolveFileOptions } from "../../base.js";
8
9
  import type { FileCache } from "../cache/file-cache.js";
9
10
  import type { GitHubApiClient } from "./github-api-client.js";
10
11
  import type { FileIndexEntry, FileInfo, GitHubTreeEntry, ResolvedGitHubConfig } from "./types.js";
@@ -176,7 +177,7 @@ export class GitHubStatOperations {
176
177
  }
177
178
  }
178
179
 
179
- async resolveFile(basePath: string): Promise<string | null> {
180
+ async resolveFile(basePath: string, options?: ResolveFileOptions): Promise<string | null> {
180
181
  await this.ensureIndex();
181
182
 
182
183
  const normalizedPath = normalizeGitHubPath(basePath, this.projectDir);
@@ -185,7 +186,7 @@ export class GitHubStatOperations {
185
186
  if (cached !== undefined) return cached;
186
187
 
187
188
  const resolved = this.tryResolve(normalizedPath) ??
188
- this.tryResolveWithPagesPrefix(normalizedPath);
189
+ (options?.allowPagesPrefix === false ? null : this.tryResolveWithPagesPrefix(normalizedPath));
189
190
 
190
191
  this.cache.set(cacheKey, resolved);
191
192
  return resolved;