@valbuild/server 0.60.21 → 0.60.22

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.
@@ -12,7 +12,6 @@ import z, { z as z$1 } from 'zod';
12
12
  import { MIME_TYPES_TO_EXT, filenameToMimeType, VAL_ENABLE_COOKIE_NAME, VAL_STATE_COOKIE as VAL_STATE_COOKIE$1, VAL_SESSION_COOKIE as VAL_SESSION_COOKIE$1 } from '@valbuild/shared/internal';
13
13
  import sizeOf from 'image-size';
14
14
  import crypto from 'crypto';
15
- import minimatch from 'minimatch';
16
15
  import { createUIRequestHandler } from '@valbuild/ui/server';
17
16
 
18
17
  class ValSyntaxError {
@@ -662,7 +661,7 @@ const patchSourceFile = (sourceFile, patch) => {
662
661
  return applyPatch(sourceFile, ops$1, patch);
663
662
  };
664
663
 
665
- const readValFile = async (id, valConfigPath, runtime, options) => {
664
+ const readValFile = async (id, rootDirPath, runtime, options) => {
666
665
  const context = runtime.newContext();
667
666
 
668
667
  // avoid failures when console.log is called
@@ -714,7 +713,7 @@ globalThis.valModule = {
714
713
  `;
715
714
  const result = context.evalCode(code,
716
715
  // Synthetic module name
717
- path__default.join(path__default.dirname(valConfigPath), "<val>"));
716
+ path__default.join(rootDirPath, "<val>"));
718
717
  const fatalErrors = [];
719
718
  if (result.error) {
720
719
  const error = result.error.consume(context.dump);
@@ -1159,18 +1158,16 @@ async function createService(projectRoot, opts, host = {
1159
1158
  const sourceFileHandler = new ValSourceFileHandler(projectRoot, compilerOptions, host);
1160
1159
  const module = await newQuickJSWASMModule();
1161
1160
  const runtime = await newValQuickJSRuntime(module, loader || new ValModuleLoader(projectRoot, compilerOptions, sourceFileHandler, host, opts.disableCache === undefined ? process.env.NODE_ENV === "development" ? false : true : opts.disableCache));
1162
- return new Service(opts, sourceFileHandler, runtime);
1161
+ return new Service(projectRoot, sourceFileHandler, runtime);
1163
1162
  }
1164
1163
  class Service {
1165
- constructor({
1166
- valConfigPath
1167
- }, sourceFileHandler, runtime) {
1164
+ constructor(projectRoot, sourceFileHandler, runtime) {
1168
1165
  this.sourceFileHandler = sourceFileHandler;
1169
1166
  this.runtime = runtime;
1170
- this.valConfigPath = valConfigPath || "./val.config";
1167
+ this.projectRoot = projectRoot;
1171
1168
  }
1172
1169
  async get(moduleId, modulePath, options) {
1173
- const valModule = await readValFile(moduleId, this.valConfigPath, this.runtime, options ?? {
1170
+ const valModule = await readValFile(moduleId, this.projectRoot, this.runtime, options ?? {
1174
1171
  validate: true,
1175
1172
  source: true,
1176
1173
  schema: true
@@ -1194,7 +1191,7 @@ class Service {
1194
1191
  }
1195
1192
  }
1196
1193
  async patch(moduleId, patch) {
1197
- await patchValFile(moduleId, this.valConfigPath, patch, this.sourceFileHandler, this.runtime);
1194
+ await patchValFile(moduleId, this.projectRoot, patch, this.sourceFileHandler, this.runtime);
1198
1195
  }
1199
1196
  dispose() {
1200
1197
  this.runtime.dispose();
@@ -1385,9 +1382,8 @@ function getValidationErrorMetadata(validationError) {
1385
1382
 
1386
1383
  const ops = new JSONOps();
1387
1384
  class ValServer {
1388
- constructor(cwd, host, options, callbacks) {
1385
+ constructor(cwd, options, callbacks) {
1389
1386
  this.cwd = cwd;
1390
- this.host = host;
1391
1387
  this.options = options;
1392
1388
  this.callbacks = callbacks;
1393
1389
  }
@@ -1423,19 +1419,10 @@ class ValServer {
1423
1419
  redirectTo: redirectToRes
1424
1420
  };
1425
1421
  }
1426
- getAllModules(treePath) {
1427
- const moduleIds = this.host.readDirectory(this.cwd, ["ts", "js"], ["node_modules", ".*"], ["**/*.val.ts", "**/*.val.js"]).filter(file => {
1428
- if (treePath) {
1429
- return file.replace(this.cwd, "").startsWith(treePath);
1430
- }
1431
- return true;
1432
- }).map(file => file.replace(this.cwd, "").replace(".val.js", "").replace(".val.ts", "").split(path__default.sep).join("/"));
1433
- return moduleIds;
1434
- }
1435
1422
  async getTree(treePath,
1436
1423
  // TODO: use the params: patch, schema, source now we return everything, every time
1437
1424
  query, cookies, requestHeaders) {
1438
- const ensureRes = await this.ensureRemoteFSInitialized("getTree", cookies);
1425
+ const ensureRes = await this.ensureInitialized("getTree", cookies);
1439
1426
  if (result.isErr(ensureRes)) {
1440
1427
  return ensureRes.error;
1441
1428
  }
@@ -1443,7 +1430,7 @@ class ValServer {
1443
1430
  const execValidations = query.validate === "true";
1444
1431
  const includeSource = query.source === "true";
1445
1432
  const includeSchema = query.schema === "true";
1446
- const moduleIds = this.getAllModules(treePath);
1433
+ const moduleIds = await this.getAllModules(treePath);
1447
1434
  let {
1448
1435
  patchIdsByModuleId,
1449
1436
  patchesById,
@@ -1483,14 +1470,14 @@ class ValServer {
1483
1470
  };
1484
1471
  }
1485
1472
  async postValidate(rawBody, cookies, requestHeaders) {
1486
- const ensureRes = await this.ensureRemoteFSInitialized("postValidate", cookies);
1473
+ const ensureRes = await this.ensureInitialized("postValidate", cookies);
1487
1474
  if (result.isErr(ensureRes)) {
1488
1475
  return ensureRes.error;
1489
1476
  }
1490
1477
  return this.validateThenMaybeCommit(rawBody, false, cookies, requestHeaders);
1491
1478
  }
1492
1479
  async postCommit(rawBody, cookies, requestHeaders) {
1493
- const ensureRes = await this.ensureRemoteFSInitialized("postCommit", cookies);
1480
+ const ensureRes = await this.ensureInitialized("postCommit", cookies);
1494
1481
  if (result.isErr(ensureRes)) {
1495
1482
  return ensureRes.error;
1496
1483
  }
@@ -1516,7 +1503,6 @@ class ValServer {
1516
1503
  }
1517
1504
 
1518
1505
  /* */
1519
-
1520
1506
  async applyAllPatchesThenValidate(moduleId, patchIdsByModuleId, patchesById, fileUpdates, cookies, requestHeaders, applyPatches, validate, includeSource, includeSchema) {
1521
1507
  const serializedModuleContent = await this.getModule(moduleId, {
1522
1508
  validate: validate,
@@ -1781,7 +1767,7 @@ class ValServer {
1781
1767
  fileUpdates
1782
1768
  } = res.value;
1783
1769
  const validationErrorsByModuleId = {};
1784
- for (const moduleIdStr of this.getAllModules("/")) {
1770
+ for (const moduleIdStr of await this.getAllModules("/")) {
1785
1771
  const moduleId = moduleIdStr;
1786
1772
  const serializedModuleContent = await this.applyAllPatchesThenValidate(moduleId, filterPatchesByModuleIdRes.data.patches ||
1787
1773
  // TODO: refine to ModuleId and PatchId when parsing
@@ -2024,10 +2010,11 @@ class LocalValServer extends ValServer {
2024
2010
  static PATCHES_DIR = "patches";
2025
2011
  static FILES_DIR = "files";
2026
2012
  constructor(options, callbacks) {
2027
- super(options.service.sourceFileHandler.projectRoot, options.service.sourceFileHandler.host, options, callbacks);
2013
+ super(options.service.sourceFileHandler.projectRoot, options, callbacks);
2028
2014
  this.options = options;
2029
2015
  this.callbacks = callbacks;
2030
2016
  this.patchesRootPath = options.cacheDir || path__default.join(options.service.sourceFileHandler.projectRoot, ".val");
2017
+ this.host = this.options.service.sourceFileHandler.host;
2031
2018
  }
2032
2019
  async session() {
2033
2020
  return {
@@ -2285,13 +2272,22 @@ class LocalValServer extends ValServer {
2285
2272
  }
2286
2273
  };
2287
2274
  }
2288
- async ensureRemoteFSInitialized() {
2275
+ async ensureInitialized() {
2289
2276
  // No RemoteFS so nothing to ensure
2290
2277
  return result.ok(undefined);
2291
2278
  }
2292
2279
  getModule(moduleId, options) {
2293
2280
  return this.options.service.get(moduleId, "", options);
2294
2281
  }
2282
+ async getAllModules(treePath) {
2283
+ const moduleIds = this.host.readDirectory(this.cwd, ["ts", "js"], ["node_modules", ".*"], ["**/*.val.ts", "**/*.val.js"]).filter(file => {
2284
+ if (treePath) {
2285
+ return file.replace(this.cwd, "").startsWith(treePath);
2286
+ }
2287
+ return true;
2288
+ }).map(file => file.replace(this.cwd, "").replace(".val.js", "").replace(".val.ts", "").split(path__default.sep).join("/"));
2289
+ return moduleIds;
2290
+ }
2295
2291
  async execCommit(patches) {
2296
2292
  for (const [patchId, moduleId, patch] of patches) {
2297
2293
  // TODO: patch the entire module content directly by using a { path: "", op: "replace", value: patchedData }?
@@ -2378,219 +2374,32 @@ function encodeJwt(payload, sessionKey) {
2378
2374
  return `${jwtHeaderBase64}.${payloadBase64}.${crypto.createHmac("sha256", sessionKey).update(`${jwtHeaderBase64}.${payloadBase64}`).digest("base64")}`;
2379
2375
  }
2380
2376
 
2381
- const SEPARATOR = "/";
2382
- class RemoteFS {
2383
- initialized = false;
2384
- constructor() {
2385
- this.data = {};
2386
- this.modifiedFiles = [];
2387
- this.deletedFiles = [];
2388
- }
2389
- useCaseSensitiveFileNames = true;
2390
- isInitialized() {
2391
- return this.initialized;
2392
- }
2393
- async initializeWith(data) {
2394
- this.data = data;
2395
- this.initialized = true;
2396
- }
2397
- async getPendingOperations() {
2398
- const modified = {};
2399
- for (const modifiedFile of this.modifiedFiles) {
2400
- const {
2401
- directory,
2402
- filename
2403
- } = RemoteFS.parsePath(modifiedFile);
2404
- modified[modifiedFile] = this.data[directory].utf8Files[filename];
2405
- }
2406
- return {
2407
- modified: modified,
2408
- deleted: this.deletedFiles
2409
- };
2410
- }
2411
- changedDirectories = {};
2412
- readDirectory = (rootDir, extensions, excludes, includes, depth) => {
2413
- // TODO: rewrite this! And make some tests! This is a mess!
2414
- // Considered using glob which typescript seems to use, but that works on an entire typeof fs
2415
- // glob uses minimatch internally, so using that instead
2416
- const files = [];
2417
- for (const dir in this.data) {
2418
- const depthExceeded = depth ? dir.replace(rootDir, "").split(SEPARATOR).length > depth : false;
2419
- if (dir.startsWith(rootDir) && !depthExceeded) {
2420
- for (const file in this.data[dir].utf8Files) {
2421
- for (const extension of extensions) {
2422
- if (file.endsWith(extension)) {
2423
- const path = `${dir}/${file}`;
2424
- for (const include of includes ?? []) {
2425
- // TODO: should default includes be ['**/*']?
2426
- if (minimatch(path, include)) {
2427
- let isExcluded = false;
2428
- for (const exlude of excludes ?? []) {
2429
- if (minimatch(path, exlude)) {
2430
- isExcluded = true;
2431
- break;
2432
- }
2433
- }
2434
- if (!isExcluded) {
2435
- files.push(path);
2436
- }
2437
- }
2438
- }
2439
- }
2440
- }
2441
- }
2442
- }
2443
- }
2444
- return ts.sys.readDirectory(rootDir, extensions, excludes, includes, depth).concat(files);
2445
- };
2446
- writeFile = (filePath, data, encoding) => {
2447
- // never write real fs
2448
- const {
2449
- directory,
2450
- filename
2451
- } = RemoteFS.parsePath(filePath);
2452
- if (this.data[directory] === undefined) {
2453
- throw new Error(`Directory not found: ${directory}`);
2454
- }
2455
- this.changedDirectories[directory] = this.changedDirectories[directory] ?? new Set();
2456
-
2457
- // if it fails below this should not be added, so maybe a try/catch?
2458
- this.changedDirectories[directory].add(filename);
2459
- this.data[directory].utf8Files[filename] = data;
2460
- this.modifiedFiles.push(filePath);
2461
- };
2462
- rmFile(filePath) {
2463
- // never remove from real fs
2464
- const {
2465
- directory,
2466
- filename
2467
- } = RemoteFS.parsePath(filePath);
2468
- if (this.data[directory] === undefined) {
2469
- throw new Error(`Directory not found: ${directory}`);
2470
- }
2471
- this.changedDirectories[directory] = this.changedDirectories[directory] ?? new Set();
2472
-
2473
- // if it fails below this should not be added, so maybe a try/catch?
2474
- this.changedDirectories[directory].add(filename);
2475
- delete this.data[directory].utf8Files[filename];
2476
- delete this.data[directory].symlinks[filename];
2477
- this.deletedFiles.push(filePath);
2478
- }
2479
- fileExists = filePath => {
2480
- var _this$data$directory;
2481
- if (ts.sys.fileExists(filePath)) {
2482
- return true;
2483
- }
2484
- const {
2485
- directory,
2486
- filename
2487
- } = RemoteFS.parsePath(this.realpath(filePath) // ts.sys seems to resolve symlinks while calling fileExists, i.e. a broken symlink (pointing to a non-existing file) is not considered to exist
2488
- );
2489
- return !!((_this$data$directory = this.data[directory]) !== null && _this$data$directory !== void 0 && _this$data$directory.utf8Files[filename]);
2490
- };
2491
- readFile = filePath => {
2492
- const realFile = ts.sys.readFile(filePath);
2493
- if (realFile !== undefined) {
2494
- return realFile;
2495
- }
2496
- const {
2497
- directory,
2498
- filename
2499
- } = RemoteFS.parsePath(filePath);
2500
- const dirNode = this.data[directory];
2501
- if (!dirNode) {
2502
- return undefined;
2503
- }
2504
- const content = dirNode.utf8Files[filename];
2505
- return content;
2506
- };
2507
- realpath(fullPath) {
2508
- if (ts.sys.fileExists(fullPath) && ts.sys.realpath) {
2509
- return ts.sys.realpath(fullPath);
2510
- }
2511
- // TODO: this only works in a very limited way.
2512
- // It does not support symlinks to symlinks nor symlinked directories for instance.
2513
- const {
2514
- directory,
2515
- filename
2516
- } = RemoteFS.parsePath(fullPath);
2517
- if (this.data[directory] === undefined) {
2518
- return fullPath;
2519
- }
2520
- if (this.data[directory].utf8Files[filename] === undefined) {
2521
- const link = this.data[directory].symlinks[filename];
2522
- if (link === undefined) {
2523
- return fullPath;
2524
- } else {
2525
- return link;
2526
- }
2527
- } else {
2528
- return path__default.join(directory, filename);
2529
- }
2530
- }
2531
-
2532
- /**
2533
- *
2534
- * @param path
2535
- * @returns directory and filename. NOTE: directory might be empty string
2536
- */
2537
- static parsePath(path) {
2538
- const pathParts = path.split(SEPARATOR);
2539
- const filename = pathParts.pop();
2540
- if (!filename) {
2541
- throw new Error(`Invalid path: '${path}'. Node filename: '${filename}'`);
2542
- }
2543
- const directory = pathParts.join(SEPARATOR);
2544
- return {
2545
- directory,
2546
- filename
2547
- };
2548
- }
2549
- }
2550
-
2551
- /**
2552
- * Represents directories
2553
- * NOTE: the keys of directory nodes are the "full" path, i.e. "foo/bar"
2554
- * NOTE: the keys of file nodes are the "filename" only, i.e. "baz.txt"
2555
- *
2556
- * @example
2557
- * {
2558
- * "foo/bar": { // <- directory. NOTE: this is the "full" path
2559
- * gitHubSha: "123",
2560
- * files: {
2561
- * "baz.txt": "hello world" // <- file. NOTE: this is the "filename" only
2562
- * },
2563
- * },
2564
- * };
2565
- */
2566
- // TODO: a Map would be better here
2567
-
2568
2377
  class ProxyValServer extends ValServer {
2569
- moduleCache = {};
2378
+ moduleCache = null;
2570
2379
  constructor(cwd, options, apiOptions, callbacks) {
2571
- const remoteFS = new RemoteFS();
2572
- super(cwd, remoteFS, options, callbacks);
2380
+ super(cwd, options, callbacks);
2573
2381
  this.cwd = cwd;
2574
2382
  this.options = options;
2575
2383
  this.apiOptions = apiOptions;
2576
2384
  this.callbacks = callbacks;
2577
- this.remoteFS = remoteFS;
2385
+ this.moduleCache = null;
2578
2386
  }
2579
2387
 
2580
2388
  /** Remote FS dependent methods: */
2581
2389
 
2582
- async getModule(moduleId, options) {
2583
- const cacheKey = moduleId + ";" + JSON.stringify(options) + this.options.git.commit + this.cwd;
2584
- const cachedModule = this.moduleCache[cacheKey];
2585
- if (cachedModule) {
2586
- return Promise.resolve(cachedModule);
2390
+ async getModule(moduleId,
2391
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2392
+ _options) {
2393
+ if (this.moduleCache) {
2394
+ return this.moduleCache[moduleId];
2587
2395
  }
2588
- if (!this.lazyService) {
2589
- this.lazyService = await createService(this.cwd, this.apiOptions, this.remoteFS);
2396
+ throw new Error("Module cache not initialized");
2397
+ }
2398
+ async getAllModules(treePath) {
2399
+ if (!this.moduleCache) {
2400
+ throw new Error("Module cache not initialized");
2590
2401
  }
2591
- const currentModule = await this.lazyService.get(moduleId, "", options);
2592
- this.moduleCache[cacheKey] = currentModule;
2593
- return currentModule;
2402
+ return Object.keys(this.moduleCache).filter(moduleId => moduleId.startsWith(treePath));
2594
2403
  }
2595
2404
  execCommit(patches, cookies) {
2596
2405
  return withAuth(this.options.valSecret, cookies, "execCommit", async ({
@@ -2605,46 +2414,19 @@ class ProxyValServer extends ValServer {
2605
2414
  }
2606
2415
  };
2607
2416
  }
2608
- const params = `commit=${encodeURIComponent(commit)}&root=${encodeURIComponent(this.apiOptions.root || "/")}&cwd=${encodeURIComponent(this.cwd)}`;
2417
+ const params = createParams({
2418
+ root: this.apiOptions.root,
2419
+ commit,
2420
+ ext: ["ts", "js", "json"],
2421
+ package: ["@valbuild/core@" + this.options.versions.core, "@valbuild/next@" + this.options.versions.next],
2422
+ include: ["**/*.val.{js,ts},package.json,tsconfig.json,jsconfig.json"]
2423
+ });
2609
2424
  const url = new URL(`/v1/commit/${this.options.remote}/heads/${this.options.git.branch}/~?${params}`, this.options.valContentUrl);
2610
-
2611
- // Creates a fresh copy of the fs. We cannot touch the existing fs, since there might be parallel operations?
2612
- // We could perhaps free up the other fs while doing this operation, but uncertain if we can actually do that and if that would actually help on memory.
2613
- // It is a concern we have, since we might be using quite a lot of memory when having the whole FS in memory.
2614
- // NOTE that base64 values from patches are not part of the patches, nor are they part of the fs so at least we do not have to worry about them.
2615
- // This NOTE was written after we wrote the comments above. We are a bit uncertain whether memory usage should be a concern at this point.
2616
- const remoteFS = new RemoteFS();
2617
- const initRes = await this.initRemoteFS(commit, remoteFS, token);
2618
- if (initRes.status !== 200) {
2619
- return initRes;
2620
- }
2621
- const service = await createService(this.cwd, this.apiOptions, remoteFS);
2622
- // TODO: optimize patches, e.g. only take the last replace for a given thing, etc...
2623
- const patchIds = [];
2624
- const binaryFileUpdates = {};
2625
- for (const [patchId, moduleId, patch] of patches) {
2626
- const patchableOps = [];
2627
- for (const op of patch) {
2628
- if (isCachedPatchFileOp(op)) {
2629
- binaryFileUpdates[op.filePath] = op.value;
2630
- } else {
2631
- if (Internal.isFileOp(op)) {
2632
- throw new Error(`Val: Unexpected file operation (file: ${op.filePath}). This is likely a Val bug.`);
2633
- }
2634
- patchableOps.push(op);
2635
- }
2636
- }
2637
- await service.patch(moduleId, patchableOps);
2638
- patchIds.push(patchId);
2639
- }
2640
- const sourceFileUpdates = await remoteFS.getPendingOperations();
2425
+ const patchIds = patches.map(([patchId]) => patchId);
2641
2426
  const fetchRes = await fetch(url, {
2642
2427
  method: "POST",
2643
2428
  headers: getAuthHeaders(token, "application/json"),
2644
2429
  body: JSON.stringify({
2645
- sourceFileUpdates: sourceFileUpdates.modified,
2646
- binaryFileUpdates,
2647
- deletedFiles: sourceFileUpdates.deleted,
2648
2430
  patchIds
2649
2431
  })
2650
2432
  });
@@ -2658,14 +2440,15 @@ class ProxyValServer extends ValServer {
2658
2440
  }
2659
2441
  });
2660
2442
  }
2661
- async initRemoteFS(commit, remoteFS, token) {
2662
- const params = new URLSearchParams(this.apiOptions.root ? {
2443
+ async init(commit, token) {
2444
+ const params = createParams({
2663
2445
  root: this.apiOptions.root,
2664
- commit
2665
- } : {
2666
- commit
2446
+ commit,
2447
+ ext: ["ts", "js", "json"],
2448
+ package: ["@valbuild/core@" + this.options.versions.core, "@valbuild/next@" + this.options.versions.next],
2449
+ include: ["**/*.val.{js,ts},package.json,tsconfig.json,jsconfig.json"]
2667
2450
  });
2668
- const url = new URL(`/v1/fs/${this.options.remote}/heads/${this.options.git.branch}/~?${params}`, this.options.valContentUrl);
2451
+ const url = new URL(`/v1/eval/${this.options.remote}/heads/${this.options.git.branch}/~?${params}`, this.options.valContentUrl);
2669
2452
  try {
2670
2453
  const fetchRes = await fetch(url, {
2671
2454
  headers: getAuthHeaders(token, "application/json")
@@ -2688,22 +2471,22 @@ class ProxyValServer extends ValServer {
2688
2471
  details: "Invalid response: missing git.commit"
2689
2472
  };
2690
2473
  }
2691
- if (typeof json.directories !== "object" || json.directories === null) {
2474
+ if (typeof json.modules !== "object" || json.modules === null) {
2692
2475
  error = {
2693
- details: "Invalid response: missing directories"
2476
+ details: "Invalid response: missing modules"
2694
2477
  };
2695
2478
  }
2696
2479
  if (error) {
2480
+ console.error("Could not initialize remote modules", error);
2697
2481
  return {
2698
2482
  status: 500,
2699
2483
  json: {
2700
- message: "Failed to fetch remote files",
2484
+ message: "Failed to fetch remote modules",
2701
2485
  ...error
2702
2486
  }
2703
2487
  };
2704
2488
  }
2705
- remoteFS.initializeWith(Object.fromEntries(Object.entries(json.directories).map(([dir, content]) => [path__default.join(this.cwd, ...dir.split("/") // content is always posix - not sure that matters...
2706
- ), content])));
2489
+ this.moduleCache = json.modules;
2707
2490
  return {
2708
2491
  status: 200
2709
2492
  };
@@ -2719,7 +2502,7 @@ class ProxyValServer extends ValServer {
2719
2502
  };
2720
2503
  }
2721
2504
  }
2722
- async ensureRemoteFSInitialized(errorMessageType, cookies) {
2505
+ async ensureInitialized(errorMessageType, cookies) {
2723
2506
  const commit = this.options.git.commit;
2724
2507
  if (!commit) {
2725
2508
  return result.err({
@@ -2730,8 +2513,8 @@ class ProxyValServer extends ValServer {
2730
2513
  });
2731
2514
  }
2732
2515
  const res = await withAuth(this.options.valSecret, cookies, errorMessageType, async data => {
2733
- if (!this.remoteFS.isInitialized()) {
2734
- return this.initRemoteFS(commit, this.remoteFS, data.token);
2516
+ if (!this.moduleCache) {
2517
+ return this.init(commit, data.token);
2735
2518
  } else {
2736
2519
  return {
2737
2520
  status: 200
@@ -3052,11 +2835,33 @@ class ProxyValServer extends ValServer {
3052
2835
  };
3053
2836
  }
3054
2837
  const host = `${reqHeaders["x-forwarded-proto"]}://${reqHeaders["host"]}`;
3055
- const fileUrl = filePath.slice("/public".length);
3056
- return {
3057
- status: 302,
3058
- redirectTo: new URL(fileUrl, host).toString()
3059
- };
2838
+ const staticPublicUrl = new URL(filePath.slice("/public".length), host).toString();
2839
+ const fetchRes = await fetch(staticPublicUrl, {
2840
+ headers: getAuthHeaders(data.token)
2841
+ });
2842
+ if (fetchRes.status === 200) {
2843
+ // TODO: does this stream data?
2844
+ if (fetchRes.body) {
2845
+ return {
2846
+ status: fetchRes.status,
2847
+ headers: {
2848
+ "Content-Type": fetchRes.headers.get("Content-Type") || "",
2849
+ "Content-Length": fetchRes.headers.get("Content-Length") || "0",
2850
+ "Cache-Control": "public, max-age=31536000, immutable"
2851
+ },
2852
+ body: fetchRes.body
2853
+ };
2854
+ } else {
2855
+ return {
2856
+ status: 500,
2857
+ json: {
2858
+ message: "No body in response"
2859
+ }
2860
+ };
2861
+ }
2862
+ } else {
2863
+ throw new Error("Failed to fetch file: " + filePath);
2864
+ }
3060
2865
  }
3061
2866
  });
3062
2867
  }
