veryfront 0.1.742 → 0.1.744

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.742",
3
+ "version": "0.1.744",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "minimumDependencyAge": "P2D",
@@ -0,0 +1,33 @@
1
+ /**************************
2
+ * Standardized Cache Hashing Utilities
3
+ *
4
+ * Provides consistent hashing for cache keys across the codebase.
5
+ * All cache keys should use these utilities to ensure:
6
+ * - Consistent format with type prefixes
7
+ * - Collision resistance between different cache types
8
+ * - Easy debugging and key parsing
9
+ *
10
+ * Key format: `{type}:{hash}` or `{type}:{version}:{hash}`
11
+ *
12
+ * @module cache/hash
13
+ **************************/
14
+ import { computeHash } from "../utils/hash-utils.js";
15
+ type CacheKeyType = "http" | "mod" | "esm" | "render" | "mdx" | "css" | "file" | "config";
16
+ export declare function fastHash(input: string): number;
17
+ export declare function hashToString(hash: number): string;
18
+ export declare function hashString(input: string): string;
19
+ export declare function getCacheKey(type: CacheKeyType, input: string): string;
20
+ export declare function getVersionedCacheKey(type: CacheKeyType, version: number | string, input: string): string;
21
+ export declare function getCompoundCacheKey(type: CacheKeyType, components: string[]): string;
22
+ export declare function parseCacheKey(key: string): {
23
+ type: string;
24
+ hash: string;
25
+ version?: string;
26
+ } | null;
27
+ export declare const sha256Hash: typeof computeHash;
28
+ export declare function sha256Short(input: string): Promise<string>;
29
+ export declare function getHttpBundleFilename(normalizedUrl: string): string;
30
+ export declare function parseHttpBundleFilename(filename: string): string | null;
31
+ export declare function isCacheKey(value: string): boolean;
32
+ export {};
33
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../../src/src/cache/hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;4BAY4B;AAE5B,OAAO,EAAE,WAAW,EAAc,MAAM,wBAAwB,CAAC;AAEjE,KAAK,YAAY,GACb,MAAM,GACN,KAAK,GACL,KAAK,GACL,QAAQ,GACR,KAAK,GACL,KAAK,GACL,MAAM,GACN,QAAQ,CAAC;AAEb,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ9C;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,KAAK,EAAE,MAAM,GACZ,MAAM,CAER;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAEpF;AAED,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,GACV;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAWzD;AAED,eAAO,MAAM,UAAU,oBAAc,CAAC;AAEtC,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEhE;AAED,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEvE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEjD"}
@@ -0,0 +1,59 @@
1
+ /**************************
2
+ * Standardized Cache Hashing Utilities
3
+ *
4
+ * Provides consistent hashing for cache keys across the codebase.
5
+ * All cache keys should use these utilities to ensure:
6
+ * - Consistent format with type prefixes
7
+ * - Collision resistance between different cache types
8
+ * - Easy debugging and key parsing
9
+ *
10
+ * Key format: `{type}:{hash}` or `{type}:{version}:{hash}`
11
+ *
12
+ * @module cache/hash
13
+ **************************/
14
+ import { computeHash, simpleHash } from "../utils/hash-utils.js";
15
+ export function fastHash(input) {
16
+ let hash = 5381;
17
+ for (let i = 0; i < input.length; i++) {
18
+ hash = ((hash << 5) + hash) ^ input.charCodeAt(i);
19
+ }
20
+ return hash >>> 0;
21
+ }
22
+ export function hashToString(hash) {
23
+ return hash.toString(36);
24
+ }
25
+ export function hashString(input) {
26
+ return hashToString(fastHash(input));
27
+ }
28
+ export function getCacheKey(type, input) {
29
+ return `${type}:${hashString(input)}`;
30
+ }
31
+ export function getVersionedCacheKey(type, version, input) {
32
+ return `${type}:v${version}:${hashString(input)}`;
33
+ }
34
+ export function getCompoundCacheKey(type, components) {
35
+ return getCacheKey(type, components.join(":"));
36
+ }
37
+ export function parseCacheKey(key) {
38
+ const [type, ...rest] = key.split(":");
39
+ if (!type || rest.length === 0)
40
+ return null;
41
+ const [maybeVersion, ...hashParts] = rest;
42
+ if (maybeVersion?.startsWith("v") && /^v\d+$/.test(maybeVersion)) {
43
+ return { type, version: maybeVersion.slice(1), hash: hashParts.join(":") };
44
+ }
45
+ return { type, hash: rest.join(":") };
46
+ }
47
+ export const sha256Hash = computeHash;
48
+ export async function sha256Short(input) {
49
+ return (await sha256Hash(input)).slice(0, 8);
50
+ }
51
+ export function getHttpBundleFilename(normalizedUrl) {
52
+ return `http-${simpleHash(normalizedUrl)}.mjs`;
53
+ }
54
+ export function parseHttpBundleFilename(filename) {
55
+ return filename.match(/^http-(\d+)\.mjs$/)?.[1] ?? null;
56
+ }
57
+ export function isCacheKey(value) {
58
+ return /^[a-z]+:[a-z0-9]+/.test(value);
59
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"module-batch-handler.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-batch-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAqDtE,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA2K/F;AA2JD;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAY1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAKrE"}
1
+ {"version":3,"file":"module-batch-handler.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-batch-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AA2DtE,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA2K/F;AAkPD;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAY1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAKrE"}
@@ -20,12 +20,13 @@ import { createSecureFs } from "../../security/index.js";
20
20
  import { transformToESM } from "../../transforms/esm-transform.js";
