veryfront 0.1.95 → 0.1.97
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 +1 -1
- package/esm/src/html/schemas/html.schema.d.ts +2 -2
- package/esm/src/jobs/runtime-env.d.ts +5 -0
- package/esm/src/jobs/runtime-env.d.ts.map +1 -0
- package/esm/src/jobs/runtime-env.js +101 -0
- package/esm/src/modules/react-loader/ssr-module-loader/loader.d.ts.map +1 -1
- package/esm/src/modules/react-loader/ssr-module-loader/loader.js +32 -1
- package/esm/src/modules/react-loader/ssr-module-loader/ssr-cache-manager.d.ts.map +1 -1
- package/esm/src/modules/react-loader/ssr-module-loader/ssr-cache-manager.js +31 -2
- package/esm/src/modules/react-loader/ssr-module-loader/vf-module-resolver.d.ts.map +1 -1
- package/esm/src/modules/react-loader/ssr-module-loader/vf-module-resolver.js +1 -0
- package/esm/src/rendering/orchestrator/module-loader/index.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/module-loader/index.js +6 -1
- package/esm/src/rendering/page-rendering.d.ts +8 -0
- package/esm/src/rendering/page-rendering.d.ts.map +1 -1
- package/esm/src/rendering/page-rendering.js +29 -18
- package/esm/src/task/runner.d.ts.map +1 -1
- package/esm/src/task/runner.js +2 -6
- package/esm/src/transforms/mdx/esm-module-loader/cache/index.d.ts +5 -1
- package/esm/src/transforms/mdx/esm-module-loader/cache/index.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/cache/index.js +18 -2
- package/esm/src/transforms/mdx/esm-module-loader/cache-format.d.ts +2 -1
- package/esm/src/transforms/mdx/esm-module-loader/cache-format.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/cache-format.js +12 -5
- package/esm/src/transforms/mdx/esm-module-loader/loader-helpers.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/loader-helpers.js +1 -0
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/cache-keys.d.ts +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/cache-keys.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/cache-keys.js +2 -2
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/dependency-recovery.d.ts +23 -0
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/dependency-recovery.d.ts.map +1 -0
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/dependency-recovery.js +112 -0
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/distributed-cache.d.ts +2 -2
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/distributed-cache.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/distributed-cache.js +33 -4
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.d.ts +6 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.js +31 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.d.ts +1 -0
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.js +15 -6
- package/esm/src/transforms/mdx/esm-module-loader/types.d.ts +1 -0
- package/esm/src/transforms/mdx/esm-module-loader/types.d.ts.map +1 -1
- package/esm/src/utils/version.d.ts +1 -1
- package/esm/src/utils/version.js +1 -1
- package/esm/src/workflow/executor/workflow-executor.d.ts.map +1 -1
- package/esm/src/workflow/executor/workflow-executor.js +7 -1
- package/esm/src/workflow/types.d.ts +1 -0
- package/esm/src/workflow/types.d.ts.map +1 -1
- package/esm/src/workflow/worker/dynamic-job-entrypoint.d.ts.map +1 -1
- package/esm/src/workflow/worker/dynamic-job-entrypoint.js +18 -1
- package/esm/src/workflow/worker/job-entrypoint.d.ts.map +1 -1
- package/esm/src/workflow/worker/job-entrypoint.js +18 -1
- package/package.json +1 -1
- package/src/deno.js +1 -1
- package/src/src/jobs/runtime-env.ts +132 -0
- package/src/src/modules/react-loader/ssr-module-loader/loader.ts +34 -0
- package/src/src/modules/react-loader/ssr-module-loader/ssr-cache-manager.ts +34 -2
- package/src/src/modules/react-loader/ssr-module-loader/vf-module-resolver.ts +1 -0
- package/src/src/rendering/orchestrator/module-loader/index.ts +12 -1
- package/src/src/rendering/page-rendering.ts +64 -39
- package/src/src/task/runner.ts +2 -8
- package/src/src/transforms/mdx/esm-module-loader/cache/index.ts +18 -1
- package/src/src/transforms/mdx/esm-module-loader/cache-format.ts +33 -1
- package/src/src/transforms/mdx/esm-module-loader/loader-helpers.ts +1 -0
- package/src/src/transforms/mdx/esm-module-loader/module-fetcher/cache-keys.ts +2 -1
- package/src/src/transforms/mdx/esm-module-loader/module-fetcher/dependency-recovery.ts +173 -0
- package/src/src/transforms/mdx/esm-module-loader/module-fetcher/distributed-cache.ts +43 -3
- package/src/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.ts +37 -0
- package/src/src/transforms/mdx/esm-module-loader/module-fetcher/index.ts +26 -11
- package/src/src/transforms/mdx/esm-module-loader/types.ts +1 -0
- package/src/src/utils/version.ts +1 -1
- package/src/src/workflow/executor/workflow-executor.ts +7 -1
- package/src/src/workflow/types.ts +1 -0
- package/src/src/workflow/worker/dynamic-job-entrypoint.ts +19 -1
- package/src/src/workflow/worker/job-entrypoint.ts +19 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { logger as baseLogger } from "../utils/index.js";
|
|
2
|
+
|
|
3
|
+
const logger = baseLogger.component("job-runtime-env");
|
|
4
|
+
|
|
5
|
+
export const INJECTED_TASK_ENV_JSON = "VERYFRONT_TASK_ENV_JSON";
|
|
6
|
+
|
|
7
|
+
const UNSAFE_INJECTED_ENV_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
8
|
+
|
|
9
|
+
const HIDDEN_TASK_CONTEXT_ENV_KEYS = new Set([
|
|
10
|
+
"VERYFRONT_API_TOKEN",
|
|
11
|
+
"VERYFRONT_API_URL",
|
|
12
|
+
"VERYFRONT_PROJECT_API_URL",
|
|
13
|
+
"VERYFRONT_API_BASE_URL",
|
|
14
|
+
"VERYFRONT_PROJECT_ID",
|
|
15
|
+
"VERYFRONT_PROJECT_SLUG",
|
|
16
|
+
"VERYFRONT_BRANCH_REF",
|
|
17
|
+
"VERYFRONT_API_USER",
|
|
18
|
+
"VERYFRONT_API_PASS",
|
|
19
|
+
"VERYFRONT_JOB_RESULT_PATH",
|
|
20
|
+
INJECTED_TASK_ENV_JSON,
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
const DISALLOWED_INJECTED_ENV_KEYS = new Set([
|
|
24
|
+
"VERYFRONT_API_TOKEN",
|
|
25
|
+
"VERYFRONT_API_URL",
|
|
26
|
+
"VERYFRONT_PROJECT_API_URL",
|
|
27
|
+
"VERYFRONT_API_BASE_URL",
|
|
28
|
+
"VERYFRONT_PROJECT_ID",
|
|
29
|
+
"VERYFRONT_PROJECT_SLUG",
|
|
30
|
+
"VERYFRONT_BRANCH_REF",
|
|
31
|
+
"VERYFRONT_API_USER",
|
|
32
|
+
"VERYFRONT_API_PASS",
|
|
33
|
+
"VERYFRONT_JOB_RESULT_PATH",
|
|
34
|
+
INJECTED_TASK_ENV_JSON,
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
function isHiddenTaskContextEnvKey(key: string): boolean {
|
|
38
|
+
return key.startsWith("TENANT_") || HIDDEN_TASK_CONTEXT_ENV_KEYS.has(key);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function isDisallowedInjectedEnvKey(key: string): boolean {
|
|
42
|
+
return key.startsWith("TENANT_") || DISALLOWED_INJECTED_ENV_KEYS.has(key);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function filterExistingProjectEnv(
|
|
46
|
+
env: Record<string, string> | undefined,
|
|
47
|
+
): Record<string, string> {
|
|
48
|
+
const filtered: Record<string, string> = {};
|
|
49
|
+
for (const [key, value] of Object.entries(env ?? {})) {
|
|
50
|
+
if (
|
|
51
|
+
UNSAFE_INJECTED_ENV_KEYS.has(key) ||
|
|
52
|
+
isDisallowedInjectedEnvKey(key) ||
|
|
53
|
+
typeof value !== "string"
|
|
54
|
+
) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
filtered[key] = value;
|
|
58
|
+
}
|
|
59
|
+
return filtered;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function readInjectedProjectEnv(
|
|
63
|
+
allEnv: Record<string, string>,
|
|
64
|
+
): Record<string, string> {
|
|
65
|
+
const raw = allEnv[INJECTED_TASK_ENV_JSON];
|
|
66
|
+
if (!raw) {
|
|
67
|
+
return {};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const parsed = JSON.parse(raw);
|
|
72
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
73
|
+
return {};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const injectedEnv = Object.create(null) as Record<string, string>;
|
|
77
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
78
|
+
if (
|
|
79
|
+
UNSAFE_INJECTED_ENV_KEYS.has(key) ||
|
|
80
|
+
isDisallowedInjectedEnvKey(key) ||
|
|
81
|
+
typeof value !== "string"
|
|
82
|
+
) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
injectedEnv[key] = value;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return injectedEnv;
|
|
89
|
+
} catch {
|
|
90
|
+
logger.warn(`Ignoring invalid ${INJECTED_TASK_ENV_JSON}`);
|
|
91
|
+
return {};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function buildTaskContextEnv(
|
|
96
|
+
allEnv: Record<string, string>,
|
|
97
|
+
envAllowlist?: string[],
|
|
98
|
+
): Record<string, string> {
|
|
99
|
+
const allowlistedEnvKeys = envAllowlist ? new Set(envAllowlist) : null;
|
|
100
|
+
const env: Record<string, string> = {};
|
|
101
|
+
|
|
102
|
+
for (const [key, value] of Object.entries(allEnv)) {
|
|
103
|
+
if (isHiddenTaskContextEnvKey(key)) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (allowlistedEnvKeys && !allowlistedEnvKeys.has(key)) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
env[key] = value;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
for (const [key, value] of Object.entries(readInjectedProjectEnv(allEnv))) {
|
|
113
|
+
if (allowlistedEnvKeys && !allowlistedEnvKeys.has(key)) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
env[key] = value;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return env;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function mergeInjectedWorkflowEnv(
|
|
123
|
+
existingEnv: Record<string, string> | undefined,
|
|
124
|
+
allEnv: Record<string, string>,
|
|
125
|
+
): Record<string, string> | undefined {
|
|
126
|
+
const mergedEnv = {
|
|
127
|
+
...filterExistingProjectEnv(existingEnv),
|
|
128
|
+
...readInjectedProjectEnv(allEnv),
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
return Object.keys(mergedEnv).length > 0 ? mergedEnv : undefined;
|
|
132
|
+
}
|
|
@@ -54,6 +54,7 @@ import { preflightLocalImports } from "./preflight-imports.js";
|
|
|
54
54
|
import { resolveVfModuleImports } from "./vf-module-resolver.js";
|
|
55
55
|
import { registerCSSImport } from "../css-import-collector.js";
|
|
56
56
|
import { injectNodePositions } from "../../../transforms/plugins/babel-node-positions.js";
|
|
57
|
+
import { ensureMdxModuleDependencies } from "../../../transforms/mdx/esm-module-loader/module-fetcher/dependency-recovery.js";
|
|
57
58
|
|
|
58
59
|
const logger = rendererLogger.component("ssr-module-loader");
|
|
59
60
|
|
|
@@ -230,6 +231,35 @@ export class SSRModuleLoader {
|
|
|
230
231
|
}
|
|
231
232
|
|
|
232
233
|
if (classifiedError.type === "module-not-found") {
|
|
234
|
+
if (this.options.contentSourceId) {
|
|
235
|
+
try {
|
|
236
|
+
const cachedCode = await this.cache.getFs().readTextFile(cacheEntry.tempPath);
|
|
237
|
+
const recovered = await ensureMdxModuleDependencies(cachedCode, {
|
|
238
|
+
projectId: this.options.projectId,
|
|
239
|
+
contentSourceId: this.options.contentSourceId,
|
|
240
|
+
log: logger,
|
|
241
|
+
});
|
|
242
|
+
if (recovered.missing.length === 0 && recovered.recovered.length > 0) {
|
|
243
|
+
const retryTempPath = cacheEntry.tempPath.replace(/\.mjs$/, "") +
|
|
244
|
+
`-recovered-${cacheEntry.contentHash}.mjs`;
|
|
245
|
+
await this.cache.getFs().writeTextFile(retryTempPath, cachedCode);
|
|
246
|
+
logger.info("Recovered vfmod dependencies for cached SSR module, retrying import", {
|
|
247
|
+
file: filePath.slice(-40),
|
|
248
|
+
recovered: recovered.recovered.slice(0, 5),
|
|
249
|
+
retryTempPath,
|
|
250
|
+
});
|
|
251
|
+
return (await import(
|
|
252
|
+
`file://${retryTempPath}?v=${cacheEntry.contentHash}&retry=1`
|
|
253
|
+
)) as Record<string, unknown>;
|
|
254
|
+
}
|
|
255
|
+
} catch (recoveryError) {
|
|
256
|
+
logger.debug("Failed to recover vfmod dependencies for cached SSR module", {
|
|
257
|
+
file: filePath.slice(-40),
|
|
258
|
+
error: recoveryError instanceof Error ? recoveryError.message : String(recoveryError),
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
233
263
|
logger.error(
|
|
234
264
|
"[SSR-MODULE-LOADER] Cached module has missing dependency, invalidating cache",
|
|
235
265
|
{
|
|
@@ -426,6 +456,10 @@ export class SSRModuleLoader {
|
|
|
426
456
|
mdxCacheDir,
|
|
427
457
|
this.options.projectDir,
|
|
428
458
|
contentHash,
|
|
459
|
+
{
|
|
460
|
+
projectId: this.options.projectId,
|
|
461
|
+
contentSourceId: this.options.contentSourceId,
|
|
462
|
+
},
|
|
429
463
|
);
|
|
430
464
|
|
|
431
465
|
if (mdxCacheResult.status === "hit") {
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
} from "./http-bundle-helpers.js";
|
|
27
27
|
import { buildTempModulePath, buildTmpDirPath, getTmpDirCacheKey } from "./tmp-paths.js";
|
|
28
28
|
import type { ModuleCacheEntry, SSRModuleLoaderOptions } from "./types.js";
|
|
29
|
+
import { ensureMdxModuleDependencies } from "../../../transforms/mdx/esm-module-loader/module-fetcher/dependency-recovery.js";
|
|
29
30
|
|
|
30
31
|
const logger = rendererLogger.component("ssr-module-loader");
|
|
31
32
|
|
|
@@ -169,7 +170,7 @@ export class SSRCacheManager {
|
|
|
169
170
|
try {
|
|
170
171
|
const cachedCode = await this.fs.readTextFile(cachedEntry.tempPath);
|
|
171
172
|
const isValid = await this.validateCachedCode(cachedCode, filePath, "memory-cache", {
|
|
172
|
-
checkLocalPaths:
|
|
173
|
+
checkLocalPaths: true,
|
|
173
174
|
checkInvalidEsmShPath: false,
|
|
174
175
|
});
|
|
175
176
|
if (!isValid) {
|
|
@@ -237,11 +238,14 @@ export class SSRCacheManager {
|
|
|
237
238
|
|
|
238
239
|
private async hasMissingLocalPaths(code: string, filePath: string): Promise<boolean> {
|
|
239
240
|
const allPaths = extractAllFilePaths(code);
|
|
241
|
+
let hasMissingPath = false;
|
|
242
|
+
|
|
240
243
|
for (const path of allPaths) {
|
|
241
244
|
try {
|
|
242
245
|
const stat = await this.fs.stat(path);
|
|
243
246
|
if (!stat.isFile) {
|
|
244
|
-
|
|
247
|
+
hasMissingPath = true;
|
|
248
|
+
break;
|
|
245
249
|
}
|
|
246
250
|
} catch (error) {
|
|
247
251
|
logger.debug("Redis cache has invalid local path, re-transforming", {
|
|
@@ -249,6 +253,34 @@ export class SSRCacheManager {
|
|
|
249
253
|
missingPath: path.slice(-60),
|
|
250
254
|
error,
|
|
251
255
|
});
|
|
256
|
+
hasMissingPath = true;
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (
|
|
262
|
+
hasMissingPath &&
|
|
263
|
+
this.options.projectId &&
|
|
264
|
+
this.options.contentSourceId
|
|
265
|
+
) {
|
|
266
|
+
const recovered = await ensureMdxModuleDependencies(code, {
|
|
267
|
+
projectId: this.options.projectId,
|
|
268
|
+
contentSourceId: this.options.contentSourceId,
|
|
269
|
+
log: logger,
|
|
270
|
+
});
|
|
271
|
+
if (recovered.recovered.length > 0) {
|
|
272
|
+
logger.debug("Recovered missing local vfmod dependencies for SSR cache entry", {
|
|
273
|
+
file: filePath.slice(-40),
|
|
274
|
+
recovered: recovered.recovered.slice(0, 5),
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
for (const path of allPaths) {
|
|
280
|
+
try {
|
|
281
|
+
const stat = await this.fs.stat(path);
|
|
282
|
+
if (!stat.isFile) return true;
|
|
283
|
+
} catch (_) {
|
|
252
284
|
return true;
|
|
253
285
|
}
|
|
254
286
|
}
|
|
@@ -223,7 +223,18 @@ export async function transformModuleWithDeps(
|
|
|
223
223
|
const sourceKey = encodeURIComponent(contentSourceId);
|
|
224
224
|
const mdxCacheDir = join(baseCacheDir, projectKey, sourceKey);
|
|
225
225
|
|
|
226
|
-
const mdxCacheResult = await lookupMdxEsmCache(
|
|
226
|
+
const mdxCacheResult = await lookupMdxEsmCache(
|
|
227
|
+
filePath,
|
|
228
|
+
mdxCacheDir,
|
|
229
|
+
projectDir,
|
|
230
|
+
undefined,
|
|
231
|
+
contentSourceId
|
|
232
|
+
? {
|
|
233
|
+
projectId,
|
|
234
|
+
contentSourceId,
|
|
235
|
+
}
|
|
236
|
+
: undefined,
|
|
237
|
+
);
|
|
227
238
|
if (mdxCacheResult.status === "hit") {
|
|
228
239
|
moduleCache.set(cacheKey, mdxCacheResult.path);
|
|
229
240
|
return mdxCacheResult.path;
|
|
@@ -15,6 +15,64 @@ interface MDXPageResult {
|
|
|
15
15
|
collectedMetadata: Record<string, unknown>;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
interface PreparedMDXPageBundles {
|
|
19
|
+
pageBundle: PageBundle;
|
|
20
|
+
serverModuleCode: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function prepareMDXPageBundles(
|
|
24
|
+
pageInfo: EntityInfo,
|
|
25
|
+
projectDir: string,
|
|
26
|
+
options?: {
|
|
27
|
+
precompiledModule?: string;
|
|
28
|
+
studioEmbed?: boolean;
|
|
29
|
+
},
|
|
30
|
+
): Promise<PreparedMDXPageBundles> {
|
|
31
|
+
const { frontmatter, content, path } = pageInfo.entity;
|
|
32
|
+
const fmArg = frontmatter && Object.keys(frontmatter).length > 0 ? frontmatter : undefined;
|
|
33
|
+
|
|
34
|
+
const ssrBundle = await compileContent(
|
|
35
|
+
"development",
|
|
36
|
+
projectDir,
|
|
37
|
+
content,
|
|
38
|
+
fmArg,
|
|
39
|
+
path,
|
|
40
|
+
"server",
|
|
41
|
+
undefined,
|
|
42
|
+
options?.studioEmbed,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const pageBundle = ssrBundle as PageBundle;
|
|
46
|
+
|
|
47
|
+
if (options?.precompiledModule) {
|
|
48
|
+
pageBundle.clientModuleCode = options.precompiledModule;
|
|
49
|
+
} else {
|
|
50
|
+
const browserBundle = await compileContent(
|
|
51
|
+
"development",
|
|
52
|
+
projectDir,
|
|
53
|
+
content,
|
|
54
|
+
fmArg,
|
|
55
|
+
path,
|
|
56
|
+
"browser",
|
|
57
|
+
undefined,
|
|
58
|
+
options?.studioEmbed,
|
|
59
|
+
);
|
|
60
|
+
pageBundle.clientModuleCode = browserBundle.compiledCode;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const clientModuleCode = pageBundle.clientModuleCode;
|
|
64
|
+
if (!clientModuleCode) {
|
|
65
|
+
throw RENDER_ERROR.create({
|
|
66
|
+
detail: "MDX compilation produced no client module code",
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
pageBundle,
|
|
72
|
+
serverModuleCode: ssrBundle.compiledCode,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
18
76
|
export function handleMDXPage(
|
|
19
77
|
pageInfo: EntityInfo,
|
|
20
78
|
slug: string,
|
|
@@ -42,49 +100,16 @@ export function handleMDXPage(
|
|
|
42
100
|
return withSpan(
|
|
43
101
|
"rendering.handleMDXPage",
|
|
44
102
|
async () => {
|
|
45
|
-
const { frontmatter,
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
projectDir,
|
|
51
|
-
content,
|
|
52
|
-
fmArg,
|
|
53
|
-
path,
|
|
54
|
-
"server",
|
|
55
|
-
undefined,
|
|
56
|
-
options?.studioEmbed,
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
const pageBundle = ssrBundle as PageBundle;
|
|
103
|
+
const { frontmatter, path } = pageInfo.entity;
|
|
104
|
+
const { pageBundle, serverModuleCode } = await prepareMDXPageBundles(pageInfo, projectDir, {
|
|
105
|
+
precompiledModule: options?.precompiledModule,
|
|
106
|
+
studioEmbed: options?.studioEmbed,
|
|
107
|
+
});
|
|
60
108
|
let collectedMetadata: Record<string, unknown> = {};
|
|
61
109
|
|
|
62
110
|
try {
|
|
63
|
-
if (options?.precompiledModule) {
|
|
64
|
-
pageBundle.clientModuleCode = options.precompiledModule;
|
|
65
|
-
} else {
|
|
66
|
-
const browserBundle = await compileContent(
|
|
67
|
-
"development",
|
|
68
|
-
projectDir,
|
|
69
|
-
content,
|
|
70
|
-
fmArg,
|
|
71
|
-
path,
|
|
72
|
-
"browser",
|
|
73
|
-
undefined,
|
|
74
|
-
options?.studioEmbed,
|
|
75
|
-
);
|
|
76
|
-
pageBundle.clientModuleCode = browserBundle.compiledCode;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const clientModuleCode = pageBundle.clientModuleCode;
|
|
80
|
-
if (!clientModuleCode) {
|
|
81
|
-
throw RENDER_ERROR.create({
|
|
82
|
-
detail: "MDX compilation produced no client module code",
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
111
|
const mod = (await mdxRenderer.loadModuleESM(
|
|
87
|
-
|
|
112
|
+
serverModuleCode,
|
|
88
113
|
adapter,
|
|
89
114
|
options?.projectId,
|
|
90
115
|
projectDir,
|
package/src/src/task/runner.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { logger as baseLogger } from "../utils/index.js";
|
|
9
9
|
import { env as getProcessEnv } from "../platform/compat/process.js";
|
|
10
|
+
import { buildTaskContextEnv } from "../jobs/runtime-env.js";
|
|
10
11
|
import type { DiscoveredTask } from "./discovery.js";
|
|
11
12
|
import type { TaskContext } from "./types.js";
|
|
12
13
|
|
|
@@ -61,14 +62,7 @@ export async function runTask(options: RunTaskOptions): Promise<TaskRunResult> {
|
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
const allEnv = getProcessEnv();
|
|
64
|
-
const env
|
|
65
|
-
? Object.fromEntries(
|
|
66
|
-
envAllowlist.flatMap((k) => {
|
|
67
|
-
const value = allEnv[k];
|
|
68
|
-
return value === undefined ? [] : [[k, value] as const];
|
|
69
|
-
}),
|
|
70
|
-
)
|
|
71
|
-
: { ...allEnv };
|
|
65
|
+
const env = buildTaskContextEnv(allEnv, envAllowlist);
|
|
72
66
|
|
|
73
67
|
const ctx: TaskContext = {
|
|
74
68
|
env,
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
import { LOG_PREFIX_MDX_LOADER } from "../constants.js";
|
|
22
22
|
import { LRUCache } from "../../../../utils/lru-wrapper.js";
|
|
23
23
|
import { buildMdxEsmPathCacheKey, MDX_ESM_ALL_FILE_URL_PATTERN_SOURCE } from "../cache-format.js";
|
|
24
|
+
import { ensureMdxModuleDependencies } from "../module-fetcher/dependency-recovery.js";
|
|
24
25
|
|
|
25
26
|
export type CacheLookupResult =
|
|
26
27
|
| { status: "hit"; path: string }
|
|
@@ -341,6 +342,7 @@ export async function lookupMdxEsmCache(
|
|
|
341
342
|
cacheDir: string,
|
|
342
343
|
projectDir?: string,
|
|
343
344
|
_contentHash?: string, // Intentionally unused - kept for API compatibility
|
|
345
|
+
recoveryOptions?: { projectId: string; contentSourceId: string },
|
|
344
346
|
): Promise<CacheLookupResult> {
|
|
345
347
|
const cache = await getModulePathCache(cacheDir);
|
|
346
348
|
const cacheKey = toMdxEsmCacheKey(filePath, projectDir);
|
|
@@ -408,7 +410,22 @@ export async function lookupMdxEsmCache(
|
|
|
408
410
|
// CRITICAL: Check that all file:// dependencies actually exist on disk.
|
|
409
411
|
// The distributed cache may contain code referencing file:// paths from other pods
|
|
410
412
|
// that don't exist locally (e.g., HTTP bundles, MDX-ESM modules).
|
|
411
|
-
|
|
413
|
+
let missingDeps = await findMissingFileDependencies(cachedCode);
|
|
414
|
+
if (missingDeps.length > 0 && recoveryOptions) {
|
|
415
|
+
const recovered = await ensureMdxModuleDependencies(cachedCode, {
|
|
416
|
+
...recoveryOptions,
|
|
417
|
+
log: logger,
|
|
418
|
+
});
|
|
419
|
+
if (recovered.recovered.length > 0) {
|
|
420
|
+
logger.debug(`${LOG_PREFIX_MDX_LOADER} Recovered cached MDX-ESM dependencies`, {
|
|
421
|
+
filePath,
|
|
422
|
+
cachedPath,
|
|
423
|
+
recovered: recovered.recovered.slice(0, 5),
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
missingDeps = await findMissingFileDependencies(cachedCode);
|
|
427
|
+
}
|
|
428
|
+
|
|
412
429
|
if (missingDeps.length > 0) {
|
|
413
430
|
logger.warn(
|
|
414
431
|
`${LOG_PREFIX_MDX_LOADER} Cached module has ${missingDeps.length} missing file dependencies, invalidating`,
|
|
@@ -10,10 +10,11 @@ const CACHE_NAMESPACE_SENTINEL = "__vf_cache_namespace__";
|
|
|
10
10
|
function formatMdxEsmTransformCacheKey(
|
|
11
11
|
namespace: string,
|
|
12
12
|
projectId: string,
|
|
13
|
+
contentSourceId: string,
|
|
13
14
|
normalizedPath: string,
|
|
14
15
|
contentHash: string,
|
|
15
16
|
): string {
|
|
16
|
-
return `${namespace}:${projectId}:${normalizedPath}:${contentHash}:ssr`;
|
|
17
|
+
return `${namespace}:${projectId}:${contentSourceId}:${normalizedPath}:${contentHash}:ssr`;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
function formatMdxEsmPathCacheKey(namespace: string, normalizedPath: string): string {
|
|
@@ -24,6 +25,15 @@ function formatMdxEsmModuleFileName(namespace: string, contentHash: string): str
|
|
|
24
25
|
return `vfmod-${namespace}-${contentHash}.mjs`;
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
function formatMdxEsmModuleRecoveryCacheKey(
|
|
29
|
+
namespace: string,
|
|
30
|
+
projectId: string,
|
|
31
|
+
contentSourceId: string,
|
|
32
|
+
fileName: string,
|
|
33
|
+
): string {
|
|
34
|
+
return `${namespace}:${projectId}:${contentSourceId}:${fileName}:vfmod`;
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
function formatMdxJsxCacheFileName(namespace: string, filePath: string): string {
|
|
28
38
|
return `jsx-${namespace}-${hashString(filePath)}.mjs`;
|
|
29
39
|
}
|
|
@@ -42,11 +52,18 @@ function buildMdxEsmCacheSchemaSample() {
|
|
|
42
52
|
transformKey: formatMdxEsmTransformCacheKey(
|
|
43
53
|
CACHE_NAMESPACE_SENTINEL,
|
|
44
54
|
"__vf_project__",
|
|
55
|
+
"preview-main",
|
|
45
56
|
"_vf_modules/pages/index.js",
|
|
46
57
|
"deadbeef",
|
|
47
58
|
),
|
|
48
59
|
pathKey: formatMdxEsmPathCacheKey(CACHE_NAMESPACE_SENTINEL, "_vf_modules/pages/index.js"),
|
|
49
60
|
moduleFile: formatMdxEsmModuleFileName(CACHE_NAMESPACE_SENTINEL, "deadbeef"),
|
|
61
|
+
moduleRecoveryKey: formatMdxEsmModuleRecoveryCacheKey(
|
|
62
|
+
CACHE_NAMESPACE_SENTINEL,
|
|
63
|
+
"__vf_project__",
|
|
64
|
+
"preview-main",
|
|
65
|
+
formatMdxEsmModuleFileName(CACHE_NAMESPACE_SENTINEL, "deadbeef"),
|
|
66
|
+
),
|
|
50
67
|
jsxFile: formatMdxJsxCacheFileName(CACHE_NAMESPACE_SENTINEL, "/tmp/project/Button.tsx"),
|
|
51
68
|
unresolvedVfModulesPattern: UNRESOLVED_VF_MODULES_PATTERN.source,
|
|
52
69
|
allFileUrlPattern: ALL_FILE_URL_PATTERN_SOURCE,
|
|
@@ -84,12 +101,14 @@ export const FRAMEWORK_VF_MODULE_CACHE_NAMESPACE = createCacheNamespace(
|
|
|
84
101
|
|
|
85
102
|
export function buildMdxEsmTransformCacheKey(
|
|
86
103
|
projectId: string,
|
|
104
|
+
contentSourceId: string,
|
|
87
105
|
normalizedPath: string,
|
|
88
106
|
contentHash: string,
|
|
89
107
|
): string {
|
|
90
108
|
return formatMdxEsmTransformCacheKey(
|
|
91
109
|
MDX_ESM_CACHE_NAMESPACE,
|
|
92
110
|
projectId,
|
|
111
|
+
contentSourceId,
|
|
93
112
|
normalizedPath,
|
|
94
113
|
contentHash,
|
|
95
114
|
);
|
|
@@ -103,6 +122,19 @@ export function buildMdxEsmModuleFileName(contentHash: string): string {
|
|
|
103
122
|
return formatMdxEsmModuleFileName(MDX_ESM_CACHE_NAMESPACE, contentHash);
|
|
104
123
|
}
|
|
105
124
|
|
|
125
|
+
export function buildMdxEsmModuleRecoveryCacheKey(
|
|
126
|
+
projectId: string,
|
|
127
|
+
contentSourceId: string,
|
|
128
|
+
fileName: string,
|
|
129
|
+
): string {
|
|
130
|
+
return formatMdxEsmModuleRecoveryCacheKey(
|
|
131
|
+
MDX_ESM_CACHE_NAMESPACE,
|
|
132
|
+
projectId,
|
|
133
|
+
contentSourceId,
|
|
134
|
+
fileName,
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
106
138
|
export function buildMdxJsxCacheFileName(filePath: string): string {
|
|
107
139
|
return formatMdxJsxCacheFileName(MDX_ESM_CACHE_NAMESPACE, filePath);
|
|
108
140
|
}
|
|
@@ -15,10 +15,11 @@ import { buildMdxEsmPathCacheKey, buildMdxEsmTransformCacheKey } from "../cache-
|
|
|
15
15
|
*/
|
|
16
16
|
export function getTransformCacheKey(
|
|
17
17
|
projectId: string,
|
|
18
|
+
contentSourceId: string,
|
|
18
19
|
normalizedPath: string,
|
|
19
20
|
contentHash: string,
|
|
20
21
|
): string {
|
|
21
|
-
return buildMdxEsmTransformCacheKey(projectId, normalizedPath, contentHash);
|
|
22
|
+
return buildMdxEsmTransformCacheKey(projectId, contentSourceId, normalizedPath, contentHash);
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export function getVersionedPathCacheKey(normalizedPath: string): string {
|