@@ -3248,6 +3053,25 @@ function getAuthHeaders(token, type) {
3248
3053
  Authorization: `Bearer ${token}`
3249
3054
  };
3250
3055
  }
3056
+ function createParams(params) {
3057
+ let paramIdx = 0;
3058
+ let paramsString = "";
3059
+ for (const key in params) {
3060
+ const param = params[key];
3061
+ if (Array.isArray(param)) {
3062
+ for (const value of param) {
3063
+ paramsString += `${key}=${encodeURIComponent(value)}&`;
3064
+ }
3065
+ } else if (param) {
3066
+ paramsString += `${key}=${encodeURIComponent(param)}`;
3067
+ }
3068
+ if (paramIdx < Object.keys(params).length - 1) {
3069
+ paramsString += "&";
3070
+ }
3071
+ paramIdx++;
3072
+ }
3073
+ return paramsString;
3074
+ }
3251
3075
 
3252
3076
  async function createValServer(route, opts, callbacks) {
3253
3077
  const serverOpts = await initHandlerOptions(route, opts);
@@ -3263,6 +3087,7 @@ async function initHandlerOptions(route, opts) {
3263
3087
  const maybeValSecret = opts.valSecret || process.env.VAL_SECRET;
3264
3088
  const isProxyMode = opts.mode === "proxy" || opts.mode === undefined && (maybeApiKey || maybeValSecret);
3265
3089
  if (isProxyMode) {
3090
+ var _opts$versions, _opts$versions2;
3266
3091
  const valBuildUrl = opts.valBuildUrl || process.env.VAL_BUILD_URL || "https://app.val.build";
3267
3092
  if (!maybeApiKey || !maybeValSecret) {
3268
3093
  throw new Error("VAL_API_KEY and VAL_SECRET env vars must both be set in proxy mode");
@@ -3280,6 +3105,14 @@ async function initHandlerOptions(route, opts) {
3280
3105
  if (!maybeValRemote) {
3281
3106
  throw new Error("Proxy mode does not work unless the 'remote' option in val.config is defined or the VAL_REMOTE env var is set.");
3282
3107
  }
3108
+ const coreVersion = (_opts$versions = opts.versions) === null || _opts$versions === void 0 ? void 0 : _opts$versions.core;
3109
+ if (!coreVersion) {
3110
+ throw new Error("Could not determine version of @valbuild/core");
3111
+ }
3112
+ const nextVersion = (_opts$versions2 = opts.versions) === null || _opts$versions2 === void 0 ? void 0 : _opts$versions2.next;
3113
+ if (!nextVersion) {
3114
+ throw new Error("Could not determine version of @valbuild/next");
3115
+ }
3283
3116
  return {
3284
3117
  mode: "proxy",
3285
3118
  route,
@@ -3287,6 +3120,10 @@ async function initHandlerOptions(route, opts) {
3287
3120
  valSecret: maybeValSecret,
3288
3121
  valBuildUrl,
3289
3122
  valContentUrl,
3123
+ versions: {
3124
+ core: coreVersion,
3125
+ next: nextVersion
3126
+ },
3290
3127
  git: {
3291
3128
  commit: maybeGitCommit,
3292
3129
  branch: maybeGitBranch
package/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "./package.json": "./package.json"
13
13
  },
14
14
  "types": "dist/valbuild-server.cjs.d.ts",
15
- "version": "0.60.21",
15
+ "version": "0.60.22",
16
16
  "scripts": {
17
17
  "typecheck": "tsc --noEmit",
18
18
  "test": "jest",
@@ -24,9 +24,9 @@
24
24
  "concurrently": "^7.6.0"
25
25
  },
26
26
  "dependencies": {
27
- "@valbuild/core": "~0.60.21",
28
- "@valbuild/shared": "~0.60.21",
29
- "@valbuild/ui": "~0.60.21",
27
+ "@valbuild/core": "~0.60.22",
28
+ "@valbuild/shared": "~0.60.22",
29
+ "@valbuild/ui": "~0.60.22",
30
30
  "express": "^4.18.2",
31
31
  "image-size": "^1.0.2",
32
32
  "minimatch": "^3.0.4",