veryfront 0.0.72 → 0.0.74

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/dist/config.js CHANGED
@@ -66,6 +66,9 @@ var veryfrontConfigSchema = z.object({
66
66
  }).partial().optional(),
67
67
  router: z.enum(["app", "pages"]).optional(),
68
68
  defaultLayout: z.string().optional(),
69
+ layout: z.string().optional(),
70
+ provider: z.string().optional(),
71
+ app: z.string().optional(),
69
72
  theme: z.object({ colors: z.record(z.string()).optional() }).partial().optional(),
70
73
  build: z.object({
71
74
  outDir: z.string().optional(),
@@ -161,6 +164,8 @@ var veryfrontConfigSchema = z.object({
161
164
  apiBaseUrl: z.string().url(),
162
165
  apiToken: z.string(),
163
166
  projectSlug: z.string(),
167
+ proxyMode: z.boolean().optional(),
168
+ productionMode: z.boolean().optional(),
164
169
  cache: z.object({
165
170
  enabled: z.boolean().optional(),
166
171
  ttl: z.number().int().positive().optional(),
@@ -222,6 +227,9 @@ function findUnknownTopLevelKeys(input) {
222
227
  "experimental",
223
228
  "router",
224
229
  "defaultLayout",
230
+ "layout",
231
+ "provider",
232
+ "app",
225
233
  "theme",
226
234
  "build",
227
235
  "cache",
@@ -239,7 +247,7 @@ function findUnknownTopLevelKeys(input) {
239
247
  }
240
248
 
241
249
  // src/core/config/loader.ts
242
- import { join } from "node:path";
250
+ import { dirname, join } from "node:path";
243
251
 
244
252
  // src/core/utils/logger/logger.ts
245
253
  init_deno_env();
@@ -272,56 +280,158 @@ function getEnvironmentVariable(name) {
272
280
  }
273
281
  return void 0;
274
282
  }
283
+ function isProductionEnvironment() {
284
+ return getEnvironmentVariable("NODE_ENV") === "production";
285
+ }
275
286
 
276
287
  // src/core/utils/logger/logger.ts
277
288
  var cachedLogLevel;
289
+ var cachedLogFormat;
278
290
  function resolveLogLevel(force = false) {
279
291
  if (force || cachedLogLevel === void 0) {
280
292
  cachedLogLevel = getDefaultLevel();
281
293
  }
282
294
  return cachedLogLevel;
283
295
  }
284
- var ConsoleLogger = class {
285
- constructor(prefix, level = resolveLogLevel()) {
296
+ function resolveLogFormat(force = false) {
297
+ if (force || cachedLogFormat === void 0) {
298
+ cachedLogFormat = getDefaultFormat();
299
+ }
300
+ return cachedLogFormat;
301
+ }
302
+ function getDefaultFormat() {
303
+ const envFormat = getEnvironmentVariable("LOG_FORMAT");
304
+ if (envFormat === "json" || envFormat === "text") {
305
+ return envFormat;
306
+ }
307
+ return isProductionEnvironment() ? "json" : "text";
308
+ }
309
+ function serializeError(err) {
310
+ if (err instanceof Error) {
311
+ return {
312
+ name: err.name,
313
+ message: err.message,
314
+ stack: err.stack
315
+ };
316
+ }
317
+ if (err !== void 0 && err !== null) {
318
+ return {
319
+ name: "UnknownError",
320
+ message: String(err)
321
+ };
322
+ }
323
+ return void 0;
324
+ }
325
+ function extractContext(args) {
326
+ let context;
327
+ let error;
328
+ for (const arg of args) {
329
+ if (arg instanceof Error) {
330
+ error = serializeError(arg);
331
+ } else if (typeof arg === "object" && arg !== null && !Array.isArray(arg)) {
332
+ context = { ...context, ...arg };
333
+ }
334
+ }
335
+ return { context, error };
336
+ }
337
+ var ConsoleLogger = class _ConsoleLogger {
338
+ constructor(prefix, level = resolveLogLevel(), format = resolveLogFormat(), boundContext) {
286
339
  this.prefix = prefix;
287
340
  this.level = level;
341
+ this.format = format;
342
+ if (boundContext) {
343
+ this.boundContext = boundContext;
344
+ }
288
345
  }
346
+ boundContext = {};
289
347
  setLevel(level) {
290
348
  this.level = level;
291
349
  }
292
350
  getLevel() {
293
351
  return this.level;
294
352
  }
295
- debug(message, ...args) {
296
- if (this.level <= 0 /* DEBUG */) {
297
- console.debug(`[${this.prefix}] DEBUG: ${message}`, ...args);
353
+ setFormat(format) {
354
+ this.format = format;
355
+ }
356
+ getFormat() {
357
+ return this.format;
358
+ }
359
+ /**
360
+ * Create a child logger with additional bound context.
361
+ */
362
+ child(context) {
363
+ return new _ConsoleLogger(this.prefix, this.level, this.format, {
364
+ ...this.boundContext,
365
+ ...context
366
+ });
367
+ }
368
+ formatJson(level, message, args) {
369
+ const { context, error } = extractContext(args);
370
+ const entry = {
371
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
372
+ level,
373
+ service: this.prefix.toLowerCase(),
374
+ message
375
+ };
376
+ const mergedContext = { ...this.boundContext, ...context };
377
+ if (Object.keys(mergedContext).length > 0) {
378
+ if ("requestId" in mergedContext) {
379
+ entry.requestId = String(mergedContext.requestId);
380
+ delete mergedContext.requestId;
381
+ }
382
+ if ("traceId" in mergedContext) {
383
+ entry.traceId = String(mergedContext.traceId);
384
+ delete mergedContext.traceId;
385
+ }
386
+ if ("projectSlug" in mergedContext) {
387
+ entry.projectSlug = String(mergedContext.projectSlug);
388
+ delete mergedContext.projectSlug;
389
+ }
390
+ if ("durationMs" in mergedContext) {
391
+ entry.durationMs = Number(mergedContext.durationMs);
392
+ delete mergedContext.durationMs;
393
+ }
394
+ if (Object.keys(mergedContext).length > 0) {
395
+ entry.context = mergedContext;
396
+ }
298
397
  }
398
+ if (error) {
399
+ entry.error = error;
400
+ }
401
+ return JSON.stringify(entry);
299
402
  }
300
- info(message, ...args) {
301
- if (this.level <= 1 /* INFO */) {
302
- console.log(`[${this.prefix}] ${message}`, ...args);
403
+ log(level, logLevel, consoleFn, message, args) {
404
+ if (this.level > logLevel)
405
+ return;
406
+ if (this.format === "json") {
407
+ consoleFn(this.formatJson(level, message, args));
408
+ } else {
409
+ const prefix = level === "info" ? "" : ` ${level.toUpperCase()}:`;
410
+ consoleFn(`[${this.prefix}]${prefix} ${message}`, ...args);
303
411
  }
304
412
  }
413
+ debug(message, ...args) {
414
+ this.log("debug", 0 /* DEBUG */, console.debug, message, args);
415
+ }
416
+ info(message, ...args) {
417
+ this.log("info", 1 /* INFO */, console.log, message, args);
418
+ }
305
419
  warn(message, ...args) {
306
- if (this.level <= 2 /* WARN */) {
307
- console.warn(`[${this.prefix}] WARN: ${message}`, ...args);
308
- }
420
+ this.log("warn", 2 /* WARN */, console.warn, message, args);
309
421
  }
310
422
  error(message, ...args) {
311
- if (this.level <= 3 /* ERROR */) {
312
- console.error(`[${this.prefix}] ERROR: ${message}`, ...args);
313
- }
423
+ this.log("error", 3 /* ERROR */, console.error, message, args);
314
424
  }
315
425
  async time(label, fn) {
316
426
  const start = performance.now();
317
427
  try {
318
428
  const result = await fn();
319
- const end = performance.now();
320
- this.debug(`${label} completed in ${(end - start).toFixed(2)}ms`);
429
+ const durationMs = performance.now() - start;
430
+ this.debug(`${label} completed`, { durationMs: Math.round(durationMs) });
321
431
  return result;
322
432
  } catch (error) {
323
- const end = performance.now();
324
- this.error(`${label} failed after ${(end - start).toFixed(2)}ms`, error);
433
+ const durationMs = performance.now() - start;
434
+ this.error(`${label} failed`, { durationMs: Math.round(durationMs) }, error);
325
435
  throw error;
326
436
  }
327
437
  }
@@ -364,6 +474,7 @@ var serverLogger = createLogger("SERVER");
364
474
  var rendererLogger = createLogger("RENDERER");
365
475
  var bundlerLogger = createLogger("BUNDLER");
366
476
  var agentLogger = createLogger("AGENT");
477
+ var proxyLogger = createLogger("PROXY");
367
478
  var logger = createLogger("VERYFRONT");
368
479
 
369
480
  // src/core/utils/constants/cdn.ts
@@ -375,7 +486,7 @@ init_deno_env();
375
486
  // deno.json
376
487
  var deno_default = {
377
488
  name: "veryfront",
378
- version: "0.0.71",
489
+ version: "0.0.74",
379
490
  nodeModulesDir: "auto",
380
491
  exclude: [
381
492
  "npm/",
@@ -460,12 +571,12 @@ var deno_default = {
460
571
  csstype: "https://esm.sh/csstype@3.2.3",
461
572
  "@types/react": "https://esm.sh/@types/react@18.3.27?deps=csstype@3.2.3",
462
573
  "@types/react-dom": "https://esm.sh/@types/react-dom@18.3.7?deps=csstype@3.2.3",
463
- react: "https://esm.sh/react@18.3.1",
464
- "react-dom": "https://esm.sh/react-dom@18.3.1",
465
- "react-dom/server": "https://esm.sh/react-dom@18.3.1/server",
466
- "react-dom/client": "https://esm.sh/react-dom@18.3.1/client",
467
- "react/jsx-runtime": "https://esm.sh/react@18.3.1/jsx-runtime",
468
- "react/jsx-dev-runtime": "https://esm.sh/react@18.3.1/jsx-dev-runtime",
574
+ react: "npm:react@18.3.1",
575
+ "react-dom": "npm:react-dom@18.3.1",
576
+ "react-dom/server": "npm:react-dom@18.3.1/server.node",
577
+ "react-dom/client": "npm:react-dom@18.3.1/client",
578
+ "react/jsx-runtime": "npm:react@18.3.1/jsx-runtime",
579
+ "react/jsx-dev-runtime": "npm:react@18.3.1/jsx-dev-runtime",
469
580
  "@mdx-js/mdx": "npm:@mdx-js/mdx@3.0.0",
470
581
  "@mdx-js/react": "npm:@mdx-js/react@3.0.0",
471
582
  "unist-util-visit": "npm:unist-util-visit@5.0.0",
@@ -475,27 +586,36 @@ var deno_default = {
475
586
  "remark-frontmatter": "npm:remark-frontmatter@5.0.0",
476
587
  "rehype-highlight": "npm:rehype-highlight@7.0.2",
477
588
  "rehype-slug": "npm:rehype-slug@6.0.0",
478
- esbuild: "https://deno.land/x/esbuild@v0.20.1/wasm.js",
479
- "esbuild/mod.js": "https://deno.land/x/esbuild@v0.20.1/mod.js",
589
+ esbuild: "npm:esbuild@0.20.2",
590
+ "esbuild/mod.js": "npm:esbuild@0.20.2",
480
591
  "es-module-lexer": "npm:es-module-lexer@1.5.0",
481
- zod: "npm:zod@3.23.8",
592
+ zod: "npm:zod@3.25.76",
482
593
  "mime-types": "npm:mime-types@2.1.35",
483
594
  mdast: "npm:@types/mdast@4.0.3",
484
595
  hast: "npm:@types/hast@3.0.3",
485
596
  unist: "npm:@types/unist@3.0.2",
486
597
  unified: "npm:unified@11.0.5",
487
- ai: "https://esm.sh/ai@5.0.76?deps=react@18.3.1,react-dom@18.3.1",
488
- "ai/react": "https://esm.sh/@ai-sdk/react@2.0.1?deps=react@18.3.1,react-dom@18.3.1",
489
- "@ai-sdk/react": "https://esm.sh/@ai-sdk/react@2.0.1?deps=react@18.3.1,react-dom@18.3.1",
598
+ ai: "npm:ai@5.0.76",
599
+ "ai/react": "npm:@ai-sdk/react@2.0.1",
600
+ "@ai-sdk/react": "npm:@ai-sdk/react@2.0.1",
490
601
  "@ai-sdk/openai": "https://esm.sh/@ai-sdk/openai@2.0.1",
491
602
  "@ai-sdk/anthropic": "https://esm.sh/@ai-sdk/anthropic@2.0.1",
492
603
  unocss: "https://esm.sh/unocss@0.59.0",
493
604
  "@unocss/core": "https://esm.sh/@unocss/core@0.59.0",
494
605
  "@unocss/preset-wind": "https://esm.sh/@unocss/preset-wind@0.59.0",
606
+ "next-themes": "npm:next-themes@0.3.0",
495
607
  redis: "npm:redis",
496
608
  pg: "npm:pg",
497
609
  "@opentelemetry/api": "npm:@opentelemetry/api@1",
498
- "@opentelemetry/core": "npm:@opentelemetry/core@1"
610
+ "@opentelemetry/core": "npm:@opentelemetry/core@1",
611
+ "@opentelemetry/sdk-trace-base": "npm:@opentelemetry/sdk-trace-base@1",
612
+ "@opentelemetry/exporter-trace-otlp-http": "npm:@opentelemetry/exporter-trace-otlp-http@0.57",
613
+ "@opentelemetry/resources": "npm:@opentelemetry/resources@1",
614
+ "@opentelemetry/semantic-conventions": "npm:@opentelemetry/semantic-conventions@1",
615
+ "@babel/parser": "npm:@babel/parser@7.26.3",
616
+ "@babel/traverse": "npm:@babel/traverse@7.26.3",
617
+ "@babel/generator": "npm:@babel/generator@7.26.3",
618
+ "@babel/types": "npm:@babel/types@7.26.3"
499
619
  },
500
620
  compilerOptions: {
501
621
  jsx: "react-jsx",
@@ -503,7 +623,7 @@ var deno_default = {
503
623
  strict: true,
504
624
  noImplicitAny: true,
505
625
  noUncheckedIndexedAccess: true,
506
- types: [],
626
+ types: ["npm:@types/react@18"],
507
627
  lib: [
508
628
  "deno.window",
509
629
  "dom",
@@ -518,9 +638,9 @@ var deno_default = {
518
638
  build: "deno compile --allow-all --output ../../bin/veryfront src/cli/main.ts",
519
639
  "build:npm": "deno run -A scripts/build-npm.ts",
520
640
  release: "deno run -A scripts/release.ts",
521
- test: "DENO_JOBS=1 deno test --parallel --fail-fast --allow-all --unstable-worker-options --unstable-net",
522
- "test:unit": "DENO_JOBS=1 deno test --parallel --allow-all --v8-flags=--max-old-space-size=8192 --ignore=tests --unstable-worker-options --unstable-net",
523
- "test:integration": "DENO_JOBS=1 deno test --parallel --fail-fast --allow-all tests --unstable-worker-options --unstable-net",
641
+ test: "VF_DISABLE_LRU_INTERVAL=1 DENO_JOBS=1 deno test --parallel --fail-fast --allow-all --unstable-worker-options --unstable-net",
642
+ "test:unit": "VF_DISABLE_LRU_INTERVAL=1 DENO_JOBS=1 deno test --parallel --allow-all --v8-flags=--max-old-space-size=8192 --ignore=tests,src/ai/workflow/__tests__ --unstable-worker-options --unstable-net",
643
+ "test:integration": "VF_DISABLE_LRU_INTERVAL=1 DENO_JOBS=1 deno test --parallel --fail-fast --allow-all tests --unstable-worker-options --unstable-net",
524
644
  "test:coverage": "rm -rf coverage && DENO_JOBS=1 deno test --parallel --fail-fast --allow-all --coverage=coverage --unstable-worker-options --unstable-net || exit 1",
525
645
  "test:coverage:unit": "rm -rf coverage && DENO_JOBS=1 deno test --parallel --fail-fast --allow-all --coverage=coverage --ignore=tests --unstable-worker-options --unstable-net || exit 1",
526
646
  "test:coverage:integration": "rm -rf coverage && DENO_JOBS=1 deno test --parallel --fail-fast --allow-all --coverage=coverage tests --unstable-worker-options --unstable-net || exit 1",
@@ -585,7 +705,7 @@ init_deno_env();
585
705
 
586
706
  // src/platform/compat/runtime.ts
587
707
  init_deno_env();
588
- var isDeno = typeof Deno !== "undefined";
708
+ var isDeno = typeof Deno !== "undefined" && typeof Deno.version === "object";
589
709
  var isNode = typeof globalThis.process !== "undefined" && globalThis.process?.versions?.node !== void 0;
590
710
  var isBun = typeof globalThis.Bun !== "undefined";
591
711
  var isCloudflare = typeof globalThis !== "undefined" && "caches" in globalThis && "WebSocketPair" in globalThis;
@@ -605,6 +725,7 @@ function getEnv(key) {
605
725
 
606
726
  // src/core/utils/version.ts
607
727
  var VERSION = getEnv("VERYFRONT_VERSION") || (typeof deno_default.version === "string" ? deno_default.version : "0.0.0");
728
+ var SERVER_START_TIME = Date.now();
608
729
 
609
730
  // src/core/utils/constants/cdn.ts
610
731
  var ESM_CDN_BASE = "https://esm.sh";
@@ -775,6 +896,167 @@ var DEV_SERVER_ENDPOINTS = {
775
896
  ERROR_OVERLAY: INTERNAL_ENDPOINTS.ERROR_OVERLAY
776
897
  };
777
898
 
899
+ // src/platform/compat/fs.ts
900
+ init_deno_env();
901
+ var NodeFileSystem = class {
902
+ constructor() {
903
+ this.fs = null;
904
+ this.os = null;
905
+ this.path = null;
906
+ this.initialized = false;
907
+ }
908
+ async ensureInitialized() {
909
+ if (this.initialized)
910
+ return;
911
+ if (!isNode) {
912
+ throw toError(createError({
913
+ type: "not_supported",
914
+ message: "Node.js fs modules not available",
915
+ feature: "Node.js"
916
+ }));
917
+ }
918
+ const [fsModule, osModule, pathModule] = await Promise.all([
919
+ import("node:fs/promises"),
920
+ import("node:os"),
921
+ import("node:path")
922
+ ]);
923
+ this.fs = fsModule;
924
+ this.os = osModule;
925
+ this.path = pathModule;
926
+ this.initialized = true;
927
+ }
928
+ async readTextFile(path) {
929
+ await this.ensureInitialized();
930
+ return await this.fs.readFile(path, { encoding: "utf8" });
931
+ }
932
+ async readFile(path) {
933
+ await this.ensureInitialized();
934
+ return await this.fs.readFile(path);
935
+ }
936
+ async writeTextFile(path, data) {
937
+ await this.ensureInitialized();
938
+ await this.fs.writeFile(path, data, { encoding: "utf8" });
939
+ }
940
+ async writeFile(path, data) {
941
+ await this.ensureInitialized();
942
+ await this.fs.writeFile(path, data);
943
+ }
944
+ async exists(path) {
945
+ await this.ensureInitialized();
946
+ try {
947
+ await this.fs.access(path);
948
+ return true;
949
+ } catch (error) {
950
+ if (error.code === "ENOENT") {
951
+ return false;
952
+ }
953
+ throw error;
954
+ }
955
+ }
956
+ async stat(path) {
957
+ await this.ensureInitialized();
958
+ const stat = await this.fs.stat(path);
959
+ return {
960
+ isFile: stat.isFile(),
961
+ isDirectory: stat.isDirectory(),
962
+ isSymlink: stat.isSymbolicLink(),
963
+ size: stat.size,
964
+ mtime: stat.mtime
965
+ };
966
+ }
967
+ async mkdir(path, options) {
968
+ await this.ensureInitialized();
969
+ await this.fs.mkdir(path, { recursive: options?.recursive ?? false });
970
+ }
971
+ async *readDir(path) {
972
+ await this.ensureInitialized();
973
+ const entries = await this.fs.readdir(path, { withFileTypes: true });
974
+ for (const entry of entries) {
975
+ yield {
976
+ name: entry.name,
977
+ isFile: entry.isFile(),
978
+ isDirectory: entry.isDirectory()
979
+ };
980
+ }
981
+ }
982
+ async remove(path, options) {
983
+ await this.ensureInitialized();
984
+ await this.fs.rm(path, {
985
+ recursive: options?.recursive ?? false,
986
+ force: options?.recursive ?? false
987
+ });
988
+ }
989
+ async makeTempDir(options) {
990
+ await this.ensureInitialized();
991
+ const tempDir = this.path.join(
992
+ this.os.tmpdir(),
993
+ `${options?.prefix ?? "tmp-"}${Math.random().toString(36).substring(2, 8)}`
994
+ );
995
+ await this.fs.mkdir(tempDir, { recursive: true });
996
+ return tempDir;
997
+ }
998
+ };
999
+ var DenoFileSystem = class {
1000
+ async readTextFile(path) {
1001
+ return await Deno.readTextFile(path);
1002
+ }
1003
+ async readFile(path) {
1004
+ return await Deno.readFile(path);
1005
+ }
1006
+ async writeTextFile(path, data) {
1007
+ await Deno.writeTextFile(path, data);
1008
+ }
1009
+ async writeFile(path, data) {
1010
+ await Deno.writeFile(path, data);
1011
+ }
1012
+ async exists(path) {
1013
+ try {
1014
+ await Deno.stat(path);
1015
+ return true;
1016
+ } catch (error) {
1017
+ if (error instanceof Deno.errors.NotFound) {
1018
+ return false;
1019
+ }
1020
+ throw error;
1021
+ }
1022
+ }
1023
+ async stat(path) {
1024
+ const stat = await Deno.stat(path);
1025
+ return {
1026
+ isFile: stat.isFile,
1027
+ isDirectory: stat.isDirectory,
1028
+ isSymlink: stat.isSymlink,
1029
+ size: stat.size,
1030
+ mtime: stat.mtime
1031
+ };
1032
+ }
1033
+ async mkdir(path, options) {
1034
+ await Deno.mkdir(path, { recursive: options?.recursive ?? false });
1035
+ }
1036
+ async *readDir(path) {
1037
+ for await (const entry of Deno.readDir(path)) {
1038
+ yield {
1039
+ name: entry.name,
1040
+ isFile: entry.isFile,
1041
+ isDirectory: entry.isDirectory
1042
+ };
1043
+ }
1044
+ }
1045
+ async remove(path, options) {
1046
+ await Deno.remove(path, { recursive: options?.recursive ?? false });
1047
+ }
1048
+ async makeTempDir(options) {
1049
+ return await Deno.makeTempDir({ prefix: options?.prefix });
1050
+ }
1051
+ };
1052
+ function createFileSystem() {
1053
+ if (isDeno) {
1054
+ return new DenoFileSystem();
1055
+ } else {
1056
+ return new NodeFileSystem();
1057
+ }
1058
+ }
1059
+
778
1060
  // src/core/config/loader.ts
779
1061
  function getDefaultImportMapForConfig() {
780
1062
  return { imports: getReactImportMap(REACT_DEFAULT_VERSION) };
@@ -911,7 +1193,62 @@ var ConfigValidationError = class extends Error {
911
1193
  this.name = "ConfigValidationError";
912
1194
  }
913
1195
  };
914
- async function loadAndMergeConfig(configPath, projectDir) {
1196
+ function isVirtualFilesystem(adapter) {
1197
+ const wrappedAdapter = adapter?.fs?.fsAdapter;
1198
+ const adapterName = wrappedAdapter?.constructor?.name;
1199
+ return adapterName === "VeryfrontFSAdapter";
1200
+ }
1201
+ async function loadConfigFromVirtualFS(configPath, projectDir, adapter) {
1202
+ const fs = createFileSystem();
1203
+ const content = await adapter.fs.readFile(configPath);
1204
+ const source = typeof content === "string" ? content : new TextDecoder().decode(content);
1205
+ serverLogger.debug(`[CONFIG] Loading config from virtual FS: ${configPath}`);
1206
+ const isTsx = configPath.endsWith(".tsx");
1207
+ const loader = isTsx ? "tsx" : configPath.endsWith(".ts") ? "ts" : "js";
1208
+ const { build } = await import("esbuild");
1209
+ const result = await build({
1210
+ bundle: false,
1211
+ // Config files shouldn't need bundling
1212
+ write: false,
1213
+ format: "esm",
1214
+ platform: "neutral",
1215
+ target: "es2022",
1216
+ stdin: {
1217
+ contents: source,
1218
+ loader,
1219
+ resolveDir: dirname(configPath),
1220
+ sourcefile: configPath
1221
+ }
1222
+ });
1223
+ if (result.errors && result.errors.length > 0) {
1224
+ const first = result.errors[0]?.text || "unknown error";
1225
+ throw new ConfigValidationError(`Failed to transpile config: ${first}`);
1226
+ }
1227
+ const js = result.outputFiles?.[0]?.text ?? "export default {}";
1228
+ const tempDir = await fs.makeTempDir({ prefix: "vf-config-" });
1229
+ const tempFile = join(tempDir, "config.mjs");
1230
+ try {
1231
+ await fs.writeTextFile(tempFile, js);
1232
+ const configModule = await import(`file://${tempFile}?v=${Date.now()}`);
1233
+ const userConfig = configModule.default || configModule;
1234
+ if (userConfig === null || typeof userConfig !== "object" || Array.isArray(userConfig)) {
1235
+ throw new ConfigValidationError(
1236
+ `Expected object, received ${userConfig === null ? "null" : typeof userConfig}`
1237
+ );
1238
+ }
1239
+ validateCorsConfig(userConfig);
1240
+ validateConfigShape(userConfig);
1241
+ const merged = mergeConfigs(userConfig);
1242
+ configCacheByProject.set(projectDir, { revision: cacheRevision, config: merged });
1243
+ return merged;
1244
+ } finally {
1245
+ await fs.remove(tempDir, { recursive: true });
1246
+ }
1247
+ }
1248
+ async function loadAndMergeConfig(configPath, projectDir, adapter) {
1249
+ if (isVirtualFilesystem(adapter)) {
1250
+ return loadConfigFromVirtualFS(configPath, projectDir, adapter);
1251
+ }
915
1252
  try {
916
1253
  const configUrl = `file://${configPath}?t=${Date.now()}-${crypto.randomUUID()}`;
917
1254
  const configModule = await import(configUrl);
@@ -947,7 +1284,7 @@ async function getConfig(projectDir, adapter) {
947
1284
  if (!exists)
948
1285
  continue;
949
1286
  try {
950
- const merged = await loadAndMergeConfig(configPath, projectDir);
1287
+ const merged = await loadAndMergeConfig(configPath, projectDir, adapter);
951
1288
  if (merged)
952
1289
  return merged;
953
1290
  } catch (error) {