veryfront 0.1.86 → 0.1.88

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 (36) hide show
  1. package/esm/deno.js +1 -1
  2. package/esm/src/cache/distributed-cache-init.d.ts +9 -0
  3. package/esm/src/cache/distributed-cache-init.d.ts.map +1 -1
  4. package/esm/src/cache/distributed-cache-init.js +70 -52
  5. package/esm/src/cache/module-cache.d.ts +6 -2
  6. package/esm/src/cache/module-cache.d.ts.map +1 -1
  7. package/esm/src/cache/module-cache.js +73 -56
  8. package/esm/src/platform/adapters/fs/veryfront/content-metrics.d.ts +1 -1
  9. package/esm/src/platform/adapters/fs/veryfront/content-metrics.d.ts.map +1 -1
  10. package/esm/src/platform/adapters/fs/veryfront/content-metrics.js +7 -1
  11. package/esm/src/platform/adapters/fs/veryfront/file-list-index.d.ts +10 -0
  12. package/esm/src/platform/adapters/fs/veryfront/file-list-index.d.ts.map +1 -1
  13. package/esm/src/platform/adapters/fs/veryfront/file-list-index.js +83 -19
  14. package/esm/src/platform/adapters/fs/veryfront/read-operations-helpers.d.ts +5 -0
  15. package/esm/src/platform/adapters/fs/veryfront/read-operations-helpers.d.ts.map +1 -1
  16. package/esm/src/platform/adapters/fs/veryfront/read-operations-helpers.js +6 -0
  17. package/esm/src/platform/adapters/fs/veryfront/read-operations.d.ts.map +1 -1
  18. package/esm/src/platform/adapters/fs/veryfront/read-operations.js +53 -34
  19. package/esm/src/rendering/page-resolution/page-resolver.d.ts.map +1 -1
  20. package/esm/src/rendering/page-resolution/page-resolver.js +10 -4
  21. package/esm/src/transforms/esm/http-cache-wrapper.d.ts +3 -0
  22. package/esm/src/transforms/esm/http-cache-wrapper.d.ts.map +1 -1
  23. package/esm/src/transforms/esm/http-cache-wrapper.js +21 -7
  24. package/esm/src/utils/version.d.ts +1 -1
  25. package/esm/src/utils/version.js +1 -1
  26. package/package.json +1 -1
  27. package/src/deno.js +1 -1
  28. package/src/src/cache/distributed-cache-init.ts +95 -59
  29. package/src/src/cache/module-cache.ts +95 -57
  30. package/src/src/platform/adapters/fs/veryfront/content-metrics.ts +13 -2
  31. package/src/src/platform/adapters/fs/veryfront/file-list-index.ts +101 -18
  32. package/src/src/platform/adapters/fs/veryfront/read-operations-helpers.ts +10 -0
  33. package/src/src/platform/adapters/fs/veryfront/read-operations.ts +87 -30
  34. package/src/src/rendering/page-resolution/page-resolver.ts +17 -6
  35. package/src/src/transforms/esm/http-cache-wrapper.ts +28 -7
  36. package/src/src/utils/version.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"read-operations.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/read-operations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAKnD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAStD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAI9B,MAAM,WAAW,sBAAsB;IACrC,gBAAgB,EAAE,MAAM,OAAO,CAAC;IAChC,YAAY,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAClC,iBAAiB,EAAE,MAAM,sBAAsB,GAAG,IAAI,CAAC;IACvD,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,OAAO,CACzB,KAAK,CAAC;QACJ,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC,GAAG,SAAS,CACf,CAAC;IACF,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,0EAA0E;IAC1E,4BAA4B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAC3D,+CAA+C;IAC/C,yBAAyB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAC5D;AAUD,qBAAa,cAAc;IAWvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC;IACpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IAfpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAI9B;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,mGAAmG;IACnG,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAA6B;gBAGnD,MAAM,EAAE,kBAAkB,EAC1B,KAAK,EAAE,SAAS,EAChB,UAAU,EAAE,cAAc,EAC1B,eAAe,CAAC,EAAE,sBAAsB,YAAA,EACxC,kBAAkB,CAAC,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,aAAA,EAC7C,gBAAgB,CAAC,GAAE,MAAM,OAAO,CAC/C,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,SAAS,CACtD,aAAA;IAKH,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAIrD,kBAAkB,IAAI,IAAI;IAK1B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAY3C,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAY3C,OAAO,CAAC,mBAAmB;YAsBb,+BAA+B;YA0C/B,mBAAmB;IAgDjC,OAAO,CAAC,kBAAkB;YAoFZ,2BAA2B;YA8D3B,uCAAuC;IAmCrD,OAAO,CAAC,oBAAoB;YAgBd,YAAY;YAgGZ,qBAAqB;YA8DrB,qBAAqB;YAgDrB,+BAA+B;YA8D/B,iBAAiB;CAyBhC"}