21
21
  import { createFileSystem } from "../../platform/compat/fs.js";
22
22
  import { join } from "../../platform/compat/path/index.js";
23
- import { applySSRImportRewrites } from "./ssr-import-rewriter.js";
23
+ import { applySSRImportRewritesAsync, resolveSSRImportTargetModulePath, stripSSRModuleJsExtension, } from "./ssr-import-rewriter.js";
24
24
  import { buildModuleTransformCacheKey } from "../../cache/keys.js";
25
25
  import { withSpan } from "../../observability/tracing/otlp-setup.js";
26
26
  import { getFrameworkRootFromMeta } from "../../platform/compat/vfs-paths.js";
27
27
  import { LRUCache } from "../../utils/lru-wrapper.js";
28
28
  import { registerLRUCache } from "../../cache/index.js";
29
+ import { sha256Short } from "../../cache/hash.js";
29
30
  const logger = serverLogger.component("module-batch");
30
31
  /** Slow request threshold in milliseconds */
31
32
  const SLOW_REQUEST_THRESHOLD_MS = 500;
@@ -202,7 +203,7 @@ async function loadAndTransformModule(modulePath, projectDir, adapter, secureFs,
202
203
  if (!stat.isFile)
203
204
  continue;
204
205
  const source = await secureFs.readFile(fullPath);
205
- return transformModule(source, fullPath, projectDir, adapter, options);
206
+ return transformModule(source, fullPath, modulePath, projectDir, adapter, secureFs, options);
206
207
  }
