@valbuild/server 0.60.16 → 0.60.17

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.
@@ -32,9 +32,9 @@ export declare abstract class ValServer implements IValServer {
32
32
  patch?: string;
33
33
  schema?: string;
34
34
  source?: string;
35
- }, cookies: ValCookies<VAL_SESSION_COOKIE>): Promise<ValServerJsonResult<ApiTreeResponse>>;
36
- postValidate(rawBody: unknown, cookies: ValCookies<VAL_SESSION_COOKIE>): Promise<ValServerJsonResult<ApiPostValidationResponse | ApiPostValidationErrorResponse>>;
37
- postCommit(rawBody: unknown, cookies: ValCookies<VAL_SESSION_COOKIE>): Promise<ValServerJsonResult<ApiCommitResponse, ApiPostValidationErrorResponse>>;
35
+ }, cookies: ValCookies<VAL_SESSION_COOKIE>, requestHeaders: RequestHeaders): Promise<ValServerJsonResult<ApiTreeResponse>>;
36
+ postValidate(rawBody: unknown, cookies: ValCookies<VAL_SESSION_COOKIE>, requestHeaders: RequestHeaders): Promise<ValServerJsonResult<ApiPostValidationResponse | ApiPostValidationErrorResponse>>;
37
+ postCommit(rawBody: unknown, cookies: ValCookies<VAL_SESSION_COOKIE>, requestHeaders: RequestHeaders): Promise<ValServerJsonResult<ApiCommitResponse, ApiPostValidationErrorResponse>>;
38
38
  private applyAllPatchesThenValidate;
39
39
  private revalidateImageAndFileValidation;
40
40
  protected sortPatchIds(patchesByModule: Record<ModuleId, {
@@ -69,7 +69,7 @@ export declare abstract class ValServer implements IValServer {
69
69
  } | ValServerError>;
70
70
  abstract getFiles(filePath: string, query: {
71
71
  sha256?: string;
72
- }, cookies: ValCookies<VAL_SESSION_COOKIE>): Promise<ValServerResult<never, ReadableStream<Uint8Array>>>;
72
+ }, cookies: ValCookies<VAL_SESSION_COOKIE>, requestHeaders: RequestHeaders): Promise<ValServerResult<never, ReadableStream<Uint8Array>> | ValServerRedirectResult<VAL_ENABLE_COOKIE_NAME>>;
73
73
  abstract session(cookies: ValCookies<VAL_SESSION_COOKIE>): Promise<ValServerJsonResult<ValSession>>;
74
74
  abstract authorize(query: {
75
75
  redirect_to?: string;
@@ -129,7 +129,7 @@ export interface IValServer {
129
129
  patch?: string;
130
130
  schema?: string;
131
131
  source?: string;
132
- }, cookies: ValCookies<VAL_SESSION_COOKIE>): Promise<ValServerJsonResult<ApiTreeResponse>>;
132
+ }, cookies: ValCookies<VAL_SESSION_COOKIE>, requestHeaders: RequestHeaders): Promise<ValServerJsonResult<ApiTreeResponse>>;
133
133
  getPatches(query: {
134
134
  id?: string[];
135
135
  }, cookies: ValCookies<VAL_SESSION_COOKIE>): Promise<ValServerJsonResult<ApiGetPatchResponse>>;
@@ -137,11 +137,11 @@ export interface IValServer {
137
137
  deletePatches(query: {
138
138
  id?: string[];
139
139
  }, cookies: ValCookies<VAL_SESSION_COOKIE>): Promise<ValServerJsonResult<ApiDeletePatchResponse>>;
140
- postValidate(body: unknown, cookies: ValCookies<VAL_SESSION_COOKIE>): Promise<ValServerJsonResult<ApiPostValidationResponse | ApiPostValidationErrorResponse>>;
141
- postCommit(body: unknown, cookies: ValCookies<VAL_SESSION_COOKIE>): Promise<ValServerJsonResult<ApiCommitResponse, ApiPostValidationErrorResponse>>;
140
+ postValidate(body: unknown, cookies: ValCookies<VAL_SESSION_COOKIE>, requestHeaders: RequestHeaders): Promise<ValServerJsonResult<ApiPostValidationResponse | ApiPostValidationErrorResponse>>;
141
+ postCommit(body: unknown, cookies: ValCookies<VAL_SESSION_COOKIE>, requestHeaders: RequestHeaders): Promise<ValServerJsonResult<ApiCommitResponse, ApiPostValidationErrorResponse>>;
142
142
  getFiles(filePath: string, query: {
143
143
  sha256?: string;
144
- }, cookies: ValCookies<VAL_SESSION_COOKIE>): Promise<ValServerResult<never, ReadableStream<Uint8Array>>>;
144
+ }, cookies: ValCookies<VAL_SESSION_COOKIE>, requestHeaders: RequestHeaders): Promise<ValServerResult<never, ReadableStream<Uint8Array>> | ValServerRedirectResult<VAL_ENABLE_COOKIE_NAME>>;
145
145
  }
146
146
  export declare function guessMimeTypeFromPath(filePath: string): string | null;
147
147
  export declare function isCachedPatchFileOp(op: Operation): op is {
@@ -152,3 +152,7 @@ export declare function isCachedPatchFileOp(op: Operation): op is {
152
152
  sha256: string;
153
153
  };
154
154
  };
155
+ export type RequestHeaders = {
156
+ host?: string | null;
157
+ "x-forwarded-proto"?: string | null;
158
+ };
@@ -1032,7 +1032,7 @@ export const IS_DEV = false;
1032
1032
  }