1
+ {"version":3,"file":"read-operations.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/read-operations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAKnD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAWtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAI9B,MAAM,WAAW,sBAAsB;IACrC,gBAAgB,EAAE,MAAM,OAAO,CAAC;IAChC,YAAY,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAClC,iBAAiB,EAAE,MAAM,sBAAsB,GAAG,IAAI,CAAC;IACvD,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,OAAO,CACzB,KAAK,CAAC;QACJ,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC,GAAG,SAAS,CACf,CAAC;IACF,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,0EAA0E;IAC1E,4BAA4B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAC3D,+CAA+C;IAC/C,yBAAyB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAC5D;AAUD,qBAAa,cAAc;IAWvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC;IACpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IAfpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAI9B;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,mGAAmG;IACnG,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAA6B;gBAGnD,MAAM,EAAE,kBAAkB,EAC1B,KAAK,EAAE,SAAS,EAChB,UAAU,EAAE,cAAc,EAC1B,eAAe,CAAC,EAAE,sBAAsB,YAAA,EACxC,kBAAkB,CAAC,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,aAAA,EAC7C,gBAAgB,CAAC,GAAE,MAAM,OAAO,CAC/C,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,SAAS,CACtD,aAAA;IAKH,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAIrD,kBAAkB,IAAI,IAAI;IAK1B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAY3C,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAY3C,OAAO,CAAC,mBAAmB;YAsBb,+BAA+B;YA0C/B,mBAAmB;IA0CjC,OAAO,CAAC,kBAAkB;YAoFZ,2BAA2B;YA8D3B,uCAAuC;IAmCrD,OAAO,CAAC,oBAAoB;YAgBd,YAAY;YA6JZ,qBAAqB;YA8DrB,qBAAqB;YAgDrB,+BAA+B;YA8D/B,iBAAiB;CAyBhC"}
@@ -4,7 +4,7 @@ import { logContentMetric } from "./content-metrics.js";
4
4
  import { FileListIndex } from "./file-list-index.js";
5
5
  import { InFlightRequestDeduper } from "./in-flight-dedupe.js";
6
6
  import { getRequestScopedFile, setRequestScopedFile } from "./multi-project-adapter.js";
7
- import { assertProjectSourcePath, buildReadFetchState, getResolvedCacheKey, isNotFoundLikeError, READ_OPERATION_EXTENSION_PRIORITY as EXTENSION_PRIORITY, splitKnownFileExtension, } from "./read-operations-helpers.js";
7
+ import { assertProjectSourcePath, buildExtensionCandidatePaths, buildReadFetchState, createNotFoundLikeError, getResolvedCacheKey, isNotFoundLikeError, READ_OPERATION_EXTENSION_PRIORITY as EXTENSION_PRIORITY, splitKnownFileExtension, } from "./read-operations-helpers.js";
8
8
  export { endRequestMetrics, getContentMetricsSnapshot, resetContentMetrics, startRequestMetrics, } from "./content-metrics.js";
9
9
  const logger = baseLogger.component("read-operations");
10
10
  const IN_FLIGHT_REQUEST_TIMEOUT_MS = 15_000;
