@valbuild/server 0.106.1 → 0.108.0

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.
@@ -5,4 +5,4 @@ import { ValidationError } from "@valbuild/core";
5
5
  * There is no schema in hand here — a `ValidationError` carries only the value
6
6
  * it flagged — so the shape is all there is to go on.
7
7
  */
8
- export declare function getValidationErrorFileRef(validationError: ValidationError): string | null;
8
+ export declare function getValidationErrorFileRef(validationError: ValidationError): any;
@@ -1,4 +1,4 @@
1
- import { ModuleFilePath, PatchId } from "@valbuild/core";
1
+ import { PatchId } from "@valbuild/core";
2
2
  import { z } from "zod";
3
3
  import type { AuthorId, BaseSha } from "./ValOps.js";
4
4
  import { PatchLogEntry, PatchLogProblem } from "./patchLog.js";
@@ -3648,7 +3648,7 @@ class JsonEntryFilesFingerprint {
3648
3648
  if (cached && cached.moduleMtimeMs === moduleMtimeMs) {
3649
3649
  return cached.entryFilePaths;
3650
3650
  }
3651
- let entryFilePaths = [];
3651
+ let entryFilePaths;
3652
3652
  try {
3653
3653
  const contents = fs__default["default"].readFileSync(absModulePath, "utf-8");
3654
3654
  entryFilePaths = findJsonEntryFilePathsInSource(moduleFilePath, ts__default["default"].createSourceFile(absModulePath, contents, ts__default["default"].ScriptTarget.ES2015));
@@ -3972,14 +3972,14 @@ const FSPatch = z.z.object({
3972
3972
  path: z.z.string().refine(p => p.startsWith("/") && p.includes(".val."), "Path is not valid. Must start with '/' and include '.val.'"),
3973
3973
  patch: internal.Patch,
3974
3974
  patchId: z.z.string(),
3975
- baseSha: z.z.string().refine(p => true),
3976
- authorId: z.z.string().refine(p => true).nullable(),
3975
+ baseSha: z.z.string().refine(_p => true),
3976
+ authorId: z.z.string().refine(_p => true).nullable(),
3977
3977
  createdAt: z.z.string().datetime(),
3978
3978
  coreVersion: z.z.string().nullable(),
3979
3979
  sessionId: z.z.string().nullable()
3980
3980
  });
3981
3981
  const FSPatchBase = z.z.object({
3982
- baseSha: z.z.string().refine(p => true),
3982
+ baseSha: z.z.string().refine(_p => true),
3983
3983
  timestamp: z.z.string().datetime()
3984
3984
  });
3985
3985
 
@@ -4753,7 +4753,6 @@ async function acquirePatchLock(lockFilePath, options) {
4753
4753
  message: `Could not create the directory for ${lockFilePath}: ${err instanceof Error ? err.message : "unknown error"}`
4754
4754
  };
4755
4755
  }
4756
- let lastSeenHolder = null;
4757
4756
  for (;;) {
4758
4757
  const acquiredAt = now();
4759
4758
  const info = {
@@ -4785,7 +4784,7 @@ async function acquirePatchLock(lockFilePath, options) {
4785
4784
  // Released between the failed create and the read. Go straight round again.
4786
4785
  continue;
4787
4786
  }
4788
- lastSeenHolder = parsePatchLockInfo(rawBefore);
4787
+ const lastSeenHolder = parsePatchLockInfo(rawBefore);
4789
4788
  if (isExpired(lastSeenHolder, now())) {
4790
4789
  // Read twice across a poll interval before removing it: an unchanged stale
4791
4790
  // file is one nobody is renewing, and requiring the second read is what
@@ -9782,15 +9781,12 @@ const ValServer = (valModules, options, callbacks) => {
9782
9781
  // 3) the benefit an attacker would get is an image that is not yet published (i.e. most cases: not very interesting)
9783
9782
  // Thus: attack surface + ease of attack + benefit = low probability of attack
9784
9783
  // If we couldn't argue that patch ids are secret enough, then this would be a problem.
9785
- let cacheControl;
9786
9784
  let fileBuffer;
9787
9785
  let mimeType;
9788
9786
  const remote = query.remote === "true";
9789
9787
  if (query.patch_id) {
9790
9788
  fileBuffer = await serverOps.getBase64EncodedBinaryFileFromPatch(filePath, query.patch_id, remote);
9791
9789
  mimeType = core.Internal.filenameToMimeType(filePath);
9792
- // TODO: reenable this:
9793
- // cacheControl = "public, max-age=20000, immutable";
9794
9790
  } else {
9795
9791
  if (serverOps instanceof ValOpsHttp && remote) {
9796
9792
  console.error(`Remote file: ${filePath} requested without patch id. This is most likely a bug in Val.`);
@@ -9803,7 +9799,12 @@ const ValServer = (valModules, options, callbacks) => {
9803
9799
  headers: {
9804
9800
  // TODO: we could use ETag and return 304 instead
9805
9801
  "Content-Type": mimeType || "application/octet-stream",
9806
- "Cache-Control": cacheControl || "public, max-age=0, must-revalidate"
9802
+ // TODO: a file requested with a patch_id is immutable for that
9803
+ // patch, so it could be served "public, max-age=20000, immutable"
9804
+ // instead. There used to be a `cacheControl` variable here for
9805
+ // that, but its only assignment was commented out, so every
9806
+ // response has always taken the revalidate branch.
9807
+ "Cache-Control": "public, max-age=0, must-revalidate"
9807
9808
  },
9808
9809
  body: bufferToReadableStream(fileBuffer)
9809
9810
  };
@@ -10705,9 +10706,7 @@ async function extractImageMetadata(filename, input) {
10705
10706
  mimeType
10706
10707
  };
10707
10708
  }
10708
- async function extractFileMetadata(filename,
10709
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
10710
- _input // TODO: use buffer to determine mimetype
10709
+ async function extractFileMetadata(filename, _input // TODO: use buffer to determine mimetype
10711
10710
  ) {
10712
10711
  let mimeType = core.Internal.filenameToMimeType(filename);
10713
10712
  if (!mimeType) {
@@ -11747,7 +11746,6 @@ async function handleRemoteFileUpload(ctx) {
11747
11746
  // schema above already established that this IS media.
11748
11747
  const actualRemoteFileSource = resolvedRemoteFileAtSourcePath.source;
11749
11748
  const fileSourceMetadata = actualRemoteFileSource && typeof actualRemoteFileSource === "object" && "path" in actualRemoteFileSource ? (() => {
11750
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
11751
11749
  const {
11752
11750
  path: _path,
11753
11751
  ...metadata
@@ -12163,7 +12161,9 @@ async function evalValConfigFile(projectRoot, configFileName) {
12163
12161
  if (isFileNotFound(err)) {
12164
12162
  return null;
12165
12163
  }
12166
- throw Error(`Could not read Val config file at path: '${valConfigPath}': ${err instanceof Error ? err.message : String(err)}`);
12164
+ throw Error(`Could not read Val config file at path: '${valConfigPath}': ${err instanceof Error ? err.message : String(err)}`, {
12165
+ cause: err
12166
+ });
12167
12167
  }
12168
12168
  if (!code.trim()) {
12169
12169
  return null;
@@ -3648,7 +3648,7 @@ class JsonEntryFilesFingerprint {
3648
3648
  if (cached && cached.moduleMtimeMs === moduleMtimeMs) {
3649
3649
  return cached.entryFilePaths;
3650
3650
  }
3651
- let entryFilePaths = [];
3651
+ let entryFilePaths;
3652
3652
  try {
3653
3653
  const contents = fs__default["default"].readFileSync(absModulePath, "utf-8");
3654
3654
  entryFilePaths = findJsonEntryFilePathsInSource(moduleFilePath, ts__default["default"].createSourceFile(absModulePath, contents, ts__default["default"].ScriptTarget.ES2015));
@@ -3972,14 +3972,14 @@ const FSPatch = z.z.object({
3972
3972
  path: z.z.string().refine(p => p.startsWith("/") && p.includes(".val."), "Path is not valid. Must start with '/' and include '.val.'"),
3973
3973
  patch: internal.Patch,
3974
3974
  patchId: z.z.string(),
3975
- baseSha: z.z.string().refine(p => true),
3976
- authorId: z.z.string().refine(p => true).nullable(),
3975
+ baseSha: z.z.string().refine(_p => true),
3976
+ authorId: z.z.string().refine(_p => true).nullable(),
3977
3977
  createdAt: z.z.string().datetime(),
3978
3978
  coreVersion: z.z.string().nullable(),
3979
3979
  sessionId: z.z.string().nullable()
3980
3980
  });
3981
3981
  const FSPatchBase = z.z.object({
3982
- baseSha: z.z.string().refine(p => true),
3982
+ baseSha: z.z.string().refine(_p => true),
3983
3983
  timestamp: z.z.string().datetime()
3984
3984
  });
3985
3985
 
@@ -4753,7 +4753,6 @@ async function acquirePatchLock(lockFilePath, options) {
4753
4753
  message: `Could not create the directory for ${lockFilePath}: ${err instanceof Error ? err.message : "unknown error"}`
4754
4754
  };
4755
4755
  }
4756
- let lastSeenHolder = null;
4757
4756
  for (;;) {
4758
4757
  const acquiredAt = now();
4759
4758
  const info = {
@@ -4785,7 +4784,7 @@ async function acquirePatchLock(lockFilePath, options) {
4785
4784
  // Released between the failed create and the read. Go straight round again.
4786
4785
  continue;
4787
4786
  }
4788
- lastSeenHolder = parsePatchLockInfo(rawBefore);
4787
+ const lastSeenHolder = parsePatchLockInfo(rawBefore);
4789
4788
  if (isExpired(lastSeenHolder, now())) {
4790
4789
  // Read twice across a poll interval before removing it: an unchanged stale
4791
4790
  // file is one nobody is renewing, and requiring the second read is what
@@ -9782,15 +9781,12 @@ const ValServer = (valModules, options, callbacks) => {
9782
9781
  // 3) the benefit an attacker would get is an image that is not yet published (i.e. most cases: not very interesting)
9783
9782
  // Thus: attack surface + ease of attack + benefit = low probability of attack
9784
9783
  // If we couldn't argue that patch ids are secret enough, then this would be a problem.
9785
- let cacheControl;
9786
9784
  let fileBuffer;
9787
9785
  let mimeType;
9788
9786
  const remote = query.remote === "true";
9789
9787
  if (query.patch_id) {
9790
9788
  fileBuffer = await serverOps.getBase64EncodedBinaryFileFromPatch(filePath, query.patch_id, remote);
9791
9789
  mimeType = core.Internal.filenameToMimeType(filePath);
9792
- // TODO: reenable this:
9793
- // cacheControl = "public, max-age=20000, immutable";
9794
9790
  } else {
9795
9791
  if (serverOps instanceof ValOpsHttp && remote) {
9796
9792
  console.error(`Remote file: ${filePath} requested without patch id. This is most likely a bug in Val.`);
@@ -9803,7 +9799,12 @@ const ValServer = (valModules, options, callbacks) => {
9803
9799
  headers: {
9804
9800
  // TODO: we could use ETag and return 304 instead
9805
9801
  "Content-Type": mimeType || "application/octet-stream",
9806
- "Cache-Control": cacheControl || "public, max-age=0, must-revalidate"
9802
+ // TODO: a file requested with a patch_id is immutable for that
9803
+ // patch, so it could be served "public, max-age=20000, immutable"
9804
+ // instead. There used to be a `cacheControl` variable here for
9805
+ // that, but its only assignment was commented out, so every
9806
+ // response has always taken the revalidate branch.
9807
+ "Cache-Control": "public, max-age=0, must-revalidate"
9807
9808
  },
9808
9809
  body: bufferToReadableStream(fileBuffer)
9809
9810
  };
@@ -10705,9 +10706,7 @@ async function extractImageMetadata(filename, input) {
10705
10706
  mimeType
10706
10707
  };
10707
10708
  }
10708
- async function extractFileMetadata(filename,
10709
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
10710
- _input // TODO: use buffer to determine mimetype
10709
+ async function extractFileMetadata(filename, _input // TODO: use buffer to determine mimetype
10711
10710
  ) {
10712
10711
  let mimeType = core.Internal.filenameToMimeType(filename);
10713
10712
  if (!mimeType) {
@@ -11747,7 +11746,6 @@ async function handleRemoteFileUpload(ctx) {
11747
11746
  // schema above already established that this IS media.
11748
11747
  const actualRemoteFileSource = resolvedRemoteFileAtSourcePath.source;
11749
11748
  const fileSourceMetadata = actualRemoteFileSource && typeof actualRemoteFileSource === "object" && "path" in actualRemoteFileSource ? (() => {
11750
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
11751
11749
  const {
11752
11750
  path: _path,
11753
11751
  ...metadata
@@ -12163,7 +12161,9 @@ async function evalValConfigFile(projectRoot, configFileName) {
12163
12161
  if (isFileNotFound(err)) {
12164
12162
  return null;
12165
12163
  }
12166
- throw Error(`Could not read Val config file at path: '${valConfigPath}': ${err instanceof Error ? err.message : String(err)}`);
12164
+ throw Error(`Could not read Val config file at path: '${valConfigPath}': ${err instanceof Error ? err.message : String(err)}`, {
12165
+ cause: err
12166
+ });
12167
12167
  }
12168
12168
  if (!code.trim()) {
12169
12169
  return null;
@@ -3614,7 +3614,7 @@ class JsonEntryFilesFingerprint {
3614
3614
  if (cached && cached.moduleMtimeMs === moduleMtimeMs) {
3615
3615
  return cached.entryFilePaths;
3616
3616
  }
3617
- let entryFilePaths = [];
3617
+ let entryFilePaths;
3618
3618
  try {
3619
3619
  const contents = fs.readFileSync(absModulePath, "utf-8");
3620
3620
  entryFilePaths = findJsonEntryFilePathsInSource(moduleFilePath, ts.createSourceFile(absModulePath, contents, ts.ScriptTarget.ES2015));
@@ -3938,14 +3938,14 @@ const FSPatch = z.object({
3938
3938
  path: z.string().refine(p => p.startsWith("/") && p.includes(".val."), "Path is not valid. Must start with '/' and include '.val.'"),
3939
3939
  patch: Patch,
3940
3940
  patchId: z.string(),
3941
- baseSha: z.string().refine(p => true),
3942
- authorId: z.string().refine(p => true).nullable(),
3941
+ baseSha: z.string().refine(_p => true),
3942
+ authorId: z.string().refine(_p => true).nullable(),
3943
3943
  createdAt: z.string().datetime(),
3944
3944
  coreVersion: z.string().nullable(),
3945
3945
  sessionId: z.string().nullable()
3946
3946
  });
3947
3947
  const FSPatchBase = z.object({
3948
- baseSha: z.string().refine(p => true),
3948
+ baseSha: z.string().refine(_p => true),
3949
3949
  timestamp: z.string().datetime()
3950
3950
  });
3951
3951
 
@@ -4719,7 +4719,6 @@ async function acquirePatchLock(lockFilePath, options) {
4719
4719
  message: `Could not create the directory for ${lockFilePath}: ${err instanceof Error ? err.message : "unknown error"}`
4720
4720
  };
4721
4721
  }
4722
- let lastSeenHolder = null;
4723
4722
  for (;;) {
4724
4723
  const acquiredAt = now();
4725
4724
  const info = {
@@ -4751,7 +4750,7 @@ async function acquirePatchLock(lockFilePath, options) {
4751
4750
  // Released between the failed create and the read. Go straight round again.
4752
4751
  continue;
4753
4752
  }
4754
- lastSeenHolder = parsePatchLockInfo(rawBefore);
4753
+ const lastSeenHolder = parsePatchLockInfo(rawBefore);
4755
4754
  if (isExpired(lastSeenHolder, now())) {
4756
4755
  // Read twice across a poll interval before removing it: an unchanged stale
4757
4756
  // file is one nobody is renewing, and requiring the second read is what
@@ -9748,15 +9747,12 @@ const ValServer = (valModules, options, callbacks) => {
9748
9747
  // 3) the benefit an attacker would get is an image that is not yet published (i.e. most cases: not very interesting)
9749
9748
  // Thus: attack surface + ease of attack + benefit = low probability of attack
9750
9749
  // If we couldn't argue that patch ids are secret enough, then this would be a problem.
9751
- let cacheControl;
9752
9750
  let fileBuffer;
9753
9751
  let mimeType;
9754
9752
  const remote = query.remote === "true";
9755
9753
  if (query.patch_id) {
9756
9754
  fileBuffer = await serverOps.getBase64EncodedBinaryFileFromPatch(filePath, query.patch_id, remote);
9757
9755
  mimeType = Internal.filenameToMimeType(filePath);
9758
- // TODO: reenable this:
9759
- // cacheControl = "public, max-age=20000, immutable";
9760
9756
  } else {
9761
9757
  if (serverOps instanceof ValOpsHttp && remote) {
9762
9758
  console.error(`Remote file: ${filePath} requested without patch id. This is most likely a bug in Val.`);
@@ -9769,7 +9765,12 @@ const ValServer = (valModules, options, callbacks) => {
9769
9765
  headers: {
9770
9766
  // TODO: we could use ETag and return 304 instead
9771
9767
  "Content-Type": mimeType || "application/octet-stream",
9772
- "Cache-Control": cacheControl || "public, max-age=0, must-revalidate"
9768
+ // TODO: a file requested with a patch_id is immutable for that
9769
+ // patch, so it could be served "public, max-age=20000, immutable"
9770
+ // instead. There used to be a `cacheControl` variable here for
9771
+ // that, but its only assignment was commented out, so every
9772
+ // response has always taken the revalidate branch.
9773
+ "Cache-Control": "public, max-age=0, must-revalidate"
9773
9774
  },
9774
9775
  body: bufferToReadableStream(fileBuffer)
9775
9776
  };
@@ -10671,9 +10672,7 @@ async function extractImageMetadata(filename, input) {
10671
10672
  mimeType
10672
10673
  };
10673
10674
  }
10674
- async function extractFileMetadata(filename,
10675
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
10676
- _input // TODO: use buffer to determine mimetype
10675
+ async function extractFileMetadata(filename, _input // TODO: use buffer to determine mimetype
10677
10676
  ) {
10678
10677
  let mimeType = Internal.filenameToMimeType(filename);
10679
10678
  if (!mimeType) {
@@ -11713,7 +11712,6 @@ async function handleRemoteFileUpload(ctx) {
11713
11712
  // schema above already established that this IS media.
11714
11713
  const actualRemoteFileSource = resolvedRemoteFileAtSourcePath.source;
11715
11714
  const fileSourceMetadata = actualRemoteFileSource && typeof actualRemoteFileSource === "object" && "path" in actualRemoteFileSource ? (() => {
11716
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
11717
11715
  const {
11718
11716
  path: _path,
11719
11717
  ...metadata
@@ -12129,7 +12127,9 @@ async function evalValConfigFile(projectRoot, configFileName) {
12129
12127
  if (isFileNotFound(err)) {
12130
12128
  return null;
12131
12129
  }
12132
- throw Error(`Could not read Val config file at path: '${valConfigPath}': ${err instanceof Error ? err.message : String(err)}`);
12130
+ throw Error(`Could not read Val config file at path: '${valConfigPath}': ${err instanceof Error ? err.message : String(err)}`, {
12131
+ cause: err
12132
+ });
12133
12133
  }
12134
12134
  if (!code.trim()) {
12135
12135
  return null;
package/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "./package.json": "./package.json"
17
17
  },
18
18
  "types": "dist/valbuild-server.cjs.d.ts",
19
- "version": "0.106.1",
19
+ "version": "0.108.0",
20
20
  "devDependencies": {
21
21
  "@prettier/sync": "^0.6.1",
22
22
  "@types/jest": "^30.0.0"
@@ -24,17 +24,17 @@
24
24
  "dependencies": {
25
25
  "chokidar": "^5.0.0",
26
26
  "image-size": "^2.0.2",
27
- "minimatch": "^10.2.3",
27
+ "minimatch": "^10.2.6",
28
28
  "sucrase": "^3.35.1",
29
- "typescript": "^5.9.3",
30
- "zod": "^4.3.5",
29
+ "typescript": "^6.0.3",
30
+ "zod": "^4.4.3",
31
31
  "zod-validation-error": "^5.0.0",
32
32
  "@valbuild/core": "0.106.0",
33
- "@valbuild/shared": "0.106.0",
34
- "@valbuild/ui": "0.106.1"
33
+ "@valbuild/shared": "0.108.0",
34
+ "@valbuild/ui": "0.108.0"
35
35
  },
36
36
  "engines": {
37
- "node": ">=18.17.0"
37
+ "node": "^20.19.0 || >=22"
38
38
  },
39
39
  "files": [
40
40
  "dist"