1033
1033
  if (modulePath.startsWith("react/jsx-runtime")) {
1034
1034
  return {
1035
- value: "export const jsx = () => { throw Error(`Cannot use 'jsx' in this type of file`) }; export default new Proxy({}, { get() { return () => { throw new Error(`Cannot import 'react' in this file`) } } } ); export const jsxs = () => { throw Error(`Cannot use 'jsxs' in this type of file`) };"
1035
+ value: "export const jsx = () => { throw Error(`Cannot use 'jsx' in this type of file`) }; export const Fragment = () => { throw Error(`Cannot use 'Fragment' in this type of file`) }; export default new Proxy({}, { get() { return () => { throw new Error(`Cannot import 'react' in this file`) } } } ); export const jsxs = () => { throw Error(`Cannot use 'jsxs' in this type of file`) };"
1036
1036
  };
1037
1037
  }
1038
1038
  if (modulePath.startsWith("react")) {
@@ -1419,7 +1419,7 @@ class ValServer {
1419
1419
  }
1420
1420
  async getTree(treePath,
1421
1421
  // TODO: use the params: patch, schema, source now we return everything, every time
1422
- query, cookies) {
1422
+ query, cookies, requestHeaders) {
1423
1423
  const ensureRes = await this.ensureRemoteFSInitialized("getTree", cookies);
1424
1424
  if (fp.result.isErr(ensureRes)) {
1425
1425
  return ensureRes.error;
@@ -1445,7 +1445,7 @@ class ValServer {
1445
1445
  fileUpdates = res.value.fileUpdates;
1446
1446
  }
1447
1447
  const possiblyPatchedContent = await Promise.all(moduleIds.map(async moduleId => {
1448
- return this.applyAllPatchesThenValidate(moduleId, patchIdsByModuleId, patchesById, fileUpdates, applyPatches, cookies);
1448
+ return this.applyAllPatchesThenValidate(moduleId, patchIdsByModuleId, patchesById, fileUpdates, applyPatches, cookies, requestHeaders);
1449
1449
  }));
1450
1450
  const modules = Object.fromEntries(possiblyPatchedContent.map(serializedModuleContent => {
1451
1451
  const module = {
@@ -1464,19 +1464,19 @@ class ValServer {
1464
1464
  json: apiTreeResponse
1465
1465
  };
1466
1466
  }
1467
- async postValidate(rawBody, cookies) {
1467
+ async postValidate(rawBody, cookies, requestHeaders) {
1468
1468
  const ensureRes = await this.ensureRemoteFSInitialized("postValidate", cookies);
1469
1469
  if (fp.result.isErr(ensureRes)) {
1470
1470
  return ensureRes.error;
1471
1471
  }
1472
- return this.validateThenMaybeCommit(rawBody, false, cookies);
1472
+ return this.validateThenMaybeCommit(rawBody, false, cookies, requestHeaders);
1473
1473
  }
1474
- async postCommit(rawBody, cookies) {
1474
+ async postCommit(rawBody, cookies, requestHeaders) {
1475
1475
  const ensureRes = await this.ensureRemoteFSInitialized("postCommit", cookies);
1476
1476
  if (fp.result.isErr(ensureRes)) {
1477
1477
  return ensureRes.error;
1478
1478
  }
1479
- const res = await this.validateThenMaybeCommit(rawBody, true, cookies);
1479
+ const res = await this.validateThenMaybeCommit(rawBody, true, cookies, requestHeaders);
1480
1480
  if (res.status === 200) {
1481
1481
  if (res.json.validationErrors) {
1482
1482
  return {
@@ -1499,7 +1499,7 @@ class ValServer {
1499
1499
 
1500
1500
  /* */
1501
1501
 
1502
- async applyAllPatchesThenValidate(moduleId, patchIdsByModuleId, patchesById, fileUpdates, applyPatches, cookies) {
1502
+ async applyAllPatchesThenValidate(moduleId, patchIdsByModuleId, patchesById, fileUpdates, applyPatches, cookies, requestHeaders) {
1503
1503
  const serializedModuleContent = await this.getModule(moduleId);
1504
1504
  const schema = serializedModuleContent.schema;
1505
1505
  const maybeSource = serializedModuleContent.source;
@@ -1543,7 +1543,7 @@ class ValServer {
1543
1543
  }
1544
1544
  const validationErrors = core.deserializeSchema(schema).validate(moduleId, source);
1545
1545
  if (validationErrors) {
1546
- const revalidated = await this.revalidateImageAndFileValidation(validationErrors, fileUpdates, cookies);
1546
+ const revalidated = await this.revalidateImageAndFileValidation(validationErrors, fileUpdates, cookies, requestHeaders);
1547
1547
  return {
1548
1548
  path: moduleId,
1549
1549
  schema,
@@ -1566,7 +1566,7 @@ class ValServer {
1566
1566
  // The reason is that validate will be called inside QuickJS (in the future, hopefully),
1567
1567
  // which does not have access to the filesystem, at least not at the time of writing this comment.
1568
1568
  // If you are reading this, and we still are not using QuickJS to validate, this assumption might be wrong.
1569
- async revalidateImageAndFileValidation(validationErrors, fileUpdates, cookies) {
1569
+ async revalidateImageAndFileValidation(validationErrors, fileUpdates, cookies, requestHeaders) {
1570
1570
  const revalidatedValidationErrors = {};
1571
1571
  for (const pathStr in validationErrors) {
1572
1572
  const errorSourcePath = pathStr;
@@ -1588,7 +1588,7 @@ class ValServer {
1588
1588
  if (updatedFileMetadata) {
1589
1589
  const fileRes = await this.getFiles(fileRef, {
1590
1590
  sha256: updatedFileMetadata.sha256
1591
- }, cookies);
1591
+ }, cookies, requestHeaders);
1592
1592
  if (fileRes.status === 200 && fileRes.body) {
1593
1593
  const res = new Response(fileRes.body);
1594
1594
  fileBuffer = Buffer.from(await res.arrayBuffer());
@@ -1724,7 +1724,7 @@ class ValServer {
1724
1724
  });
1725
1725
  }
1726
1726
  }
1727
- async validateThenMaybeCommit(rawBody, commit, cookies) {
1727
+ async validateThenMaybeCommit(rawBody, commit, cookies, requestHeaders) {
1728
1728
  const filterPatchesByModuleIdRes = z.z.object({
1729
1729
  patches: z.z.record(z.z.array(z.z.string())).optional()
1730
1730
  }).safeParse(rawBody);
@@ -1752,7 +1752,7 @@ class ValServer {
1752
1752
  const moduleId = moduleIdStr;
1753
1753
  const serializedModuleContent = await this.applyAllPatchesThenValidate(moduleId, filterPatchesByModuleIdRes.data.patches ||
1754
1754
  // TODO: refine to ModuleId and PatchId when parsing
1755
- patchIdsByModuleId, patchesById, fileUpdates, true, cookies);
1755
+ patchIdsByModuleId, patchesById, fileUpdates, true, cookies, requestHeaders);
1756
1756
  if (serializedModuleContent.errors) {
1757
1757
  validationErrorsByModuleId[moduleId] = serializedModuleContent;
1758
1758
  }
@@ -2970,7 +2970,7 @@ class ProxyValServer extends ValServer {
2970
2970
  }
2971
2971
  });
2972
2972
  }
2973
- async getFiles(filePath, query, cookies) {
2973
+ async getFiles(filePath, query, cookies, reqHeaders) {
2974
2974
  return withAuth(this.options.valSecret, cookies, "getFiles", async data => {
2975
2975
  const url = new URL(`/v1/files/${this.options.remote}${filePath}`, this.options.valContentUrl);
2976
2976
  if (typeof query.sha256 === "string") {
@@ -3002,41 +3002,19 @@ class ProxyValServer extends ValServer {
3002
3002
  };
3003
3003
  }
3004
3004
  } else {
3005
- const fileExists = this.remoteFS.fileExists(path__namespace["default"].join(this.cwd, filePath));
3006
- let buffer;
3007
- if (fileExists) {
3008
- buffer = await this.readStaticBinaryFile(path__namespace["default"].join(this.cwd, filePath));
3009
- }
3010
- if (!buffer) {
3005
+ if (!(reqHeaders.host && reqHeaders["x-forwarded-proto"])) {
3011
3006
  return {
3012
- status: 404,
3007
+ status: 500,
3013
3008
  json: {
3014
- message: "File not found"
3009
+ message: "Missing host or x-forwarded-proto header"
3015
3010
  }
3016
3011
  };
3017
3012
  }
3018
- const mimeType = guessMimeTypeFromPath(filePath) || "application/octet-stream";
3019
- if (query.sha256) {
3020
- const sha256 = getSha256(mimeType, buffer);
3021
- if (sha256 === query.sha256) {
3022
- return {
3023
- status: 200,
3024
- headers: {
3025
- "Content-Type": mimeType,
3026
- "Content-Length": buffer.byteLength.toString(),
3027
- "Cache-Control": "public, max-age=31536000, immutable"
3028
- },
3029
- body: bufferToReadableStream(buffer)
3030
- };
3031
- }
3032
- }
3013
+ const host = `${reqHeaders["x-forwarded-proto"]}://${reqHeaders["host"]}`;
3014
+ const fileUrl = filePath.slice("/public".length);
3033
3015
  return {
3034
- status: 200,
3035
- headers: {
3036
- "Content-Type": mimeType,
3037
- "Content-Length": buffer.byteLength.toString()
3038
- },
3039
- body: bufferToReadableStream(buffer)
3016
+ status: 302,
3017
+ redirectTo: new URL(fileUrl, host).toString()
3040
3018
  };
3041
3019
  }
3042
3020
  });
@@ -3359,8 +3337,10 @@ function createValApiRouter(route, valServerPromise, convert) {
3359
3337
  return async req => {
3360
3338
  var _req$method;
3361
3339
  const valServer = await valServerPromise;
3362
- req.headers.get("content-type");
3363
- req.headers.get("Cookie");
3340
+ const requestHeaders = {
3341
+ host: req.headers.get("host"),
3342
+ "x-forwarded-proto": req.headers.get("x-forwarded-proto")
3343
+ };
3364
3344
  const url = new URL(req.url);
3365
3345
  if (!url.pathname.startsWith(route)) {
3366
3346
  const error = {
@@ -3423,16 +3403,16 @@ function createValApiRouter(route, valServerPromise, convert) {
3423
3403
  }));
3424
3404
  } else if (method === "POST" && path === "/commit") {
3425
3405
  const body = await req.json();
3426
- return convert(await valServer.postCommit(body, getCookies(req, [VAL_SESSION_COOKIE])));
3406
+ return convert(await valServer.postCommit(body, getCookies(req, [VAL_SESSION_COOKIE]), requestHeaders));
3427
3407
  } else if (method === "POST" && path === "/validate") {
3428
3408
  const body = await req.json();
3429
- return convert(await valServer.postValidate(body, getCookies(req, [VAL_SESSION_COOKIE])));
3409
+ return convert(await valServer.postValidate(body, getCookies(req, [VAL_SESSION_COOKIE]), requestHeaders));
3430
3410
  } else if (method === "GET" && path.startsWith(TREE_PATH_PREFIX)) {
3431
3411
  return withTreePath(path, TREE_PATH_PREFIX)(async treePath => convert(await valServer.getTree(treePath, {
3432
3412
  patch: url.searchParams.get("patch") || undefined,
3433
3413
  schema: url.searchParams.get("schema") || undefined,
3434
3414
  source: url.searchParams.get("source") || undefined
3435
- }, getCookies(req, [VAL_SESSION_COOKIE]))));
3415
+ }, getCookies(req, [VAL_SESSION_COOKIE]), requestHeaders)));
3436
3416
  } else if (method === "GET" && path.startsWith(PATCHES_PATH_PREFIX)) {
3437
3417
  return withTreePath(path, PATCHES_PATH_PREFIX)(async () => convert(await valServer.getPatches({
3438
3418
  id: url.searchParams.getAll("id")
@@ -3448,7 +3428,7 @@ function createValApiRouter(route, valServerPromise, convert) {
3448
3428
  const treePath = path.slice(FILES_PATH_PREFIX.length);
3449
3429
  return convert(await valServer.getFiles(treePath, {
3450
3430
  sha256: url.searchParams.get("sha256") || undefined
3451
- }, getCookies(req, [VAL_SESSION_COOKIE])));
3431
+ }, getCookies(req, [VAL_SESSION_COOKIE]), requestHeaders));
3452
3432
  } else {
3453
3433
  return convert({
3454
3434
  status: 404,
@@ -1032,7 +1032,7 @@ export const IS_DEV = false;
1032
1032
  }
1033
1033
  if (modulePath.startsWith("react/jsx-runtime")) {
1034
1034
  return {
1035
- value: "export const jsx = () => { throw Error(`Cannot use 'jsx' in this type of file`) }; export default new Proxy({}, { get() { return () => { throw new Error(`Cannot import 'react' in this file`) } } } ); export const jsxs = () => { throw Error(`Cannot use 'jsxs' in this type of file`) };"
1035
+ value: "export const jsx = () => { throw Error(`Cannot use 'jsx' in this type of file`) }; export const Fragment = () => { throw Error(`Cannot use 'Fragment' in this type of file`) }; export default new Proxy({}, { get() { return () => { throw new Error(`Cannot import 'react' in this file`) } } } ); export const jsxs = () => { throw Error(`Cannot use 'jsxs' in this type of file`) };"
1036
1036
  };
1037
1037
  }
1038
1038
  if (modulePath.startsWith("react")) {
@@ -1419,7 +1419,7 @@ class ValServer {
1419
1419
  }
1420
1420
  async getTree(treePath,
1421
1421
  // TODO: use the params: patch, schema, source now we return everything, every time
1422
- query, cookies) {
1422
+ query, cookies, requestHeaders) {
1423
1423
  const ensureRes = await this.ensureRemoteFSInitialized("getTree", cookies);
1424
1424
  if (fp.result.isErr(ensureRes)) {
1425
1425
  return ensureRes.error;
@@ -1445,7 +1445,7 @@ class ValServer {
1445
1445
  fileUpdates = res.value.fileUpdates;
1446
1446
  }
1447
1447
  const possiblyPatchedContent = await Promise.all(moduleIds.map(async moduleId => {
1448
- return this.applyAllPatchesThenValidate(moduleId, patchIdsByModuleId, patchesById, fileUpdates, applyPatches, cookies);
1448
+ return this.applyAllPatchesThenValidate(moduleId, patchIdsByModuleId, patchesById, fileUpdates, applyPatches, cookies, requestHeaders);
1449
1449
  }));
1450
1450
  const modules = Object.fromEntries(possiblyPatchedContent.map(serializedModuleContent => {
1451
1451
  const module = {
@@ -1464,19 +1464,19 @@ class ValServer {
1464
1464
  json: apiTreeResponse
1465
1465
  };
1466
1466
  }
1467
- async postValidate(rawBody, cookies) {
1467
+ async postValidate(rawBody, cookies, requestHeaders) {
1468
1468
  const ensureRes = await this.ensureRemoteFSInitialized("postValidate", cookies);
1469
1469
  if (fp.result.isErr(ensureRes)) {
1470
1470
  return ensureRes.error;
1471
1471
  }
1472
- return this.validateThenMaybeCommit(rawBody, false, cookies);
1472
+ return this.validateThenMaybeCommit(rawBody, false, cookies, requestHeaders);
1473
1473
  }
1474
- async postCommit(rawBody, cookies) {
1474
+ async postCommit(rawBody, cookies, requestHeaders) {
1475
1475
  const ensureRes = await this.ensureRemoteFSInitialized("postCommit", cookies);
1476
1476
  if (fp.result.isErr(ensureRes)) {
1477
1477
  return ensureRes.error;
1478
1478
  }
1479
- const res = await this.validateThenMaybeCommit(rawBody, true, cookies);
1479
+ const res = await this.validateThenMaybeCommit(rawBody, true, cookies, requestHeaders);
1480
1480
  if (res.status === 200) {
1481
1481
  if (res.json.validationErrors) {
1482
1482
  return {
@@ -1499,7 +1499,7 @@ class ValServer {
1499
1499
 
1500
1500
  /* */
1501
1501
 
1502
- async applyAllPatchesThenValidate(moduleId, patchIdsByModuleId, patchesById, fileUpdates, applyPatches, cookies) {
1502
+ async applyAllPatchesThenValidate(moduleId, patchIdsByModuleId, patchesById, fileUpdates, applyPatches, cookies, requestHeaders) {
1503
1503
  const serializedModuleContent = await this.getModule(moduleId);
1504
1504
  const schema = serializedModuleContent.schema;
1505
1505
  const maybeSource = serializedModuleContent.source;
@@ -1543,7 +1543,7 @@ class ValServer {
1543
1543
  }
1544
1544
  const validationErrors = core.deserializeSchema(schema).validate(moduleId, source);
1545
1545
  if (validationErrors) {
1546
- const revalidated = await this.revalidateImageAndFileValidation(validationErrors, fileUpdates, cookies);
1546
+ const revalidated = await this.revalidateImageAndFileValidation(validationErrors, fileUpdates, cookies, requestHeaders);
1547
1547
  return {
1548
1548
  path: moduleId,
1549
1549
  schema,
@@ -1566,7 +1566,7 @@ class ValServer {
1566
1566
  // The reason is that validate will be called inside QuickJS (in the future, hopefully),
1567
1567
  // which does not have access to the filesystem, at least not at the time of writing this comment.
1568
1568
  // If you are reading this, and we still are not using QuickJS to validate, this assumption might be wrong.
1569
- async revalidateImageAndFileValidation(validationErrors, fileUpdates, cookies) {
1569
+ async revalidateImageAndFileValidation(validationErrors, fileUpdates, cookies, requestHeaders) {
1570
1570
  const revalidatedValidationErrors = {};
1571
1571
  for (const pathStr in validationErrors) {
1572
1572
  const errorSourcePath = pathStr;
@@ -1588,7 +1588,7 @@ class ValServer {
1588
1588
  if (updatedFileMetadata) {
1589
1589
  const fileRes = await this.getFiles(fileRef, {
1590
1590
  sha256: updatedFileMetadata.sha256
1591
- }, cookies);
1591
+ }, cookies, requestHeaders);
1592
1592
  if (fileRes.status === 200 && fileRes.body) {
1593
1593
  const res = new Response(fileRes.body);
1594
1594
  fileBuffer = Buffer.from(await res.arrayBuffer());
@@ -1724,7 +1724,7 @@ class ValServer {
1724
1724
  });
1725
1725
  }
1726
1726
  }
1727
- async validateThenMaybeCommit(rawBody, commit, cookies) {
1727
+ async validateThenMaybeCommit(rawBody, commit, cookies, requestHeaders) {
1728
1728
  const filterPatchesByModuleIdRes = z.z.object({
1729
1729
  patches: z.z.record(z.z.array(z.z.string())).optional()
1730
1730
  }).safeParse(rawBody);
@@ -1752,7 +1752,7 @@ class ValServer {
1752
1752
  const moduleId = moduleIdStr;
1753
1753
  const serializedModuleContent = await this.applyAllPatchesThenValidate(moduleId, filterPatchesByModuleIdRes.data.patches ||
1754
1754
  // TODO: refine to ModuleId and PatchId when parsing
1755
- patchIdsByModuleId, patchesById, fileUpdates, true, cookies);
1755
+ patchIdsByModuleId, patchesById, fileUpdates, true, cookies, requestHeaders);
1756
1756
  if (serializedModuleContent.errors) {
1757
1757
  validationErrorsByModuleId[moduleId] = serializedModuleContent;
1758
1758
  }
@@ -2970,7 +2970,7 @@ class ProxyValServer extends ValServer {
2970
2970
  }
2971
2971
  });
2972
2972
  }
2973
- async getFiles(filePath, query, cookies) {
2973
+ async getFiles(filePath, query, cookies, reqHeaders) {
2974
2974
  return withAuth(this.options.valSecret, cookies, "getFiles", async data => {
2975
2975
  const url = new URL(`/v1/files/${this.options.remote}${filePath}`, this.options.valContentUrl);
2976
2976
  if (typeof query.sha256 === "string") {
@@ -3002,41 +3002,19 @@ class ProxyValServer extends ValServer {
3002
3002
  };
3003
3003
  }
3004
3004
  } else {
3005
- const fileExists = this.remoteFS.fileExists(path__namespace["default"].join(this.cwd, filePath));
3006
- let buffer;
3007
- if (fileExists) {
3008
- buffer = await this.readStaticBinaryFile(path__namespace["default"].join(this.cwd, filePath));
3009
- }
3010
- if (!buffer) {
3005
+ if (!(reqHeaders.host && reqHeaders["x-forwarded-proto"])) {
3011
3006
  return {
3012
- status: 404,
3007
+ status: 500,
3013
3008
  json: {
3014
- message: "File not found"
3009
+ message: "Missing host or x-forwarded-proto header"
3015
3010
  }
3016
3011
  };
3017
3012
  }
3018
- const mimeType = guessMimeTypeFromPath(filePath) || "application/octet-stream";
3019
- if (query.sha256) {
3020
- const sha256 = getSha256(mimeType, buffer);
3021
- if (sha256 === query.sha256) {
3022
- return {
3023
- status: 200,
3024
- headers: {
3025
- "Content-Type": mimeType,
3026
- "Content-Length": buffer.byteLength.toString(),
3027
- "Cache-Control": "public, max-age=31536000, immutable"
3028
- },
3029
- body: bufferToReadableStream(buffer)
3030
- };
3031
- }
3032
- }
3013
+ const host = `${reqHeaders["x-forwarded-proto"]}://${reqHeaders["host"]}`;
3014
+ const fileUrl = filePath.slice("/public".length);
3033
3015
  return {
3034
- status: 200,
3035
- headers: {
3036
- "Content-Type": mimeType,
3037
- "Content-Length": buffer.byteLength.toString()
3038
- },
3039
- body: bufferToReadableStream(buffer)
3016
+ status: 302,
3017
+ redirectTo: new URL(fileUrl, host).toString()
3040
3018
  };
3041
3019
  }
3042
3020
  });
@@ -3359,8 +3337,10 @@ function createValApiRouter(route, valServerPromise, convert) {
3359
3337
  return async req => {
3360
3338
  var _req$method;
3361
3339
  const valServer = await valServerPromise;
3362
- req.headers.get("content-type");
3363
- req.headers.get("Cookie");
3340
+ const requestHeaders = {
3341
+ host: req.headers.get("host"),
3342
+ "x-forwarded-proto": req.headers.get("x-forwarded-proto")
3343
+ };
3364
3344
  const url = new URL(req.url);
3365
3345
  if (!url.pathname.startsWith(route)) {
3366
3346
  const error = {
@@ -3423,16 +3403,16 @@ function createValApiRouter(route, valServerPromise, convert) {
3423
3403
  }));
3424
3404
  } else if (method === "POST" && path === "/commit") {
3425
3405
  const body = await req.json();
3426
- return convert(await valServer.postCommit(body, getCookies(req, [VAL_SESSION_COOKIE])));
3406
+ return convert(await valServer.postCommit(body, getCookies(req, [VAL_SESSION_COOKIE]), requestHeaders));
3427
3407
  } else if (method === "POST" && path === "/validate") {
3428
3408
  const body = await req.json();
3429
- return convert(await valServer.postValidate(body, getCookies(req, [VAL_SESSION_COOKIE])));
3409
+ return convert(await valServer.postValidate(body, getCookies(req, [VAL_SESSION_COOKIE]), requestHeaders));
3430
3410
  } else if (method === "GET" && path.startsWith(TREE_PATH_PREFIX)) {
3431
3411
  return withTreePath(path, TREE_PATH_PREFIX)(async treePath => convert(await valServer.getTree(treePath, {
3432
3412
  patch: url.searchParams.get("patch") || undefined,
3433
3413
  schema: url.searchParams.get("schema") || undefined,
3434
3414
  source: url.searchParams.get("source") || undefined
3435
- }, getCookies(req, [VAL_SESSION_COOKIE]))));
3415
+ }, getCookies(req, [VAL_SESSION_COOKIE]), requestHeaders)));
3436
3416
  } else if (method === "GET" && path.startsWith(PATCHES_PATH_PREFIX)) {
3437
3417
  return withTreePath(path, PATCHES_PATH_PREFIX)(async () => convert(await valServer.getPatches({
3438
3418
  id: url.searchParams.getAll("id")
@@ -3448,7 +3428,7 @@ function createValApiRouter(route, valServerPromise, convert) {
3448
3428
  const treePath = path.slice(FILES_PATH_PREFIX.length);
3449
3429
  return convert(await valServer.getFiles(treePath, {
3450
3430
  sha256: url.searchParams.get("sha256") || undefined
3451
- }, getCookies(req, [VAL_SESSION_COOKIE])));
3431
+ }, getCookies(req, [VAL_SESSION_COOKIE]), requestHeaders));
3452
3432
  } else {
3453
3433
  return convert({
3454
3434
  status: 404,
@@ -1001,7 +1001,7 @@ export const IS_DEV = false;
1001
1001
  }
1002
1002
  if (modulePath.startsWith("react/jsx-runtime")) {
1003
1003
  return {
1004
- value: "export const jsx = () => { throw Error(`Cannot use 'jsx' in this type of file`) }; export default new Proxy({}, { get() { return () => { throw new Error(`Cannot import 'react' in this file`) } } } ); export const jsxs = () => { throw Error(`Cannot use 'jsxs' in this type of file`) };"
1004
+ value: "export const jsx = () => { throw Error(`Cannot use 'jsx' in this type of file`) }; export const Fragment = () => { throw Error(`Cannot use 'Fragment' in this type of file`) }; export default new Proxy({}, { get() { return () => { throw new Error(`Cannot import 'react' in this file`) } } } ); export const jsxs = () => { throw Error(`Cannot use 'jsxs' in this type of file`) };"
1005
1005
  };
1006
1006
  }
1007
1007
  if (modulePath.startsWith("react")) {
@@ -1388,7 +1388,7 @@ class ValServer {
1388
1388
  }
1389
1389
  async getTree(treePath,
1390
1390
  // TODO: use the params: patch, schema, source now we return everything, every time
1391
- query, cookies) {
1391
+ query, cookies, requestHeaders) {
1392
1392
  const ensureRes = await this.ensureRemoteFSInitialized("getTree", cookies);
1393
1393
  if (result.isErr(ensureRes)) {
1394
1394
  return ensureRes.error;
@@ -1414,7 +1414,7 @@ class ValServer {
1414
1414
  fileUpdates = res.value.fileUpdates;
1415
1415
  }
1416
1416
  const possiblyPatchedContent = await Promise.all(moduleIds.map(async moduleId => {
1417
- return this.applyAllPatchesThenValidate(moduleId, patchIdsByModuleId, patchesById, fileUpdates, applyPatches, cookies);
1417
+ return this.applyAllPatchesThenValidate(moduleId, patchIdsByModuleId, patchesById, fileUpdates, applyPatches, cookies, requestHeaders);
1418
1418
  }));
1419
1419
  const modules = Object.fromEntries(possiblyPatchedContent.map(serializedModuleContent => {
1420
1420
  const module = {
@@ -1433,19 +1433,19 @@ class ValServer {
1433
1433
  json: apiTreeResponse
1434
1434
  };
1435
1435
  }
1436
- async postValidate(rawBody, cookies) {
1436
+ async postValidate(rawBody, cookies, requestHeaders) {
1437
1437
  const ensureRes = await this.ensureRemoteFSInitialized("postValidate", cookies);
1438
1438
  if (result.isErr(ensureRes)) {
1439
1439
  return ensureRes.error;
1440
1440
  }
1441
- return this.validateThenMaybeCommit(rawBody, false, cookies);
1441
+ return this.validateThenMaybeCommit(rawBody, false, cookies, requestHeaders);
1442
1442
  }
1443
- async postCommit(rawBody, cookies) {
1443
+ async postCommit(rawBody, cookies, requestHeaders) {
1444
1444
  const ensureRes = await this.ensureRemoteFSInitialized("postCommit", cookies);
1445
1445
  if (result.isErr(ensureRes)) {
1446
1446
  return ensureRes.error;
1447
1447
  }
1448
- const res = await this.validateThenMaybeCommit(rawBody, true, cookies);
1448
+ const res = await this.validateThenMaybeCommit(rawBody, true, cookies, requestHeaders);
1449
1449
  if (res.status === 200) {
1450
1450
  if (res.json.validationErrors) {
1451
1451
  return {
@@ -1468,7 +1468,7 @@ class ValServer {
1468
1468
 
1469
1469
  /* */
1470
1470
 
1471
- async applyAllPatchesThenValidate(moduleId, patchIdsByModuleId, patchesById, fileUpdates, applyPatches, cookies) {
1471
+ async applyAllPatchesThenValidate(moduleId, patchIdsByModuleId, patchesById, fileUpdates, applyPatches, cookies, requestHeaders) {
1472
1472
  const serializedModuleContent = await this.getModule(moduleId);
1473
1473
  const schema = serializedModuleContent.schema;
1474
1474
  const maybeSource = serializedModuleContent.source;
@@ -1512,7 +1512,7 @@ class ValServer {
1512
1512
  }
1513
1513
  const validationErrors = deserializeSchema(schema).validate(moduleId, source);
1514
1514
  if (validationErrors) {
1515
- const revalidated = await this.revalidateImageAndFileValidation(validationErrors, fileUpdates, cookies);
1515
+ const revalidated = await this.revalidateImageAndFileValidation(validationErrors, fileUpdates, cookies, requestHeaders);
1516
1516
  return {
1517
1517
  path: moduleId,
1518
1518
  schema,
@@ -1535,7 +1535,7 @@ class ValServer {
1535
1535
  // The reason is that validate will be called inside QuickJS (in the future, hopefully),
1536
1536
  // which does not have access to the filesystem, at least not at the time of writing this comment.
1537
1537
  // If you are reading this, and we still are not using QuickJS to validate, this assumption might be wrong.
1538
- async revalidateImageAndFileValidation(validationErrors, fileUpdates, cookies) {
1538
+ async revalidateImageAndFileValidation(validationErrors, fileUpdates, cookies, requestHeaders) {
1539
1539
  const revalidatedValidationErrors = {};
1540
1540
  for (const pathStr in validationErrors) {
1541
1541
  const errorSourcePath = pathStr;
@@ -1557,7 +1557,7 @@ class ValServer {
1557
1557
  if (updatedFileMetadata) {
1558
1558
  const fileRes = await this.getFiles(fileRef, {
1559
1559
  sha256: updatedFileMetadata.sha256
1560
- }, cookies);
1560
+ }, cookies, requestHeaders);
1561
1561
  if (fileRes.status === 200 && fileRes.body) {
1562
1562
  const res = new Response(fileRes.body);
1563
1563
  fileBuffer = Buffer.from(await res.arrayBuffer());
@@ -1693,7 +1693,7 @@ class ValServer {
1693
1693
  });
1694
1694
  }
1695
1695
  }
1696
- async validateThenMaybeCommit(rawBody, commit, cookies) {
1696
+ async validateThenMaybeCommit(rawBody, commit, cookies, requestHeaders) {
1697
1697
  const filterPatchesByModuleIdRes = z$1.object({
1698
1698
  patches: z$1.record(z$1.array(z$1.string())).optional()
1699
1699
  }).safeParse(rawBody);
@@ -1721,7 +1721,7 @@ class ValServer {
1721
1721
  const moduleId = moduleIdStr;
1722
1722
  const serializedModuleContent = await this.applyAllPatchesThenValidate(moduleId, filterPatchesByModuleIdRes.data.patches ||
1723
1723
  // TODO: refine to ModuleId and PatchId when parsing
1724
- patchIdsByModuleId, patchesById, fileUpdates, true, cookies);
1724
+ patchIdsByModuleId, patchesById, fileUpdates, true, cookies, requestHeaders);
1725
1725
  if (serializedModuleContent.errors) {
1726
1726
  validationErrorsByModuleId[moduleId] = serializedModuleContent;
1727
1727
  }
@@ -2939,7 +2939,7 @@ class ProxyValServer extends ValServer {
2939
2939
  }
2940
2940
  });
2941
2941
  }
2942
- async getFiles(filePath, query, cookies) {
2942
+ async getFiles(filePath, query, cookies, reqHeaders) {
2943
2943
  return withAuth(this.options.valSecret, cookies, "getFiles", async data => {
2944
2944
  const url = new URL(`/v1/files/${this.options.remote}${filePath}`, this.options.valContentUrl);
2945
2945
  if (typeof query.sha256 === "string") {
@@ -2971,41 +2971,19 @@ class ProxyValServer extends ValServer {
2971
2971
  };
2972
2972
  }
2973
2973
  } else {
2974
- const fileExists = this.remoteFS.fileExists(path__default.join(this.cwd, filePath));
2975
- let buffer;
2976
- if (fileExists) {
2977
- buffer = await this.readStaticBinaryFile(path__default.join(this.cwd, filePath));
2978
- }
2979
- if (!buffer) {
2974
+ if (!(reqHeaders.host && reqHeaders["x-forwarded-proto"])) {
2980
2975
  return {
2981
- status: 404,
2976
+ status: 500,
2982
2977
  json: {
2983
- message: "File not found"
2978
+ message: "Missing host or x-forwarded-proto header"
2984
2979
  }
2985
2980
  };
2986
2981
  }
2987
- const mimeType = guessMimeTypeFromPath(filePath) || "application/octet-stream";
2988
- if (query.sha256) {
2989
- const sha256 = getSha256(mimeType, buffer);
2990
- if (sha256 === query.sha256) {
2991
- return {
2992
- status: 200,
2993
- headers: {
2994
- "Content-Type": mimeType,
2995
- "Content-Length": buffer.byteLength.toString(),
2996
- "Cache-Control": "public, max-age=31536000, immutable"
2997
- },
2998
- body: bufferToReadableStream(buffer)
2999
- };
3000
- }
3001
- }
2982
+ const host = `${reqHeaders["x-forwarded-proto"]}://${reqHeaders["host"]}`;
2983
+ const fileUrl = filePath.slice("/public".length);
3002
2984
  return {
3003
- status: 200,
3004
- headers: {
3005
- "Content-Type": mimeType,
3006
- "Content-Length": buffer.byteLength.toString()
3007
- },
3008
- body: bufferToReadableStream(buffer)
2985
+ status: 302,
2986
+ redirectTo: new URL(fileUrl, host).toString()
3009
2987
  };
3010
2988
  }
3011
2989
  });
@@ -3328,8 +3306,10 @@ function createValApiRouter(route, valServerPromise, convert) {
3328
3306
  return async req => {
3329
3307
  var _req$method;
3330
3308
  const valServer = await valServerPromise;
3331
- req.headers.get("content-type");
3332
- req.headers.get("Cookie");
3309
+ const requestHeaders = {
3310
+ host: req.headers.get("host"),
3311
+ "x-forwarded-proto": req.headers.get("x-forwarded-proto")
3312
+ };
3333
3313
  const url = new URL(req.url);
3334
3314
  if (!url.pathname.startsWith(route)) {
3335
3315
  const error = {
@@ -3392,16 +3372,16 @@ function createValApiRouter(route, valServerPromise, convert) {
3392
3372
  }));
3393
3373
  } else if (method === "POST" && path === "/commit") {
3394
3374
  const body = await req.json();
3395
- return convert(await valServer.postCommit(body, getCookies(req, [VAL_SESSION_COOKIE])));
3375
+ return convert(await valServer.postCommit(body, getCookies(req, [VAL_SESSION_COOKIE]), requestHeaders));
3396
3376
  } else if (method === "POST" && path === "/validate") {
3397
3377
  const body = await req.json();
3398
- return convert(await valServer.postValidate(body, getCookies(req, [VAL_SESSION_COOKIE])));
3378
+ return convert(await valServer.postValidate(body, getCookies(req, [VAL_SESSION_COOKIE]), requestHeaders));
3399
3379
  } else if (method === "GET" && path.startsWith(TREE_PATH_PREFIX)) {
3400
3380
  return withTreePath(path, TREE_PATH_PREFIX)(async treePath => convert(await valServer.getTree(treePath, {
3401
3381
  patch: url.searchParams.get("patch") || undefined,
3402
3382
  schema: url.searchParams.get("schema") || undefined,
3403
3383
  source: url.searchParams.get("source") || undefined
3404
- }, getCookies(req, [VAL_SESSION_COOKIE]))));
3384
+ }, getCookies(req, [VAL_SESSION_COOKIE]), requestHeaders)));
3405
3385
  } else if (method === "GET" && path.startsWith(PATCHES_PATH_PREFIX)) {
3406
3386
  return withTreePath(path, PATCHES_PATH_PREFIX)(async () => convert(await valServer.getPatches({
3407
3387
  id: url.searchParams.getAll("id")
@@ -3417,7 +3397,7 @@ function createValApiRouter(route, valServerPromise, convert) {
3417
3397
  const treePath = path.slice(FILES_PATH_PREFIX.length);
3418
3398
  return convert(await valServer.getFiles(treePath, {
3419
3399
  sha256: url.searchParams.get("sha256") || undefined
3420
- }, getCookies(req, [VAL_SESSION_COOKIE])));
3400
+ }, getCookies(req, [VAL_SESSION_COOKIE]), requestHeaders));
3421
3401
  } else {
3422
3402
  return convert({
3423
3403
  status: 404,
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.16",
15
+ "version": "0.60.17",
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.16",
28
- "@valbuild/shared": "~0.60.16",
29
- "@valbuild/ui": "~0.60.16",
27
+ "@valbuild/core": "~0.60.17",
28
+ "@valbuild/shared": "~0.60.17",
29
+ "@valbuild/ui": "~0.60.17",
30
30
  "express": "^4.18.2",
31
31
  "image-size": "^1.0.2",
32
32
  "minimatch": "^3.0.4",