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,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distributed recovery for missing MDX ESM module dependencies.
|
|
3
|
+
*
|
|
4
|
+
* Restores missing vfmod files on fresh pods from the distributed transform
|
|
5
|
+
* cache, scoped to the current project and content source.
|
|
6
|
+
*
|
|
7
|
+
* @module transforms/mdx/esm-module-loader/module-fetcher/dependency-recovery
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { basename, dirname } from "../../../../platform/compat/path/index.js";
|
|
11
|
+
import { detokenizeAllCachePaths } from "../../../../cache/index.js";
|
|
12
|
+
import type { CacheBackend } from "../../../../cache/types.js";
|
|
13
|
+
import type { Logger } from "../../../../utils/logger/logger.js";
|
|
14
|
+
import { getDistributedTransformBackend } from "../../../esm/transform-cache.js";
|
|
15
|
+
import { ensureHttpBundlesExist } from "../../../esm/http-cache.js";
|
|
16
|
+
import { extractHttpBundlePaths } from "../../../../modules/react-loader/ssr-module-loader/http-bundle-helpers.js";
|
|
17
|
+
import { getHttpBundleCacheDir } from "../../../../utils/cache-dir.js";
|
|
18
|
+
import { LOG_PREFIX_MDX_LOADER } from "../constants.js";
|
|
19
|
+
import { getLocalFs } from "../cache/index.js";
|
|
20
|
+
import { buildMdxEsmModuleRecoveryCacheKey } from "../cache-format.js";
|
|
21
|
+
|
|
22
|
+
const MDX_VFMOD_FILE_URL_PATTERN = /file:\/\/([^"'\s]+veryfront-mdx-esm\/[^"'\s]+\.mjs)/gi;
|
|
23
|
+
|
|
24
|
+
interface EnsureMdxModuleDependenciesOptions {
|
|
25
|
+
projectId: string;
|
|
26
|
+
contentSourceId: string;
|
|
27
|
+
log: Logger;
|
|
28
|
+
distributedCache?: CacheBackend | null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface EnsureMdxModuleDependenciesResult {
|
|
32
|
+
recovered: string[];
|
|
33
|
+
missing: string[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function extractMdxModuleDependencyPaths(code: string): string[] {
|
|
37
|
+
const paths: string[] = [];
|
|
38
|
+
const seen = new Set<string>();
|
|
39
|
+
let match: RegExpExecArray | null;
|
|
40
|
+
while ((match = MDX_VFMOD_FILE_URL_PATTERN.exec(code)) !== null) {
|
|
41
|
+
const rawPath = match[1];
|
|
42
|
+
if (!rawPath) continue;
|
|
43
|
+
const cleanPath = rawPath.replace(/\?.*$/, "");
|
|
44
|
+
if (seen.has(cleanPath)) continue;
|
|
45
|
+
seen.add(cleanPath);
|
|
46
|
+
paths.push(cleanPath);
|
|
47
|
+
}
|
|
48
|
+
return paths;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function ensureHttpBundleDependencies(code: string, log: Logger): Promise<boolean> {
|
|
52
|
+
const bundlePaths = extractHttpBundlePaths(code);
|
|
53
|
+
if (bundlePaths.length === 0) return true;
|
|
54
|
+
|
|
55
|
+
const failed = await ensureHttpBundlesExist(bundlePaths, getHttpBundleCacheDir());
|
|
56
|
+
if (failed.length === 0) return true;
|
|
57
|
+
|
|
58
|
+
log.warn(`${LOG_PREFIX_MDX_LOADER} Failed to recover HTTP bundles for vfmod dependency`, {
|
|
59
|
+
failed,
|
|
60
|
+
totalBundles: bundlePaths.length,
|
|
61
|
+
});
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function ensureModuleFileAndDeps(
|
|
66
|
+
absolutePath: string,
|
|
67
|
+
distributedCache: CacheBackend,
|
|
68
|
+
options: EnsureMdxModuleDependenciesOptions,
|
|
69
|
+
visited: Set<string>,
|
|
70
|
+
recovered: Set<string>,
|
|
71
|
+
): Promise<boolean> {
|
|
72
|
+
if (visited.has(absolutePath)) return true;
|
|
73
|
+
visited.add(absolutePath);
|
|
74
|
+
|
|
75
|
+
const localFs = getLocalFs();
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
const stat = await localFs.stat(absolutePath);
|
|
79
|
+
if (stat?.isFile) {
|
|
80
|
+
const existingCode = await localFs.readTextFile(absolutePath);
|
|
81
|
+
if (!(await ensureHttpBundleDependencies(existingCode, options.log))) return false;
|
|
82
|
+
|
|
83
|
+
for (const nestedPath of extractMdxModuleDependencyPaths(existingCode)) {
|
|
84
|
+
if (
|
|
85
|
+
!(await ensureModuleFileAndDeps(
|
|
86
|
+
nestedPath,
|
|
87
|
+
distributedCache,
|
|
88
|
+
options,
|
|
89
|
+
visited,
|
|
90
|
+
recovered,
|
|
91
|
+
))
|
|
92
|
+
) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
} catch (_) {
|
|
100
|
+
/* expected: dependency may not exist on this pod yet */
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const recoveryKey = buildMdxEsmModuleRecoveryCacheKey(
|
|
104
|
+
options.projectId,
|
|
105
|
+
options.contentSourceId,
|
|
106
|
+
basename(absolutePath),
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const portableCode = await distributedCache.get(recoveryKey);
|
|
110
|
+
if (!portableCode) {
|
|
111
|
+
options.log.debug(`${LOG_PREFIX_MDX_LOADER} No distributed vfmod recovery entry`, {
|
|
112
|
+
dependencyPath: absolutePath,
|
|
113
|
+
recoveryKey,
|
|
114
|
+
});
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const recoveredCode = detokenizeAllCachePaths(portableCode);
|
|
119
|
+
if (!(await ensureHttpBundleDependencies(recoveredCode, options.log))) return false;
|
|
120
|
+
|
|
121
|
+
for (const nestedPath of extractMdxModuleDependencyPaths(recoveredCode)) {
|
|
122
|
+
if (
|
|
123
|
+
!(await ensureModuleFileAndDeps(
|
|
124
|
+
nestedPath,
|
|
125
|
+
distributedCache,
|
|
126
|
+
options,
|
|
127
|
+
visited,
|
|
128
|
+
recovered,
|
|
129
|
+
))
|
|
130
|
+
) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
await localFs.mkdir(dirname(absolutePath), { recursive: true });
|
|
136
|
+
await localFs.writeTextFile(absolutePath, recoveredCode);
|
|
137
|
+
recovered.add(absolutePath);
|
|
138
|
+
|
|
139
|
+
options.log.debug(`${LOG_PREFIX_MDX_LOADER} Recovered vfmod dependency from distributed cache`, {
|
|
140
|
+
dependencyPath: absolutePath,
|
|
141
|
+
recoveryKey,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function ensureMdxModuleDependencies(
|
|
148
|
+
code: string,
|
|
149
|
+
options: EnsureMdxModuleDependenciesOptions,
|
|
150
|
+
): Promise<EnsureMdxModuleDependenciesResult> {
|
|
151
|
+
const distributedCache = options.distributedCache ?? (await getDistributedTransformBackend());
|
|
152
|
+
if (!distributedCache) return { recovered: [], missing: extractMdxModuleDependencyPaths(code) };
|
|
153
|
+
|
|
154
|
+
const visited = new Set<string>();
|
|
155
|
+
const recovered = new Set<string>();
|
|
156
|
+
const missing: string[] = [];
|
|
157
|
+
|
|
158
|
+
for (const dependencyPath of extractMdxModuleDependencyPaths(code)) {
|
|
159
|
+
const ok = await ensureModuleFileAndDeps(
|
|
160
|
+
dependencyPath,
|
|
161
|
+
distributedCache,
|
|
162
|
+
options,
|
|
163
|
+
visited,
|
|
164
|
+
recovered,
|
|
165
|
+
);
|
|
166
|
+
if (!ok) missing.push(dependencyPath);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
recovered: [...recovered],
|
|
171
|
+
missing,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
@@ -23,6 +23,9 @@ import {
|
|
|
23
23
|
findMissingFileDependenciesInCode,
|
|
24
24
|
hasIncompatibleFrameworkPaths,
|
|
25
25
|
} from "./framework-validator.js";
|
|
26
|
+
import { ensureMdxModuleDependencies } from "./dependency-recovery.js";
|
|
27
|
+
import { buildMdxEsmModuleFileName, buildMdxEsmModuleRecoveryCacheKey } from "../cache-format.js";
|
|
28
|
+
import { hashString } from "../utils/hash.js";
|
|
26
29
|
|
|
27
30
|
/** TTL for cached transforms (uses centralized config) */
|
|
28
31
|
const TRANSFORM_CACHE_TTL_SECONDS = TRANSFORM_DISTRIBUTED_TTL_SEC;
|
|
@@ -59,6 +62,8 @@ interface DistributedCacheReadResult {
|
|
|
59
62
|
*/
|
|
60
63
|
export async function readDistributedCache(
|
|
61
64
|
transformCacheKey: string,
|
|
65
|
+
projectId: string,
|
|
66
|
+
contentSourceId: string | undefined,
|
|
62
67
|
normalizedPath: string,
|
|
63
68
|
projectSlug: string,
|
|
64
69
|
projectDir: string,
|
|
@@ -129,10 +134,26 @@ export async function readDistributedCache(
|
|
|
129
134
|
// that don't exist on this machine.
|
|
130
135
|
if (moduleCode) {
|
|
131
136
|
const missingDeps = await findMissingFileDependenciesInCode(moduleCode, log);
|
|
132
|
-
if (missingDeps.length > 0) {
|
|
137
|
+
if (missingDeps.length > 0 && contentSourceId) {
|
|
138
|
+
const recovered = await ensureMdxModuleDependencies(moduleCode, {
|
|
139
|
+
distributedCache,
|
|
140
|
+
projectId,
|
|
141
|
+
contentSourceId,
|
|
142
|
+
log,
|
|
143
|
+
});
|
|
144
|
+
if (recovered.recovered.length > 0) {
|
|
145
|
+
log.debug(`${LOG_PREFIX_MDX_LOADER} Recovered missing vfmod dependencies from cache`, {
|
|
146
|
+
normalizedPath,
|
|
147
|
+
recovered: recovered.recovered.slice(0, 5),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const unresolvedDeps = await findMissingFileDependenciesInCode(moduleCode, log);
|
|
153
|
+
if (unresolvedDeps.length > 0) {
|
|
133
154
|
log.warn(
|
|
134
|
-
`${LOG_PREFIX_MDX_LOADER} Cached code has ${
|
|
135
|
-
{ normalizedPath, missingDeps:
|
|
155
|
+
`${LOG_PREFIX_MDX_LOADER} Cached code has ${unresolvedDeps.length} missing file dependencies, invalidating`,
|
|
156
|
+
{ normalizedPath, missingDeps: unresolvedDeps.slice(0, 5) },
|
|
136
157
|
);
|
|
137
158
|
moduleCode = null;
|
|
138
159
|
}
|
|
@@ -177,6 +198,8 @@ export async function readDistributedCache(
|
|
|
177
198
|
export function writeDistributedCache(
|
|
178
199
|
distributedCache: DistributedCache,
|
|
179
200
|
transformCacheKey: string,
|
|
201
|
+
projectId: string,
|
|
202
|
+
contentSourceId: string,
|
|
180
203
|
moduleCode: string,
|
|
181
204
|
normalizedPath: string,
|
|
182
205
|
log: Logger,
|
|
@@ -195,6 +218,23 @@ export function writeDistributedCache(
|
|
|
195
218
|
});
|
|
196
219
|
});
|
|
197
220
|
|
|
221
|
+
const moduleFileName = buildMdxEsmModuleFileName(hashString(normalizedPath + moduleCode));
|
|
222
|
+
const moduleRecoveryKey = buildMdxEsmModuleRecoveryCacheKey(
|
|
223
|
+
projectId,
|
|
224
|
+
contentSourceId,
|
|
225
|
+
moduleFileName,
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
distributedCache
|
|
229
|
+
.set(moduleRecoveryKey, portableCode, TRANSFORM_CACHE_TTL_SECONDS)
|
|
230
|
+
.catch((error) => {
|
|
231
|
+
log.debug(`${LOG_PREFIX_MDX_LOADER} Distributed vfmod recovery set failed`, {
|
|
232
|
+
normalizedPath,
|
|
233
|
+
moduleRecoveryKey,
|
|
234
|
+
error,
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
198
238
|
// Create and store bundle manifest companion key for atomic validation
|
|
199
239
|
const bundlePaths = extractHttpBundlePaths(moduleCode);
|
|
200
240
|
if (bundlePaths.length > 0) {
|
|
@@ -14,6 +14,12 @@ import { getLocalFs } from "../cache/index.js";
|
|
|
14
14
|
import { extractHttpBundlePaths } from "../../../../modules/react-loader/ssr-module-loader/http-bundle-helpers.js";
|
|
15
15
|
import { ensureHttpBundlesExist } from "../../../esm/http-cache.js";
|
|
16
16
|
import { MDX_ESM_MJS_FILE_URL_PATTERN_SOURCE } from "../cache-format.js";
|
|
17
|
+
import { ensureMdxModuleDependencies } from "./dependency-recovery.js";
|
|
18
|
+
|
|
19
|
+
interface MdxRecoveryOptions {
|
|
20
|
+
projectId: string;
|
|
21
|
+
contentSourceId: string;
|
|
22
|
+
}
|
|
17
23
|
|
|
18
24
|
/**
|
|
19
25
|
* Check if cached code has file:// paths that are incompatible with this environment.
|
|
@@ -157,6 +163,7 @@ export async function validateCachedModule(
|
|
|
157
163
|
log: Logger,
|
|
158
164
|
pathCache: Map<string, string>,
|
|
159
165
|
versionedKey: string,
|
|
166
|
+
recoveryOptions?: MdxRecoveryOptions,
|
|
160
167
|
): Promise<boolean> {
|
|
161
168
|
// Reject caches with raw HTTP URLs - all modules should use file:// paths.
|
|
162
169
|
// This ensures consistency between compiled and non-compiled modes.
|
|
@@ -192,6 +199,36 @@ export async function validateCachedModule(
|
|
|
192
199
|
}
|
|
193
200
|
}
|
|
194
201
|
|
|
202
|
+
if (recoveryOptions) {
|
|
203
|
+
const recovered = await ensureMdxModuleDependencies(cachedCode, {
|
|
204
|
+
...recoveryOptions,
|
|
205
|
+
log,
|
|
206
|
+
});
|
|
207
|
+
if (recovered.recovered.length > 0) {
|
|
208
|
+
log.debug(`${LOG_PREFIX_MDX_LOADER} Recovered cached module vfmod dependencies`, {
|
|
209
|
+
normalizedPath,
|
|
210
|
+
cachedPath,
|
|
211
|
+
recovered: recovered.recovered.slice(0, 5),
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const missingDeps = await findMissingFileDependenciesInCode(cachedCode, log);
|
|
217
|
+
if (missingDeps.length > 0) {
|
|
218
|
+
log.warn(`${LOG_PREFIX_MDX_LOADER} Cached module has missing vfmod dependencies`, {
|
|
219
|
+
normalizedPath,
|
|
220
|
+
cachedPath,
|
|
221
|
+
missingDeps: missingDeps.slice(0, 5),
|
|
222
|
+
});
|
|
223
|
+
pathCache.delete(versionedKey);
|
|
224
|
+
try {
|
|
225
|
+
await getLocalFs().remove(cachedPath);
|
|
226
|
+
} catch (_) {
|
|
227
|
+
/* expected: cached file may already be removed */
|
|
228
|
+
}
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
|
|
195
232
|
if (!(await hasIncompatibleFrameworkPaths(cachedCode, log))) return true;
|
|
196
233
|
|
|
197
234
|
log.warn(`${LOG_PREFIX_MDX_LOADER} Cached module has incompatible framework paths`, {
|
|
@@ -190,7 +190,7 @@ async function doFetchAndCacheModule(
|
|
|
190
190
|
parentModulePath?: string,
|
|
191
191
|
): Promise<string | null> {
|
|
192
192
|
const log = getLog(context);
|
|
193
|
-
const { esmCacheDir, adapter, projectDir, projectId } = context;
|
|
193
|
+
const { esmCacheDir, adapter, projectDir, projectId, contentSourceId } = context;
|
|
194
194
|
|
|
195
195
|
const pathCache = await getModulePathCache(esmCacheDir);
|
|
196
196
|
const versionedKey = getVersionedPathCacheKey(normalizedPath);
|
|
@@ -209,6 +209,12 @@ async function doFetchAndCacheModule(
|
|
|
209
209
|
log,
|
|
210
210
|
pathCache,
|
|
211
211
|
versionedKey,
|
|
212
|
+
context.contentSourceId
|
|
213
|
+
? {
|
|
214
|
+
projectId: context.projectId,
|
|
215
|
+
contentSourceId: context.contentSourceId,
|
|
216
|
+
}
|
|
217
|
+
: undefined,
|
|
212
218
|
)
|
|
213
219
|
) {
|
|
214
220
|
recordModuleToSession(normalizedPath);
|
|
@@ -252,7 +258,9 @@ async function doFetchAndCacheModule(
|
|
|
252
258
|
const { sourceCode, actualFilePath } = resolved;
|
|
253
259
|
|
|
254
260
|
const contentHash = hashString(sourceCode);
|
|
255
|
-
const transformCacheKey =
|
|
261
|
+
const transformCacheKey = contentSourceId
|
|
262
|
+
? getTransformCacheKey(projectId, contentSourceId, normalizedPath, contentHash)
|
|
263
|
+
: null;
|
|
256
264
|
|
|
257
265
|
let moduleCode: string | null = null;
|
|
258
266
|
let needsDistributedCacheWrite = false;
|
|
@@ -260,14 +268,18 @@ async function doFetchAndCacheModule(
|
|
|
260
268
|
// Try distributed cache read with full validation.
|
|
261
269
|
// Returns null only if no distributed backend is configured.
|
|
262
270
|
// Otherwise returns { code, distributedCache } where code may be null (miss).
|
|
263
|
-
const distResult =
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
+
const distResult = transformCacheKey
|
|
272
|
+
? await readDistributedCache(
|
|
273
|
+
transformCacheKey,
|
|
274
|
+
projectId,
|
|
275
|
+
contentSourceId,
|
|
276
|
+
normalizedPath,
|
|
277
|
+
projectSlug,
|
|
278
|
+
projectDir,
|
|
279
|
+
context.reactVersion,
|
|
280
|
+
log,
|
|
281
|
+
)
|
|
282
|
+
: null;
|
|
271
283
|
if (distResult?.code) {
|
|
272
284
|
moduleCode = distResult.code;
|
|
273
285
|
}
|
|
@@ -402,10 +414,12 @@ async function doFetchAndCacheModule(
|
|
|
402
414
|
|
|
403
415
|
// Write to distributed cache AFTER nested imports are resolved.
|
|
404
416
|
// This ensures other pods get fully-resolved code without /_vf_modules/ paths.
|
|
405
|
-
if (needsDistributedCacheWrite && distResult?.distributedCache) {
|
|
417
|
+
if (needsDistributedCacheWrite && distResult?.distributedCache && transformCacheKey) {
|
|
406
418
|
writeDistributedCache(
|
|
407
419
|
distResult.distributedCache,
|
|
408
420
|
transformCacheKey,
|
|
421
|
+
projectId,
|
|
422
|
+
contentSourceId!,
|
|
409
423
|
moduleCode,
|
|
410
424
|
normalizedPath,
|
|
411
425
|
log,
|
|
@@ -449,6 +463,7 @@ export function createModuleFetcherContext(
|
|
|
449
463
|
projectDir: string,
|
|
450
464
|
projectId: string,
|
|
451
465
|
options?: {
|
|
466
|
+
contentSourceId?: string;
|
|
452
467
|
isLocalProject?: boolean;
|
|
453
468
|
projectSlug?: string;
|
|
454
469
|
reactVersion?: string;
|
package/src/src/utils/version.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { getEnv } from "../platform/compat/process.js";
|
|
|
3
3
|
|
|
4
4
|
// Keep in sync with deno.json version.
|
|
5
5
|
// scripts/release.ts updates this constant during releases.
|
|
6
|
-
export const VERSION = "0.1.
|
|
6
|
+
export const VERSION = "0.1.97";
|
|
7
7
|
|
|
8
8
|
export function normalizeVeryfrontVersion(version: string | undefined): string | undefined {
|
|
9
9
|
if (!version) return undefined;
|
|
@@ -27,6 +27,8 @@ import type {
|
|
|
27
27
|
import { generateId, parseDuration } from "../types.js";
|
|
28
28
|
import { hasLockSupport, type WorkflowBackend } from "../backends/types.js";
|
|
29
29
|
import { getCurrentRequestContext } from "../../platform/adapters/fs/veryfront/multi-project-adapter.js";
|
|
30
|
+
import { env as getProcessEnv } from "../../platform/compat/process.js";
|
|
31
|
+
import { mergeInjectedWorkflowEnv } from "../../jobs/runtime-env.js";
|
|
30
32
|
import { DAGExecutor } from "./dag-executor.js";
|
|
31
33
|
import { CheckpointManager } from "./checkpoint-manager.js";
|
|
32
34
|
import { runWithWorkflowTenant, StepExecutor, type StepExecutorConfig } from "./step-executor.js";
|
|
@@ -196,6 +198,7 @@ export class WorkflowExecutor {
|
|
|
196
198
|
releaseId: requestCtx.releaseId ?? null,
|
|
197
199
|
}
|
|
198
200
|
: undefined;
|
|
201
|
+
const injectedProjectEnv = mergeInjectedWorkflowEnv(undefined, getProcessEnv());
|
|
199
202
|
|
|
200
203
|
const run: WorkflowRun<TInput, TOutput> = {
|
|
201
204
|
id: options?.runId ?? generateId("run"),
|
|
@@ -205,7 +208,10 @@ export class WorkflowExecutor {
|
|
|
205
208
|
input,
|
|
206
209
|
nodeStates: {},
|
|
207
210
|
currentNodes: [],
|
|
208
|
-
context: {
|
|
211
|
+
context: {
|
|
212
|
+
input,
|
|
213
|
+
...(injectedProjectEnv ? { env: injectedProjectEnv } : {}),
|
|
214
|
+
},
|
|
209
215
|
checkpoints: [],
|
|
210
216
|
pendingApprovals: [],
|
|
211
217
|
createdAt: new Date(),
|
|
@@ -27,9 +27,11 @@
|
|
|
27
27
|
|
|
28
28
|
import { logger as baseLogger } from "../../utils/index.js";
|
|
29
29
|
import { getEnv } from "../../platform/compat/process.js";
|
|
30
|
+
import { env as getProcessEnv } from "../../platform/compat/process.js";
|
|
30
31
|
import { runWithRequestContext } from "../../platform/adapters/fs/veryfront/multi-project-adapter.js";
|
|
31
32
|
import { enhanceAdapterWithFS } from "../../platform/adapters/fs/integration.js";
|
|
32
33
|
import { denoAdapter } from "../../platform/adapters/runtime/deno/index.js";
|
|
34
|
+
import { mergeInjectedWorkflowEnv } from "../../jobs/runtime-env.js";
|
|
33
35
|
import { discoverWorkflows } from "../discovery/index.js";
|
|
34
36
|
import type { VeryfrontConfig } from "../../config/index.js";
|
|
35
37
|
import type { WorkflowBackend } from "../backends/types.js";
|
|
@@ -109,12 +111,28 @@ export async function runDynamicWorkflowJob(
|
|
|
109
111
|
|
|
110
112
|
try {
|
|
111
113
|
// Fetch the workflow run
|
|
112
|
-
|
|
114
|
+
let run = await backend.getRun(runId);
|
|
113
115
|
if (!run) {
|
|
114
116
|
logger.error(`Workflow run not found: ${runId}`);
|
|
115
117
|
return DYNAMIC_EXIT_CODES.NOT_FOUND;
|
|
116
118
|
}
|
|
117
119
|
|
|
120
|
+
const injectedEnv = mergeInjectedWorkflowEnv(run.context.env, getProcessEnv());
|
|
121
|
+
if (injectedEnv) {
|
|
122
|
+
const currentEnv = run.context.env;
|
|
123
|
+
const currentSerialized = currentEnv ? JSON.stringify(currentEnv) : "";
|
|
124
|
+
const nextSerialized = JSON.stringify(injectedEnv);
|
|
125
|
+
if (currentSerialized !== nextSerialized) {
|
|
126
|
+
await backend.updateRun(runId, {
|
|
127
|
+
context: {
|
|
128
|
+
...run.context,
|
|
129
|
+
env: injectedEnv,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
run = (await backend.getRun(runId)) ?? run;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
118
136
|
// Get tenant context (from env or from stored run)
|
|
119
137
|
const tenant = getTenantFromEnv() ?? run._tenant;
|
|
120
138
|
|
|
@@ -22,7 +22,9 @@
|
|
|
22
22
|
|
|
23
23
|
import { logger as baseLogger } from "../../utils/index.js";
|
|
24
24
|
import { getEnv } from "../../platform/compat/process.js";
|
|
25
|
+
import { env as getProcessEnv } from "../../platform/compat/process.js";
|
|
25
26
|
import { runWithRequestContext } from "../../platform/adapters/fs/veryfront/multi-project-adapter.js";
|
|
27
|
+
import { mergeInjectedWorkflowEnv } from "../../jobs/runtime-env.js";
|
|
26
28
|
import type { WorkflowBackend } from "../backends/types.js";
|
|
27
29
|
import type { WorkflowExecutor } from "../executor/workflow-executor.js";
|
|
28
30
|
import type { CapturedTenantContext, WorkflowDefinition } from "../types.js";
|
|
@@ -116,12 +118,28 @@ export async function runWorkflowJob(config: JobEntrypointConfig): Promise<numbe
|
|
|
116
118
|
|
|
117
119
|
try {
|
|
118
120
|
// Fetch the workflow run
|
|
119
|
-
|
|
121
|
+
let run = await backend.getRun(runId);
|
|
120
122
|
if (!run) {
|
|
121
123
|
logger.error(`Workflow run not found: ${runId}`);
|
|
122
124
|
return EXIT_CODES.NOT_FOUND;
|
|
123
125
|
}
|
|
124
126
|
|
|
127
|
+
const injectedEnv = mergeInjectedWorkflowEnv(run.context.env, getProcessEnv());
|
|
128
|
+
if (injectedEnv) {
|
|
129
|
+
const currentEnv = run.context.env;
|
|
130
|
+
const currentSerialized = currentEnv ? JSON.stringify(currentEnv) : "";
|
|
131
|
+
const nextSerialized = JSON.stringify(injectedEnv);
|
|
132
|
+
if (currentSerialized !== nextSerialized) {
|
|
133
|
+
await backend.updateRun(runId, {
|
|
134
|
+
context: {
|
|
135
|
+
...run.context,
|
|
136
|
+
env: injectedEnv,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
run = (await backend.getRun(runId)) ?? run;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
125
143
|
// Get tenant context (from env or from stored run)
|
|
126
144
|
const tenant = getTenantFromEnv() ?? run._tenant;
|
|
127
145
|
|