@axiom-lattice/core 3.1.1 → 3.1.2

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/index.d.mts CHANGED
@@ -6527,6 +6527,8 @@ declare class FilesystemBackend implements BackendProtocol {
6527
6527
  */
6528
6528
  private resolvePath;
6529
6529
  private assertVirtualParentContained;
6530
+ private assertVirtualOpenedFileContained;
6531
+ private readFileBuffer;
6530
6532
  private validateDeleteTarget;
6531
6533
  /**
6532
6534
  * List files and directories in the specified directory (non-recursive).
@@ -6552,6 +6554,8 @@ declare class FilesystemBackend implements BackendProtocol {
6552
6554
  * @returns Raw file content as FileData
6553
6555
  */
6554
6556
  readRaw(filePath: string): Promise<FileData>;
6557
+ /** Read file content as raw bytes without following symbolic links. */
6558
+ readBinary(filePath: string): Promise<Buffer>;
6555
6559
  /**
6556
6560
  * Create a new file with content.
6557
6561
  * Returns WriteResult. External storage sets filesUpdate=null.
package/dist/index.d.ts CHANGED
@@ -6527,6 +6527,8 @@ declare class FilesystemBackend implements BackendProtocol {
6527
6527
  */
6528
6528
  private resolvePath;
6529
6529
  private assertVirtualParentContained;
6530
+ private assertVirtualOpenedFileContained;
6531
+ private readFileBuffer;
6530
6532
  private validateDeleteTarget;
6531
6533
  /**
6532
6534
  * List files and directories in the specified directory (non-recursive).
@@ -6552,6 +6554,8 @@ declare class FilesystemBackend implements BackendProtocol {
6552
6554
  * @returns Raw file content as FileData
6553
6555
  */
6554
6556
  readRaw(filePath: string): Promise<FileData>;
6557
+ /** Read file content as raw bytes without following symbolic links. */
6558
+ readBinary(filePath: string): Promise<Buffer>;
6555
6559
  /**
6556
6560
  * Create a new file with content.
6557
6561
  * Returns WriteResult. External storage sets filesUpdate=null.
package/dist/index.js CHANGED
@@ -18861,6 +18861,51 @@ var FilesystemBackend = class {
18861
18861
  throw new Error(`Path: ${resolvedPath} outside root directory: ${this.cwd}`);
18862
18862
  }
18863
18863
  }
18864
+ async assertVirtualOpenedFileContained(resolvedPath, openedStat) {
18865
+ if (!this.virtualMode) {
18866
+ return;
18867
+ }
18868
+ const [rootPath, realFilePath] = await Promise.all([
18869
+ fs2.realpath(this.cwd),
18870
+ fs2.realpath(resolvedPath)
18871
+ ]);
18872
+ const relative4 = path4.relative(rootPath, realFilePath);
18873
+ if (relative4 === ".." || relative4.startsWith(`..${path4.sep}`) || path4.isAbsolute(relative4)) {
18874
+ throw new Error(`Path: ${resolvedPath} outside root directory: ${this.cwd}`);
18875
+ }
18876
+ const realPathStat = await fs2.stat(realFilePath);
18877
+ if (realPathStat.dev !== openedStat.dev || realPathStat.ino !== openedStat.ino) {
18878
+ throw new Error(`File changed during secure read: ${resolvedPath}`);
18879
+ }
18880
+ }
18881
+ async readFileBuffer(filePath) {
18882
+ const resolvedPath = this.resolvePath(filePath);
18883
+ await this.assertVirtualParentContained(resolvedPath);
18884
+ if (!SUPPORTS_NOFOLLOW) {
18885
+ const initialStat = await fs2.lstat(resolvedPath);
18886
+ if (initialStat.isSymbolicLink()) {
18887
+ throw new Error(`Symlinks are not allowed: ${filePath}`);
18888
+ }
18889
+ }
18890
+ const flags = SUPPORTS_NOFOLLOW ? fsSync.constants.O_RDONLY | fsSync.constants.O_NOFOLLOW : fsSync.constants.O_RDONLY;
18891
+ const fd = await fs2.open(resolvedPath, flags);
18892
+ try {
18893
+ const stat4 = await fd.stat();
18894
+ if (!stat4.isFile()) {
18895
+ throw new Error(`File '${filePath}' not found`);
18896
+ }
18897
+ await this.assertVirtualOpenedFileContained(resolvedPath, stat4);
18898
+ if (!SUPPORTS_NOFOLLOW) {
18899
+ const finalStat = await fs2.lstat(resolvedPath);
18900
+ if (finalStat.isSymbolicLink() || finalStat.dev !== stat4.dev || finalStat.ino !== stat4.ino) {
18901
+ throw new Error(`File changed during secure read: ${resolvedPath}`);
18902
+ }
18903
+ }
18904
+ return { content: await fd.readFile(), stat: stat4 };
18905
+ } finally {
18906
+ await fd.close();
18907
+ }
18908
+ }
18864
18909
  validateDeleteTarget(filePath, stat4) {
18865
18910
  if (stat4.isSymbolicLink()) {
18866
18911
  return `Error: Cannot delete '${filePath}': symlinks are not allowed`;
@@ -18960,32 +19005,8 @@ var FilesystemBackend = class {
18960
19005
  */
18961
19006
  async read(filePath, offset = 0, limit = 2e3) {
18962
19007
  try {
18963
- const resolvedPath = this.resolvePath(filePath);
18964
- let content;
18965
- if (SUPPORTS_NOFOLLOW) {
18966
- const stat4 = await fs2.stat(resolvedPath);
18967
- if (!stat4.isFile()) {
18968
- return `Error: File '${filePath}' not found`;
18969
- }
18970
- const fd = await fs2.open(
18971
- resolvedPath,
18972
- fsSync.constants.O_RDONLY | fsSync.constants.O_NOFOLLOW
18973
- );
18974
- try {
18975
- content = await fd.readFile({ encoding: "utf-8" });
18976
- } finally {
18977
- await fd.close();
18978
- }
18979
- } else {
18980
- const stat4 = await fs2.lstat(resolvedPath);
18981
- if (stat4.isSymbolicLink()) {
18982
- return `Error: Symlinks are not allowed: ${filePath}`;
18983
- }
18984
- if (!stat4.isFile()) {
18985
- return `Error: File '${filePath}' not found`;
18986
- }
18987
- content = await fs2.readFile(resolvedPath, "utf-8");
18988
- }
19008
+ const { content: buffer2 } = await this.readFileBuffer(filePath);
19009
+ const content = buffer2.toString("utf-8");
18989
19010
  const emptyMsg = checkEmptyContent(content);
18990
19011
  if (emptyMsg) {
18991
19012
  return emptyMsg;
@@ -19009,35 +19030,19 @@ var FilesystemBackend = class {
19009
19030
  * @returns Raw file content as FileData
19010
19031
  */
19011
19032
  async readRaw(filePath) {
19012
- const resolvedPath = this.resolvePath(filePath);
19013
- let content;
19014
- let stat4;
19015
- if (SUPPORTS_NOFOLLOW) {
19016
- stat4 = await fs2.stat(resolvedPath);
19017
- if (!stat4.isFile()) throw new Error(`File '${filePath}' not found`);
19018
- const fd = await fs2.open(
19019
- resolvedPath,
19020
- fsSync.constants.O_RDONLY | fsSync.constants.O_NOFOLLOW
19021
- );
19022
- try {
19023
- content = await fd.readFile({ encoding: "utf-8" });
19024
- } finally {
19025
- await fd.close();
19026
- }
19027
- } else {
19028
- stat4 = await fs2.lstat(resolvedPath);
19029
- if (stat4.isSymbolicLink()) {
19030
- throw new Error(`Symlinks are not allowed: ${filePath}`);
19031
- }
19032
- if (!stat4.isFile()) throw new Error(`File '${filePath}' not found`);
19033
- content = await fs2.readFile(resolvedPath, "utf-8");
19034
- }
19033
+ const { content: buffer2, stat: stat4 } = await this.readFileBuffer(filePath);
19034
+ const content = buffer2.toString("utf-8");
19035
19035
  return {
19036
19036
  content: content.split("\n"),
19037
19037
  created_at: stat4.ctime.toISOString(),
19038
19038
  modified_at: stat4.mtime.toISOString()
19039
19039
  };
19040
19040
  }
19041
+ /** Read file content as raw bytes without following symbolic links. */
19042
+ async readBinary(filePath) {
19043
+ const { content } = await this.readFileBuffer(filePath);
19044
+ return content;
19045
+ }
19041
19046
  /**
19042
19047
  * Create a new file with content.
19043
19048
  * Returns WriteResult. External storage sets filesUpdate=null.