@@ -113,10 +113,15 @@ export class ReadOperations {
113
113
  // - File list is refreshed on every WebSocket poke (websocket-manager.ts:483-500)
114
114
  // - Request-scoped cache ensures consistency within a single render
115
115
  // - Persistent cache is only written for production mode (to avoid staleness risk in preview)
116
- if (!skipPersistentCaches) {
117
- const fileListContent = await this.fileListIndex.lookup(normalizedPath);
118
- if (!fileListContent)
119
- return null;
116
+ if (skipPersistentCaches) {
117
+ logger.debug("Skipping file list cache due to invalidation", {
118
+ path: normalizedPath,
119
+ cacheKeyPrefix,
120
+ });
121
+ return { status: "unavailable", fresh: false };
122
+ }
123
+ const match = await this.fileListIndex.match(normalizedPath);
124
+ if (match.status === "hit" && match.content) {
120
125
  logContentMetric("FILE_LIST_HIT", {
121
126
  path: normalizedPath,
122
127
  mode: ctx?.sourceType ?? "unknown",
@@ -126,25 +131,13 @@ export class ReadOperations {
126
131
  // Only cache to persistent storage for production mode
127
132
  // Preview mode uses file list cache directly without persisting (fresher, WebSocket-driven)
128
133
  if (isProduction) {
129
- this.cache.set(cacheKey, fileListContent);
134
+ this.cache.set(cacheKey, match.content);
130
135
  }
131
- setRequestScopedFile(cacheKey, fileListContent);
132
- return fileListContent;
136
+ setRequestScopedFile(cacheKey, match.content);
133
137
  }
134
- // Skip only happens during cache invalidation (both preview and production)
135
- logContentMetric("CACHE_MISS", {
136
- path: normalizedPath,
137
- mode: ctx?.sourceType ?? "unknown",
138
- missReason: "invalidation",
139
- isPreviewMode,
140
- });
141
- logger.debug("Skipping file list cache due to invalidation", {
142
- path: normalizedPath,
143
- cacheKeyPrefix,
144
- });
145
- return null;
138
+ return match;
146
139
  }
147
- setupInFlightFetch(normalizedPath, apiPath, cacheKey, isPublished, isProduction, isPreviewMode, ctx) {
140
+ setupInFlightFetch(normalizedPath, apiPath, cacheKey, isPublished, isProduction, isPreviewMode, ctx, missReason) {
148
141
  const cleanupResult = this.inFlightRequests.cleanup();
149
142
  if (cleanupResult) {
150
143
  logger.warn("Cleaned up in-flight requests", cleanupResult);
@@ -159,11 +152,10 @@ export class ReadOperations {
159
152
  return existingEntry.promise;
160
153
  }
161
154
  // Track why we're making a network fetch (for optimization analysis)
162
- const hasFileListCache = !!this.getFileListCache;
163
155
  logContentMetric("CACHE_MISS", {
164
156
  path: normalizedPath,
165
157
  mode: ctx?.sourceType ?? "unknown",
166
- missReason: (hasFileListCache ? "not_in_filelist" : "no_filelist_cache"),
158
+ missReason,
167
159
  isPreviewMode,
168
160
  });
169
161
  // THIS IS A NETWORK FETCH - every call here = API round trip
@@ -248,10 +240,10 @@ export class ReadOperations {
248
240
  }
249
241
  }
250
242
  async tryResolveExtensionlessPathFromFileList(normalizedPath, cacheKeyPrefix, cacheKey, isProduction, ctx, isPreviewMode) {
251
- const candidatePaths = EXTENSION_PRIORITY.map((ext) => `${normalizedPath}${ext}`);
252
- const resolved = await this.fileListIndex.findFirstWithContent(candidatePaths);
253
- if (!resolved)
254
- return null;
243
+ const candidatePaths = buildExtensionCandidatePaths(normalizedPath);
244
+ const resolved = await this.fileListIndex.findFirstMatch(candidatePaths);
245
+ if (resolved.status !== "hit" || !resolved.path || !resolved.content)
246
+ return resolved;
255
247
  const resolvedCacheKey = getResolvedCacheKey(cacheKeyPrefix, resolved.path);
256
248
  this.extensionResolutionCache.set(normalizedPath, resolved.path);
257
249
  logContentMetric("FILE_LIST_HIT", {
@@ -268,7 +260,7 @@ export class ReadOperations {
268
260
  resolvedCacheKey: resolvedCacheKey === cacheKey ? undefined : resolvedCacheKey,
269
261
  });
270
262
  this.cacheResolvedContent(cacheKey, resolvedCacheKey, resolved.content, isProduction);
271
- return resolved.content;
263
+ return resolved;
272
264
  }
273
265
  cacheResolvedContent(cacheKey, resolvedCacheKey, content, persistToCache) {
274
266
  if (persistToCache) {
@@ -309,20 +301,47 @@ export class ReadOperations {
309
301
  const persistentCached = await this.getProductionPersistentCacheHit(normalizedPath, cacheKeyPrefix, cacheKey, isProduction, skipPersistentCaches, currentReleaseId, isPrefixInvalidated, ctx);
310
302
  if (persistentCached)
311
303
  return persistentCached;
312
- const fileListCached = await this.getFileListCacheHit(normalizedPath, cacheKeyPrefix, cacheKey, isProduction, skipPersistentCaches, isPreviewMode, ctx);
313
- if (fileListCached)
314
- return fileListCached;
304
+ const fileListMatch = await this.getFileListCacheHit(normalizedPath, cacheKeyPrefix, cacheKey, isProduction, skipPersistentCaches, isPreviewMode, ctx);
305
+ if (fileListMatch.status === "hit" && fileListMatch.content)
306
+ return fileListMatch.content;
307
+ if (fileListMatch.status === "present_without_content") {
308
+ return this.setupInFlightFetch(normalizedPath, apiPath, cacheKey, isPublished, isProduction, isPreviewMode, ctx, "indexed_without_content");
309
+ }
315
310
  if (!hasKnownExt) {
316
311
  if (!skipPersistentCaches) {
317
312
  const resolvedFromFileList = await this.tryResolveExtensionlessPathFromFileList(normalizedPath, cacheKeyPrefix, cacheKey, isProduction, ctx, isPreviewMode);
318
- if (resolvedFromFileList)
319
- return resolvedFromFileList;
313
+ if (resolvedFromFileList.status === "hit" && resolvedFromFileList.content) {
314
+ return resolvedFromFileList.content;
315
+ }
316
+ if (resolvedFromFileList.status === "present_without_content" &&
317
+ resolvedFromFileList.path) {
318
+ const resolvedCacheKey = getResolvedCacheKey(cacheKeyPrefix, resolvedFromFileList.path);
319
+ const resolvedApiPath = this.getOriginalApiPath?.(resolvedFromFileList.path) ??
320
+ resolvedFromFileList.path;
321
+ const fetchedResolved = await this.setupInFlightFetch(resolvedFromFileList.path, resolvedApiPath, resolvedCacheKey, isPublished, isProduction, isPreviewMode, ctx, "indexed_without_content");
322
+ this.extensionResolutionCache.set(normalizedPath, resolvedFromFileList.path);
323
+ this.cacheResolvedContent(cacheKey, resolvedCacheKey, fetchedResolved, isProduction && !skipPersistentCaches);
324
+ return fetchedResolved;
325
+ }
326
+ if (fileListMatch.status === "missing" &&
327
+ fileListMatch.fresh &&
328
+ resolvedFromFileList.status === "missing" &&
329
+ resolvedFromFileList.fresh) {
330
+ throw createNotFoundLikeError(normalizedPath);
331
+ }
320
332
  }
321
333
  const resolved = await this.tryResolveExtensionlessPath(apiPath, cacheKeyPrefix, cacheKey, isProduction, skipPersistentCaches);
322
334
  if (resolved)
323
335
  return resolved;
324
336
  }
325
- return this.setupInFlightFetch(normalizedPath, apiPath, cacheKey, isPublished, isProduction, isPreviewMode, ctx);
337
+ if (fileListMatch.status === "missing" && fileListMatch.fresh) {
338
+ throw createNotFoundLikeError(normalizedPath);
339
+ }
340
+ return this.setupInFlightFetch(normalizedPath, apiPath, cacheKey, isPublished, isProduction, isPreviewMode, ctx, skipPersistentCaches
341
+ ? "invalidation"
342
+ : fileListMatch.status === "missing" && fileListMatch.fresh
343
+ ? "not_in_filelist"
344
+ : "no_filelist_cache");
326
345
  }
327
346
  async fetchPublishedContent(normalizedPath, apiPath, cacheKey, releaseId, environmentName, shouldCache) {
328
347
  logger.debug("Fetching published content", {
@@ -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;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"}
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;IAiExC,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"}
@@ -56,10 +56,16 @@ export class PageResolver {
56
56
  }
57
57
  }
58
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/.
61
- pageInfo = await getAppRouteEntity(this.projectDir, slug, this.adapter, appDirName);
62
- if (!pageInfo) {
59
+ // Auto mode stays structural: detect the dominant router once, then keep
60
+ // pages fallback available for mixed or in-transition projects.
61
+ const useAppRouter = await detectAppRouter(this.projectDir, this.config, this.adapter, { projectId: this.projectId });
62
+ if (useAppRouter) {
63
+ pageInfo = await getAppRouteEntity(this.projectDir, slug, this.adapter, appDirName);
64
+ if (!pageInfo) {
65
+ pageInfo = await getEntityBySlug(this.projectDir, slug, this.adapter);
66
+ }
67
+ }
68
+ else {
63
69
  pageInfo = await getEntityBySlug(this.projectDir, slug, this.adapter);
64
70
  }
65
71
  }
@@ -10,8 +10,11 @@
10
10
  *
11
11
  * @module transforms/esm/http-cache-wrapper
12
12
  */
13
+ import type { CacheBackend } from "../../cache/types.js";
13
14
  import type { BundleHash, LocalModuleCode, NormalizedUrl, PortableModuleCode } from "./http-cache-types.js";
14
15
  import { asBundleHash } from "./http-cache-invariants.js";
16
+ export declare function __setDistributedCacheAccessorForTests(accessor: (() => Promise<CacheBackend | null>) | null): void;
17
+ export declare function initializeHttpModuleDistributedCache(): Promise<boolean>;
15
18
  /**
16
19
  * Tokenize local code paths to portable format.
17
20
  * Replaces absolute cache directory paths with __VF_CACHE_DIR__ tokens.
@@ -1 +1 @@
1
- {"version":3,"file":"http-cache-wrapper.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/http-cache-wrapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAQH,OAAO,KAAK,EACV,UAAU,EAEV,eAAe,EACf,aAAa,EACb,kBAAkB,EACnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,YAAY,EAKb,MAAM,4BAA4B,CAAC;AAuBpC;;;;;;GAMG;AACH,iBAAS,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,kBAAkB,CAoB3D;AAED;;;GAGG;AACH,iBAAS,UAAU,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,GAAG,eAAe,CAMtE;AAmCD;;GAEG;AACH,UAAU,aAAa;IACrB,wEAAwE;IACxE,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IAC7B,uDAAuD;IACvD,UAAU,EAAE,OAAO,CAAC;IACpB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,WAAW,GAAG,oBAAoB,GAAG,cAAc,GAAG,OAAO,CAAC;CAC5E;AAED;;;;;;;;;GASG;AACH,cAAM,eAAe;IACnB;;;;;;OAMG;IACG,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAiDtE;;;;;;OAMG;IACG,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAqCrE;;;;;;;;OAQG;IACG,OAAO,CACX,IAAI,EAAE,UAAU,GAAG,MAAM,EACzB,IAAI,EAAE,eAAe,EACrB,GAAG,EAAE,aAAa,GAAG,MAAM,EAC3B,GAAG,GAAE,MAAwC,GAC5C,OAAO,CAAC,IAAI,CAAC;IA+BhB;;;;;;OAMG;IACG,aAAa,CACjB,MAAM,EAAE,KAAK,CAAC,UAAU,GAAG,MAAM,CAAC,GACjC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IA8CxC;;;;;OAKG;IACG,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAcvE;;;;;;OAMG;IACG,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsB7D;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAItC;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,iBAAwB,CAAC;AAErD;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC"}
1
+ {"version":3,"file":"http-cache-wrapper.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/http-cache-wrapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,KAAK,EACV,UAAU,EAEV,eAAe,EACf,aAAa,EACb,kBAAkB,EACnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,YAAY,EAKb,MAAM,4BAA4B,CAAC;AAoBpC,wBAAgB,qCAAqC,CACnD,QAAQ,EAAE,CAAC,MAAM,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,GACpD,IAAI,CAEN;AAED,wBAAsB,oCAAoC,IAAI,OAAO,CAAC,OAAO,CAAC,CAM7E;AAWD;;;;;;GAMG;AACH,iBAAS,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,kBAAkB,CAoB3D;AAED;;;GAGG;AACH,iBAAS,UAAU,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,GAAG,eAAe,CAMtE;AAmCD;;GAEG;AACH,UAAU,aAAa;IACrB,wEAAwE;IACxE,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IAC7B,uDAAuD;IACvD,UAAU,EAAE,OAAO,CAAC;IACpB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,WAAW,GAAG,oBAAoB,GAAG,cAAc,GAAG,OAAO,CAAC;CAC5E;AAED;;;;;;;;;GASG;AACH,cAAM,eAAe;IACnB;;;;;;OAMG;IACG,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAiDtE;;;;;;OAMG;IACG,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAqCrE;;;;;;;;OAQG;IACG,OAAO,CACX,IAAI,EAAE,UAAU,GAAG,MAAM,EACzB,IAAI,EAAE,eAAe,EACrB,GAAG,EAAE,aAAa,GAAG,MAAM,EAC3B,GAAG,GAAE,MAAwC,GAC5C,OAAO,CAAC,IAAI,CAAC;IA+BhB;;;;;;OAMG;IACG,aAAa,CACjB,MAAM,EAAE,KAAK,CAAC,UAAU,GAAG,MAAM,CAAC,GACjC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IA8CxC;;;;;OAKG;IACG,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAcvE;;;;;;OAMG;IACG,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsB7D;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAItC;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,iBAAwB,CAAC;AAErD;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC"}
@@ -23,6 +23,20 @@ const logger = rendererLogger.component("http-cache-wrapper");
23
23
  const BATCH_FETCH_CHUNK_SIZE = 100;
24
24
  /** Lazy-loaded distributed cache backend for cross-pod sharing */
25
25
  const getDistributedCache = createDistributedCacheAccessor(() => CacheBackends.httpModule(), "HTTP-CACHE-WRAPPER");
26
+ let testDistributedCacheAccessor = null;
27
+ function resolveDistributedCache() {
28
+ return testDistributedCacheAccessor ? testDistributedCacheAccessor() : getDistributedCache();
29
+ }
30
+ export function __setDistributedCacheAccessorForTests(accessor) {
31
+ testDistributedCacheAccessor = accessor;
32
+ }
33
+ export async function initializeHttpModuleDistributedCache() {
34
+ const distributed = await resolveDistributedCache();
35
+ if (!distributed)
36
+ return false;
37
+ logger.info("Initialized distributed cache backend", { backend: distributed.type });
38
+ return true;
39
+ }
26
40
  /**
27
41
  * Generate versioned cache key for HTTP bundles.
28
42
  * Format: {VERSION}:{prefix}:{hash}
@@ -110,7 +124,7 @@ class HttpBundleCache {
110
124
  * @returns Result containing local code or failure reason
111
125
  */
112
126
  async getCodeByHash(hash) {
113
- const distributed = await getDistributedCache();
127
+ const distributed = await resolveDistributedCache();
114
128
  if (!distributed) {
115
129
  return { code: null, wasGzipped: false, failReason: "not_found" };
116
130
  }
@@ -160,7 +174,7 @@ class HttpBundleCache {
160
174
  * @returns Result containing local code or failure reason
161
175
  */
162
176
  async getCodeByUrl(hash) {
163
- const distributed = await getDistributedCache();
177
+ const distributed = await resolveDistributedCache();
164
178
  if (!distributed) {
165
179
  return { code: null, wasGzipped: false, failReason: "not_found" };
166
180
  }
@@ -200,7 +214,7 @@ class HttpBundleCache {
200
214
  * @param ttl - TTL in seconds (defaults to HTTP_MODULE_DISTRIBUTED_TTL_SEC)
201
215
  */
202
216
  async setCode(hash, code, url, ttl = HTTP_MODULE_DISTRIBUTED_TTL_SEC) {
203
- const distributed = await getDistributedCache();
217
+ const distributed = await resolveDistributedCache();
204
218
  if (!distributed)
205
219
  return;
206
220
  const hashStr = typeof hash === "string" ? hash : hash;
@@ -233,7 +247,7 @@ class HttpBundleCache {
233
247
  * @returns Map of hash -> local code (missing/failed hashes not included)
234
248
  */
235
249
  async getBatchCodes(hashes) {
236
- const distributed = await getDistributedCache();
250
+ const distributed = await resolveDistributedCache();
237
251
  if (!distributed)
238
252
  return new Map();
239
253
  const results = new Map();
@@ -278,7 +292,7 @@ class HttpBundleCache {
278
292
  * @returns Original URL or null
279
293
  */
280
294
  async getOriginalUrl(hash) {
281
- const distributed = await getDistributedCache();
295
+ const distributed = await resolveDistributedCache();
282
296
  if (!distributed)
283
297
  return null;
284
298
  const hashStr = typeof hash === "string" ? hash : hash;
@@ -298,7 +312,7 @@ class HttpBundleCache {
298
312
  * @returns true if deletion was attempted, false if cache unavailable
299
313
  */
300
314
  async deleteCode(hash) {
301
- const distributed = await getDistributedCache();
315
+ const distributed = await resolveDistributedCache();
302
316
  if (!distributed)
303
317
  return false;
304
318
  const hashStr = typeof hash === "string" ? hash : hash;
@@ -321,7 +335,7 @@ class HttpBundleCache {
321
335
  * Check if distributed cache is available.
322
336
  */
323
337
  async isAvailable() {
324
- const distributed = await getDistributedCache();
338
+ const distributed = await resolveDistributedCache();
325
339
  return distributed !== null;
326
340
  }
327
341
  }
@@ -1,4 +1,4 @@
1
- export declare const VERSION = "0.1.59";
1
+ export declare const VERSION = "0.1.88";
2
2
  export declare const SERVER_START_TIME: number;
3
3
  export interface BuildVersion {
4
4
  framework: string;
@@ -1,6 +1,6 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.59";
3
+ export const VERSION = "0.1.88";
4
4
  export const SERVER_START_TIME = Date.now();
5
5
  export function createBuildVersion(projectUpdatedAt) {
6
6
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.86",
3
+ "version": "0.1.88",
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.86",
3
+ "version": "0.1.88",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -1,6 +1,7 @@
1
1
  import { initializeFileCacheBackend } from "../platform/adapters/fs/cache/file-cache.js";
2
2
  import { initializeSSRDistributedCache } from "../modules/react-loader/ssr-module-loader/index.js";
3
3
  import { initializeTransformCache } from "../transforms/esm/transform-cache.js";
4
+ import { initializeHttpModuleDistributedCache } from "../transforms/esm/http-cache-wrapper.js";
4
5
  import { SpanNames } from "../observability/tracing/span-names.js";
5
6
  import { withSpan } from "../observability/tracing/otlp-setup.js";
6
7
  import { initializeProjectCSSCache } from "../html/styles-builder/tailwind-compiler.js";
@@ -16,8 +17,25 @@ interface DistributedCacheStatus {
16
17
  ssrModuleCache: boolean;
17
18
  fileCache: boolean;
18
19
  projectCSSCache: boolean;
20
+ httpModuleCache: boolean;
19
21
  }
20
22
 
23
+ type DistributedCacheInitializers = {
24
+ transformCache: () => Promise<boolean>;
25
+ ssrModuleCache: () => Promise<boolean>;
26
+ fileCache: () => Promise<boolean>;
27
+ projectCSSCache: () => Promise<boolean>;
28
+ httpModuleCache: () => Promise<boolean>;
29
+ };
30
+
31
+ const defaultInitializers: DistributedCacheInitializers = {
32
+ transformCache: initializeTransformCache,
33
+ ssrModuleCache: initializeSSRDistributedCache,
34
+ fileCache: initializeFileCacheBackend,
35
+ projectCSSCache: initializeProjectCSSCache,
36
+ httpModuleCache: initializeHttpModuleDistributedCache,
37
+ };
38
+
21
39
  function determineBackend(): DistributedCacheStatus["backend"] {
22
40
  if (isApiCacheAvailable()) return "api";
23
41
  if (isRedisConfigured()) return "redis";
@@ -29,6 +47,81 @@ function wasSuccessful(result: PromiseSettledResult<boolean>): boolean {
29
47
  return result.status === "fulfilled" && result.value;
30
48
  }
31
49
 
50
+ async function initializeDistributedCachesWithInitializers(
51
+ backend: DistributedCacheStatus["backend"],
52
+ initializers: DistributedCacheInitializers,
53
+ ): Promise<DistributedCacheStatus> {
54
+ logger.info("Initializing caches...", { backend });
55
+
56
+ const cacheNames = [
57
+ "transformCache",
58
+ "ssrModuleCache",
59
+ "fileCache",
60
+ "projectCSSCache",
61
+ "httpModuleCache",
62
+ ] as const;
63
+ const results = await Promise.allSettled([
64
+ initializers.transformCache(),
65
+ initializers.ssrModuleCache(),
66
+ initializers.fileCache(),
67
+ initializers.projectCSSCache(),
68
+ initializers.httpModuleCache(),
69
+ ]);
70
+
71
+ for (let i = 0; i < results.length; i++) {
72
+ const result = results[i];
73
+ if (result && result.status === "rejected") {
74
+ logger.error(`Cache initialization failed: ${cacheNames[i]}`, {
75
+ backend,
76
+ error: result.reason instanceof Error ? result.reason.message : String(result.reason),
77
+ });
78
+ }
79
+ }
80
+
81
+ const status: DistributedCacheStatus = {
82
+ backend,
83
+ transformCache: wasSuccessful(results[0]),
84
+ ssrModuleCache: wasSuccessful(results[1]),
85
+ fileCache: wasSuccessful(results[2]),
86
+ projectCSSCache: wasSuccessful(results[3]),
87
+ httpModuleCache: wasSuccessful(results[4]),
88
+ };
89
+
90
+ const enabled = [
91
+ status.transformCache,
92
+ status.ssrModuleCache,
93
+ status.fileCache,
94
+ status.projectCSSCache,
95
+ status.httpModuleCache,
96
+ ].filter(Boolean).length;
97
+
98
+ if (enabled === 0) {
99
+ logger.warn("No caches enabled despite backend being available", {
100
+ backend,
101
+ });
102
+ return status;
103
+ }
104
+
105
+ logger.info("Initialization complete", {
106
+ backend,
107
+ enabled,
108
+ transform: status.transformCache,
109
+ ssrModule: status.ssrModuleCache,
110
+ file: status.fileCache,
111
+ projectCSS: status.projectCSSCache,
112
+ httpModule: status.httpModuleCache,
113
+ });
114
+
115
+ return status;
116
+ }
117
+
118
+ export function __runDistributedCacheInitializationForTests(
119
+ backend: DistributedCacheStatus["backend"],
120
+ initializers: DistributedCacheInitializers,
121
+ ): Promise<DistributedCacheStatus> {
122
+ return initializeDistributedCachesWithInitializers(backend, initializers);
123
+ }
124
+
32
125
  export function initializeDistributedCaches(): Promise<DistributedCacheStatus> {
33
126
  const backend = determineBackend();
34
127
 
@@ -39,70 +132,13 @@ export function initializeDistributedCaches(): Promise<DistributedCacheStatus> {
39
132
  ssrModuleCache: false,
40
133
  fileCache: false,
41
134
  projectCSSCache: false,
135
+ httpModuleCache: false,
42
136
  });
43
137
  }
44
138
 
45
139
  return withSpan(
46
140
  SpanNames.CACHE_DISTRIBUTED_INIT,
47
- async (): Promise<DistributedCacheStatus> => {
48
- logger.info("Initializing caches...", { backend });
49
-
50
- const cacheNames = [
51
- "transformCache",
52
- "ssrModuleCache",
53
- "fileCache",
54
- "projectCSSCache",
55
- ] as const;
56
- const results = await Promise.allSettled([
57
- initializeTransformCache(),
58
- initializeSSRDistributedCache(),
59
- initializeFileCacheBackend(),
60
- initializeProjectCSSCache(),
61
- ]);
62
-
63
- for (let i = 0; i < results.length; i++) {
64
- const result = results[i];
65
- if (result && result.status === "rejected") {
66
- logger.error(`Cache initialization failed: ${cacheNames[i]}`, {
67
- backend,
68
- error: result.reason instanceof Error ? result.reason.message : String(result.reason),
69
- });
70
- }
71
- }
72
-
73
- const status: DistributedCacheStatus = {
74
- backend,
75
- transformCache: wasSuccessful(results[0]),
76
- ssrModuleCache: wasSuccessful(results[1]),
77
- fileCache: wasSuccessful(results[2]),
78
- projectCSSCache: wasSuccessful(results[3]),
79
- };
80
-
81
- const enabled = [
82
- status.transformCache,
83
- status.ssrModuleCache,
84
- status.fileCache,
85
- status.projectCSSCache,
86
- ].filter(Boolean).length;
87
-
88
- if (enabled === 0) {
89
- logger.warn("No caches enabled despite backend being available", {
90
- backend,
91
- });
92
- return status;
93
- }
94
-
95
- logger.info("Initialization complete", {
96
- backend,
97
- enabled,
98
- transform: status.transformCache,
99
- ssrModule: status.ssrModuleCache,
100
- file: status.fileCache,
101
- projectCSS: status.projectCSSCache,
102
- });
103
-
104
- return status;
105
- },
141
+ () => initializeDistributedCachesWithInitializers(backend, defaultInitializers),
106
142
  { "cache.backend": backend },
107
143
  );
108
144
  }