207
208
  catch (_) {
208
209
  /* expected: file may not exist at this extension */
@@ -224,7 +225,7 @@ async function loadAndTransformModule(modulePath, projectDir, adapter, secureFs,
224
225
  if (!stat.isFile)
225
226
  continue;
226
227
  const source = await platformFs.readTextFile(frameworkPath);
227
- return transformModule(source, frameworkPath, projectDir, adapter, options);
228
+ return transformModule(source, frameworkPath, modulePath, projectDir, adapter, secureFs, options);
228
229
  }
229
230
  catch (_) {
230
231
  /* expected: framework file may not exist at this extension */
@@ -233,7 +234,7 @@ async function loadAndTransformModule(modulePath, projectDir, adapter, secureFs,
233
234
  }
234
235
  return null;
235
236
  }
236
- async function transformModule(source, sourceFile, projectDir, adapter, options) {
237
+ async function transformModule(source, sourceFile, modulePath, projectDir, adapter, secureFs, options) {
237
238
  let code = await transformToESM(source, sourceFile, projectDir, adapter, {
238
239
  projectId: options.projectId ?? projectDir,
239
240
  dev: options.dev,
@@ -241,13 +242,75 @@ async function transformModule(source, sourceFile, projectDir, adapter, options)
241
242
  reactVersion: options.reactVersion,
242
243
  });
243
244
  if (options.ssr) {
244
- code = applySSRImportRewrites(code, {
245
+ code = await applySSRImportRewritesAsync(code, {
245
246
  projectSlug: options.projectSlug,
246
247
  branch: options.branch,
248
+ resolveCacheBuster: createBatchSSRTargetCacheBusterResolver({
249
+ projectDir,
250
+ secureFs,
251
+ currentModulePath: modulePath,
252
+ }),
247
253
  });
248
254
  }
249
255
  return code;
250
256
  }
257
+ async function readBatchTargetSource(projectDir, secureFs, modulePath) {
258
+ const basePath = stripSSRModuleJsExtension(modulePath);
259
+ for (const ext of EXTENSIONS) {
260
+ const fullPath = join(projectDir, basePath + ext);
261
+ try {
262
+ const stat = await secureFs.stat(fullPath);
263
+ if (!stat.isFile)
264
+ continue;
265
+ return {
266
+ path: fullPath,
267
+ source: await secureFs.readFile(fullPath),
268
+ };
269
+ }
270
+ catch (_) {
271
+ /* expected: file may not exist at this extension */
272
+ }
273
+ }
274
+ if (!basePath.startsWith("lib/"))
275
+ return null;
276
+ const frameworkLookupDirs = [EMBEDDED_SRC_DIR, join(FRAMEWORK_ROOT, "src")];
277
+ const platformFs = createFileSystem();
278
+ for (const lookupDir of frameworkLookupDirs) {
279
+ for (const ext of FRAMEWORK_EXTENSIONS) {
280
+ const frameworkPath = join(lookupDir, basePath + ext);
281
+ try {
282
+ const stat = await platformFs.stat(frameworkPath);
283
+ if (!stat.isFile)
284
+ continue;
285
+ return {
286
+ path: frameworkPath,
287
+ source: await platformFs.readTextFile(frameworkPath),
288
+ };
289
+ }
290
+ catch (_) {
291
+ /* expected: framework file may not exist at this extension */
292
+ }
293
+ }
294
+ }
295
+ return null;
296
+ }
297
+ function createBatchSSRTargetCacheBusterResolver(options) {
298
+ const versions = new Map();
299
+ return (target) => {
300
+ const targetPath = resolveSSRImportTargetModulePath(target, options.currentModulePath);
301
+ let promise = versions.get(targetPath);
302
+ if (!promise) {
303
+ promise = (async () => {
304
+ const resolved = await readBatchTargetSource(options.projectDir, options.secureFs, targetPath);
305
+ if (!resolved)
306
+ return undefined;
307
+ return await sha256Short(`${resolved.path}\0${resolved.source}`);
308
+ })();
309
+ versions.set(targetPath, promise);
310
+ }
311
+ return promise;
312
+ };
313
+ }
251
314
  /**
252
315
  * Generate the batch bundle code
253
316
  * Creates a module that exports all loaded modules by path
@@ -1 +1 @@
1
- {"version":3,"file":"module-server.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-server.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAG5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAuBtE;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAsDrD,CAAC;AAQF,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,uBAAuB;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA0TzF;AA+PD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGrD"}
1
+ {"version":3,"file":"module-server.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-server.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAG5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AA6BtE;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAsDrD,CAAC;AAQF,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,uBAAuB;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAkVzF;AAgTD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGrD"}
@@ -11,11 +11,12 @@ import { getApiBaseUrlEnv } from "../../config/env.js";
11
11
  import { injectContext, withSpan } from "../../observability/tracing/otlp-setup.js";
12
12
  import { injectNodePositions } from "../../transforms/plugins/babel-node-positions.js";
13
13
  import { parseProjectDomain } from "../../server/utils/domain-parser.js";
14
- import { applySSRImportRewrites } from "./ssr-import-rewriter.js";
14
+ import { applySSRImportRewritesAsync, resolveSSRImportTargetModulePath, stripSSRModuleJsExtension, } from "./ssr-import-rewriter.js";
15
15
  import { addHMRTimestamps } from "../../transforms/esm/import-rewriter.js";
16
16
  import { FRAMEWORK_ROOT, resolveFrameworkSourcePath, } from "../../platform/compat/framework-source-resolver.js";
17
17
  import { getReactUrls, REACT_DEFAULT_VERSION } from "../../utils/constants/cdn.js";
18
18
  import { readLimitedCrossProjectSource } from "./cross-project-source-limit.js";
19
+ import { sha256Short } from "../../cache/hash.js";
19
20
  const logger = serverLogger.component("module-server");
20
21
  /**
21
22
  * Embedded polyfills for compiled Deno binaries.
@@ -153,9 +154,15 @@ export function serveModule(req, options) {
153
154
  try {
154
155
  let transformedCode = await transformToESM(snippetCode, `_snippets/${hash}.tsx`, projectDir, adapter, { projectId: effectiveProjectId, dev, ssr: isSSR, reactVersion });
155
156
  if (isSSR) {
156
- transformedCode = applySSRImportRewrites(transformedCode, {
157
+ transformedCode = await applySSRImportRewritesAsync(transformedCode, {
157
158
  projectSlug: snippetProjectSlug,
158
159
  branch: snippetBranch,
160
+ resolveCacheBuster: createSSRTargetCacheBusterResolver({
161
+ secureFs,
162
+ projectDir,
163
+ currentModulePath: `_snippets/${hash}.js`,
164
+ reactVersion,
165
+ }),
159
166
  });
160
167
  }
161
168
  logger.debug("Snippet transformed", {
@@ -215,7 +222,16 @@ export function serveModule(req, options) {
215
222
  reactVersion,
216
223
  });
217
224
  if (isSSR) {
218
- code = applySSRImportRewrites(code, { crossProjectRef: projectRef });
225
+ code = await applySSRImportRewritesAsync(code, {
226
+ crossProjectRef: projectRef,
227
+ resolveCacheBuster: createSSRTargetCacheBusterResolver({
228
+ secureFs,
229
+ projectDir,
230
+ currentModulePath: crossPath,
231
+ crossProjectRef: projectRef,
232
+ reactVersion,
233
+ }),
234
+ });
219
235
  }
220
236
  return createModuleResponse(method, code, HTTP_OK, {
221
237
  "Content-Type": "application/javascript; charset=utf-8",
@@ -303,7 +319,16 @@ export function serveModule(req, options) {
303
319
  };
304
320
  code = await transformToESM(source, sourceFile, projectDir, adapter, transformOpts);
305
321
  if (isSSR) {
306
- code = applySSRImportRewrites(code, { projectSlug, branch });
322
+ code = await applySSRImportRewritesAsync(code, {
323
+ projectSlug,
324
+ branch,
325
+ resolveCacheBuster: createSSRTargetCacheBusterResolver({
326
+ secureFs,
327
+ projectDir,
328
+ currentModulePath: modulePath,
329
+ reactVersion,
330
+ }),
331
+ });
307
332
  }
308
333
  const hmrTimestamp = url.searchParams.get("t");
309
334
  if (hmrTimestamp) {
@@ -330,6 +355,37 @@ export function serveModule(req, options) {
330
355
  }
331
356
  }, { "modules.path": url.pathname, "modules.projectSlug": options.projectSlug || "unknown" });
332
357
  }
358
+ async function readSourceFileForVersion(secureFs, findResult) {
359
+ if (findResult.embeddedContent !== undefined)
360
+ return findResult.embeddedContent;
361
+ const platformFs = createFileSystem();
362
+ return findResult.isFrameworkFile
363
+ ? await platformFs.readTextFile(findResult.path)
364
+ : await secureFs.readFile(findResult.path);
365
+ }
366
+ function createSSRTargetCacheBusterResolver(options) {
367
+ const versions = new Map();
368
+ return (target) => {
369
+ const targetPath = resolveSSRImportTargetModulePath(target, options.currentModulePath);
370
+ const key = `${options.crossProjectRef ?? "local"}\0${targetPath}`;
371
+ let promise = versions.get(key);
372
+ if (!promise) {
373
+ promise = (async () => {
374
+ if (options.crossProjectRef) {
375
+ const source = await fetchCrossProjectSource(options.crossProjectRef, targetPath);
376
+ return source === null ? undefined : await sha256Short(`${targetPath}\0${source}`);
377
+ }
378
+ const findResult = await findSourceFile(options.secureFs, options.projectDir, stripSSRModuleJsExtension(targetPath), options.reactVersion);
379
+ if (!findResult)
380
+ return undefined;
381
+ const source = await readSourceFileForVersion(options.secureFs, findResult);
382
+ return await sha256Short(`${findResult.path}\0${source}`);
383
+ })();
384
+ versions.set(key, promise);
385
+ }
386
+ return promise;
387
+ };
388
+ }
333
389
  const REACT_PACKAGE_ASSET_SPECIFIERS = {
334
390
  "react/react": "react",
335
391
  "react/react-dom": "react-dom",
@@ -1,15 +1,27 @@
1
+ type CacheBuster = number | string;
2
+ export interface SSRImportRewriteTarget {
3
+ specifier: string;
4
+ kind: "alias" | "relative";
5
+ modulePath: string;
6
+ rewrittenPath: string;
7
+ }
8
+ export declare function stripSSRModuleJsExtension(path: string): string;
9
+ export declare function resolveSSRImportTargetModulePath(target: SSRImportRewriteTarget, currentModulePath: string): string;
1
10
  interface SSRRewriteOptions {
2
11
  /** Project slug for multi-project routing */
3
12
  projectSlug?: string | null;
4
13
  /** Branch name for branch-aware routing */
5
14
  branch?: string | null;
6
- /** Cache buster timestamp */
7
- cacheBuster?: number;
15
+ /** Cache buster token. When omitted, each rewritten target gets a stable token. */
16
+ cacheBuster?: CacheBuster;
17
+ /** Resolve a cache buster token for each rewritten target. */
18
+ resolveCacheBuster?: (target: SSRImportRewriteTarget) => CacheBuster | null | undefined | Promise<CacheBuster | null | undefined>;
8
19
  /** Cross-project reference (e.g., "demo@0.0") for @/ path rewrites */
9
20
  crossProjectRef?: string;
10
21
  /** React version to use for import rewrites */
11
22
  reactVersion?: string;
12
23
  }
13
24
  export declare function applySSRImportRewrites(code: string, options?: SSRRewriteOptions): string;
25
+ export declare function applySSRImportRewritesAsync(code: string, options?: SSRRewriteOptions): Promise<string>;
14
26
  export {};
15
27
  //# sourceMappingURL=ssr-import-rewriter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ssr-import-rewriter.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/ssr-import-rewriter.ts"],"names":[],"mappings":"AAOA,UAAU,iBAAiB;IACzB,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA4FD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAK5F"}
1
+ {"version":3,"file":"ssr-import-rewriter.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/ssr-import-rewriter.ts"],"names":[],"mappings":"AAQA,KAAK,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC;AAEnC,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,GAAG,UAAU,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9D;AAWD,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,sBAAsB,EAC9B,iBAAiB,EAAE,MAAM,GACxB,MAAM,CAWR;AAED,UAAU,iBAAiB;IACzB,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,mFAAmF;IACnF,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,8DAA8D;IAC9D,kBAAkB,CAAC,EAAE,CACnB,MAAM,EAAE,sBAAsB,KAC3B,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAC9E,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAwKD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAK5F;AA+CD,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,MAAM,CAAC,CAKjB"}
@@ -1,6 +1,30 @@
1
1
  import { DEFAULT_REACT_VERSION, getReactImportMap, } from "../../transforms/esm/package-registry.js";
2
2
  import { isDeno, isNode } from "../../platform/compat/runtime.js";
3
3
  import { getLocalReactPaths } from "../../platform/compat/react-paths.js";
4
+ import { hashString } from "../../cache/hash.js";
5
+ export function stripSSRModuleJsExtension(path) {
6
+ return path.replace(/\.(?:mjs|js)$/i, "");
7
+ }
8
+ function normalizeSSRModulePath(path) {
9
+ let normalized = path.replace(/^\/+/, "");
10
+ if (normalized.startsWith("_vf_modules/")) {
11
+ normalized = normalized.slice("_vf_modules/".length);
12
+ }
13
+ if (normalized.startsWith("@/"))
14
+ normalized = normalized.slice(2);
15
+ return normalized;
16
+ }
17
+ export function resolveSSRImportTargetModulePath(target, currentModulePath) {
18
+ if (target.kind === "alias")
19
+ return normalizeSSRModulePath(target.modulePath);
20
+ const currentPath = normalizeSSRModulePath(currentModulePath);
21
+ if (target.specifier.startsWith("/")) {
22
+ return normalizeSSRModulePath(target.specifier);
23
+ }
24
+ const basePath = currentPath.startsWith("/") ? currentPath : `/${currentPath}`;
25
+ const resolved = new URL(target.specifier, `http://veryfront.local${basePath}`).pathname;
26
+ return normalizeSSRModulePath(resolved);
27
+ }
4
28
  function shouldKeepBareSpecifier(specifier) {
5
29
  // npm: specifiers are only supported in Deno, not Node.js
6
30
  // In Node.js, we need to convert them to esm.sh URLs (handled in rewriteBareImports)
@@ -56,24 +80,86 @@ function rewriteBareImports(code, version) {
56
80
  return `from "https://esm.sh/${bareSpecifier}?external=react&target=es2022"`;
57
81
  });
58
82
  }
83
+ function getDefaultCacheBuster(target, options) {
84
+ return hashString([
85
+ target.kind,
86
+ target.modulePath,
87
+ target.rewrittenPath,
88
+ options.projectSlug ?? "",
89
+ options.branch ?? "",
90
+ options.crossProjectRef ?? "",
91
+ options.reactVersion ?? "",
92
+ ].join("\0"));
93
+ }
94
+ function getCacheBusterSync(target, options) {
95
+ if (options.cacheBuster !== undefined)
96
+ return String(options.cacheBuster);
97
+ return getDefaultCacheBuster(target, options);
98
+ }
99
+ async function getCacheBusterAsync(target, options) {
100
+ if (options.cacheBuster !== undefined)
101
+ return String(options.cacheBuster);
102
+ const resolved = await options.resolveCacheBuster?.(target);
103
+ if (resolved !== undefined && resolved !== null)
104
+ return String(resolved);
105
+ return getDefaultCacheBuster(target, options);
106
+ }
107
+ function buildAliasRewrite(specifierPath, options) {
108
+ const { crossProjectRef } = options;
109
+ const jsPath = specifierPath.endsWith(".js") ? specifierPath : `${specifierPath}.js`;
110
+ if (crossProjectRef) {
111
+ const rewrittenPath = `/_vf_modules/_cross/${crossProjectRef}/@/${jsPath}`;
112
+ return {
113
+ target: {
114
+ specifier: `@/${specifierPath}`,
115
+ kind: "alias",
116
+ modulePath: jsPath,
117
+ rewrittenPath,
118
+ },
119
+ prefix: `${rewrittenPath}?ssr=true`,
120
+ };
121
+ }
122
+ const rewrittenPath = `/_vf_modules/${jsPath}`;
123
+ return {
124
+ target: {
125
+ specifier: `@/${specifierPath}`,
126
+ kind: "alias",
127
+ modulePath: jsPath,
128
+ rewrittenPath,
129
+ },
130
+ prefix: `${rewrittenPath}?ssr=true`,
131
+ };
132
+ }
133
+ function buildRelativeRewrite(specifier) {
134
+ return {
135
+ target: {
136
+ specifier,
137
+ kind: "relative",
138
+ modulePath: specifier,
139
+ rewrittenPath: specifier,
140
+ },
141
+ prefix: `${specifier}?ssr=true`,
142
+ };
143
+ }
144
+ function buildScopedParams(options) {
145
+ const projectParam = options.projectSlug ? `&project=${options.projectSlug}` : "";
146
+ const branchParam = options.branch ? `&branch=${options.branch}` : "";
147
+ return `${projectParam}${branchParam}`;
148
+ }
59
149
  function rewritePathAliases(code, options) {
60
- const { projectSlug, branch, cacheBuster = Date.now(), crossProjectRef } = options;
61
- const projectParam = projectSlug ? `&project=${projectSlug}` : "";
62
- const branchParam = branch ? `&branch=${branch}` : "";
150
+ const scopedParams = buildScopedParams(options);
63
151
  return code.replace(/from\s+["']@\/([^"']+)["']/g, (_match, path) => {
64
- const jsPath = path.endsWith(".js") ? path : `${path}.js`;
65
- if (crossProjectRef) {
66
- return `from "/_vf_modules/_cross/${crossProjectRef}/@/${jsPath}?ssr=true&v=${cacheBuster}"`;
67
- }
68
- return `from "/_vf_modules/${jsPath}?ssr=true${projectParam}${branchParam}&v=${cacheBuster}"`;
152
+ const { target, prefix } = buildAliasRewrite(path, options);
153
+ const cacheBuster = getCacheBusterSync(target, options);
154
+ return `from "${prefix}${scopedParams}&v=${cacheBuster}"`;
69
155
  });
70
156
  }
71
157
  function rewriteRelativeImports(code, options) {
72
- const { projectSlug, branch, cacheBuster = Date.now() } = options;
73
- const projectParam = projectSlug ? `&project=${projectSlug}` : "";
74
- const branchParam = branch ? `&branch=${branch}` : "";
158
+ const scopedParams = buildScopedParams(options);
75
159
  return code.replace(/from\s+["']((?:\.\.?\/|\/)[^"']+\.js)["']/g, (_match, path) => {
76
- return `from "${path}?ssr=true${projectParam}${branchParam}&v=${cacheBuster}"`;
160
+ const { target, prefix } = buildRelativeRewrite(path);
161
+ const cacheBuster = getCacheBusterSync(target, options);
162
+ return `from "${prefix}${scopedParams}&v=${cacheBuster}"`;
77
163
  });
78
164
  }
79
165
  export function applySSRImportRewrites(code, options = {}) {
@@ -82,3 +168,39 @@ export function applySSRImportRewrites(code, options = {}) {
82
168
  result = rewriteRelativeImports(result, options);
83
169
  return result;
84
170
  }
171
+ async function replaceAsync(code, pattern, replacer) {
172
+ const chunks = [];
173
+ let lastIndex = 0;
174
+ pattern.lastIndex = 0;
175
+ for (let match = pattern.exec(code); match; match = pattern.exec(code)) {
176
+ chunks.push(code.slice(lastIndex, match.index));
177
+ chunks.push(await replacer(match));
178
+ lastIndex = match.index + match[0].length;
179
+ }
180
+ chunks.push(code.slice(lastIndex));
181
+ return chunks.join("");
182
+ }
183
+ async function rewritePathAliasesAsync(code, options) {
184
+ const scopedParams = buildScopedParams(options);
185
+ return await replaceAsync(code, /from\s+["']@\/([^"']+)["']/g, async (match) => {
186
+ const path = match[1] ?? "";
187
+ const { target, prefix } = buildAliasRewrite(path, options);
188
+ const cacheBuster = await getCacheBusterAsync(target, options);
189
+ return `from "${prefix}${scopedParams}&v=${cacheBuster}"`;
190
+ });
191
+ }
192
+ async function rewriteRelativeImportsAsync(code, options) {
193
+ const scopedParams = buildScopedParams(options);
194
+ return await replaceAsync(code, /from\s+["']((?:\.\.?\/|\/)[^"']+\.js)["']/g, async (match) => {
195
+ const path = match[1] ?? "";
196
+ const { target, prefix } = buildRelativeRewrite(path);
197
+ const cacheBuster = await getCacheBusterAsync(target, options);
198
+ return `from "${prefix}${scopedParams}&v=${cacheBuster}"`;
199
+ });
200
+ }
201
+ export async function applySSRImportRewritesAsync(code, options = {}) {
202
+ let result = rewriteBareImports(code, options.reactVersion);
203
+ result = await rewritePathAliasesAsync(result, options);
204
+ result = await rewriteRelativeImportsAsync(result, options);
205
+ return result;
206
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"render-context.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/context/render-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0CAA0C,CAAC;AAEhF,OAAO,EAIL,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,YAAY,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,2GAA2G;IAC3G,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,cAAc,EACnB,OAAO,CAAC,EAAE,0BAA0B,GACnC,aAAa,CA4Cf;AAaD,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,eAAe,EACzB,OAAO,CAAC,EAAE,0BAA0B,GACnC,aAAa,CA8Bf;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,eAAO,MAAM,aAAa,4BAAsB,CAAC;AAEjD,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,GAAG,OAAO,CAExE"}
1
+ {"version":3,"file":"render-context.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/context/render-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0CAA0C,CAAC;AAEhF,OAAO,EAIL,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,YAAY,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,2GAA2G;IAC3G,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,cAAc,EACnB,OAAO,CAAC,EAAE,0BAA0B,GACnC,aAAa,CA4Cf;AAoBD,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,eAAe,EACzB,OAAO,CAAC,EAAE,0BAA0B,GACnC,aAAa,CA8Bf;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,eAAO,MAAM,aAAa,4BAAsB,CAAC;AAEjD,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,GAAG,OAAO,CAExE"}
@@ -40,8 +40,14 @@ export function createRenderContext(ctx, options) {
40
40
  function getReleaseKey(isLocal, environment, branch, releaseId) {
41
41
  if (isLocal)
42
42
  return branch ?? "main";
43
- if (environment === "production")
43
+ if (environment === "production") {
44
+ if (!releaseId) {
45
+ throw INVALID_ARGUMENT.create({
46
+ detail: "Production requires releaseId for cache isolation",
47
+ });
48
+ }
44
49
  return releaseId;
50
+ }
45
51
  return branch ?? "main";
46
52
  }
47
53
  export function createRenderContextFromEnriched(enriched, options) {
@@ -1 +1 @@
1
- {"version":3,"file":"enriched-context.d.ts","sourceRoot":"","sources":["../../../../src/src/server/context/enriched-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,2BAA2B,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAChG,YAAY,EACV,2BAA2B,EAC3B,eAAe,EACf,WAAW,GACZ,MAAM,6BAA6B,CAAC;AAErC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,eAAe,CAoC1F;AAMD,wBAAgB,kCAAkC,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAK/E"}
1
+ {"version":3,"file":"enriched-context.d.ts","sourceRoot":"","sources":["../../../../src/src/server/context/enriched-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,2BAA2B,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAChG,YAAY,EACV,2BAA2B,EAC3B,eAAe,EACf,WAAW,GACZ,MAAM,6BAA6B,CAAC;AAErC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,eAAe,CA8C1F;AAMD,wBAAgB,kCAAkC,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAK/E"}
@@ -4,9 +4,21 @@ export function buildEnrichedContext(options) {
4
4
  if (!options.contentSourceId) {
5
5
  throw INVALID_ARGUMENT.create({ detail: `Missing contentSourceId for ${options.projectSlug}` });
6
6
  }
7
- const releaseKey = options.environment === "production"
8
- ? (options.releaseId ?? "unknown")
9
- : (options.branch ?? "main");
7
+ let releaseKey;
8
+ if (options.isLocalProject) {
9
+ releaseKey = options.branch ?? "main";
10
+ }
11
+ else if (options.environment === "production") {
12
+ if (!options.releaseId) {
13
+ throw INVALID_ARGUMENT.create({
14
+ detail: "Production requires releaseId for cache isolation",
15
+ });
16
+ }
17
+ releaseKey = options.releaseId;
18
+ }
19
+ else {
20
+ releaseKey = options.branch ?? "main";
21
+ }
10
22
  return {
11
23
  projectId: options.projectId,
12
24
  projectSlug: options.projectSlug,
@@ -13,7 +13,7 @@ function discoveryKey(ctx) {
13
13
  const environment = ctx.enriched?.environment ?? ctx.resolvedEnvironment ??
14
14
  (ctx.releaseId ? "production" : "preview");
15
15
  if (environment === "production") {
16
- return `${slug}:release:${ctx.releaseId ?? "unknown"}`;
16
+ return ctx.releaseId ? `${slug}:release:${ctx.releaseId}` : `${slug}:production:unreleased`;
17
17
  }
18
18
  const branch = ctx.requestContext?.branch ?? ctx.enriched?.branch ?? ctx.parsedDomain?.branch ??
19
19
  "main";
@@ -26,7 +26,7 @@ function shouldCacheCompletedDiscovery(ctx) {
26
26
  }
27
27
  const environment = ctx.enriched?.environment ?? ctx.resolvedEnvironment ??
28
28
  (ctx.releaseId ? "production" : "preview");
29
- return environment === "production";
29
+ return environment === "production" && !!ctx.releaseId;
30
30
  }
31
31
  /**
32
32
  * Run primitive discovery (agents, tools) for a project if not already done.
@@ -1 +1 @@
1
- {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/src/skill/executor.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA4EnG;;GAEG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAqBrF;AAED;;GAEG;AACH,qBAAa,mBAAoB,YAAW,mBAAmB;IACvD,OAAO,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAsB3E;AA6DD;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,mBAAmB,CAE5D"}
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/src/skill/executor.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA4EnG;;GAEG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAqBrF;AAED;;GAEG;AACH,qBAAa,mBAAoB,YAAW,mBAAmB;IACvD,OAAO,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAsB3E;AAgED;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,mBAAmB,CAE5D"}
@@ -149,6 +149,9 @@ class CloudScriptExecutor {
149
149
  const commandPromise = sandbox.executeCommand(cmdString);
150
150
  const result = await withTimeout(commandPromise, timeoutMs);
151
151
  if (result === TIMEOUT_SENTINEL) {
152
+ commandPromise.catch(() => {
153
+ // The command may reject after the timeout path has already returned.
154
+ });
152
155
  // Kill any running processes before returning — withTimeout only
153
156
  // races the timer, it doesn't terminate the sandbox command.
154
157
  try {
@@ -1,3 +1,3 @@
1
1
  /** Shared version value. */
2
- export declare const VERSION = "0.1.742";
2
+ export declare const VERSION = "0.1.744";
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.742";
4
+ export const VERSION = "0.1.744";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.742",
3
+ "version": "0.1.744",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",