@relayfile/sdk 0.10.54 → 0.10.55

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,6 +5,7 @@ import { pathToFileURL } from "node:url";
5
5
  import { RelayFileApiError } from "./errors.js";
6
6
  import { RelayFileClient } from "./client.js";
7
7
  const DEFAULT_POLL_INTERVAL_MS = 1_000;
8
+ const MAX_TREE_PAGES_PER_DIRECTORY = 4_096;
8
9
  export class MountHarnessPermissionError extends Error {
9
10
  code = "permission_denied";
10
11
  path;
@@ -120,7 +121,8 @@ class RelayfileMountHarness {
120
121
  await mkdir(this.localDir, { recursive: true });
121
122
  const desiredFiles = new Map();
122
123
  const desiredDirectories = new Set([""]);
123
- await this.collectRemoteTree(this.config.remotePath, desiredFiles, desiredDirectories);
124
+ const visitedRemoteDirectories = new Set();
125
+ await this.collectRemoteTree(this.config.remotePath, desiredFiles, desiredDirectories, visitedRemoteDirectories);
124
126
  for (const relativeDir of [...desiredDirectories].sort((left, right) => left.localeCompare(right))) {
125
127
  if (relativeDir === "") {
126
128
  continue;
@@ -144,24 +146,47 @@ class RelayfileMountHarness {
144
146
  directories: desiredDirectories.size,
145
147
  });
146
148
  }
147
- async collectRemoteTree(remotePath, desiredFiles, desiredDirectories) {
148
- const tree = await this.client.listTree(this.config.workspaceId, {
149
- path: remotePath,
150
- depth: 1,
151
- });
152
- for (const entry of tree.entries) {
153
- const relativePath = relativeRemotePath(this.config.remotePath, entry.path);
154
- if (relativePath === "") {
155
- continue;
149
+ async collectRemoteTree(remotePath, desiredFiles, desiredDirectories, visitedRemoteDirectories) {
150
+ if (visitedRemoteDirectories.has(remotePath)) {
151
+ return;
152
+ }
153
+ visitedRemoteDirectories.add(remotePath);
154
+ let cursor;
155
+ const seenCursors = new Set();
156
+ let pageCount = 0;
157
+ for (;;) {
158
+ pageCount += 1;
159
+ if (pageCount > MAX_TREE_PAGES_PER_DIRECTORY) {
160
+ throw new Error(`Relayfile tree pagination exceeded ${MAX_TREE_PAGES_PER_DIRECTORY} pages for ${remotePath}.`);
156
161
  }
157
- if (entry.type === "dir") {
158
- desiredDirectories.add(relativePath);
159
- await this.collectRemoteTree(entry.path, desiredFiles, desiredDirectories);
160
- continue;
162
+ const tree = await this.client.listTree(this.config.workspaceId, {
163
+ path: remotePath,
164
+ depth: 1,
165
+ cursor,
166
+ });
167
+ for (const entry of tree.entries) {
168
+ const relativePath = relativeRemotePath(this.config.remotePath, entry.path);
169
+ if (relativePath === "") {
170
+ continue;
171
+ }
172
+ if (entry.type === "dir") {
173
+ desiredDirectories.add(relativePath);
174
+ await this.collectRemoteTree(entry.path, desiredFiles, desiredDirectories, visitedRemoteDirectories);
175
+ continue;
176
+ }
177
+ desiredDirectories.add(path.posix.dirname(relativePath) === "." ? "" : path.posix.dirname(relativePath));
178
+ const file = await this.client.readFile(this.config.workspaceId, entry.path);
179
+ desiredFiles.set(relativePath, decodeContent(file.content, file.encoding));
180
+ }
181
+ const nextCursor = tree.nextCursor?.trim() || undefined;
182
+ if (!nextCursor) {
183
+ return;
184
+ }
185
+ if (seenCursors.has(nextCursor) || nextCursor === cursor) {
186
+ throw new Error(`Relayfile tree cursor repeated for ${remotePath}.`);
161
187
  }
162
- desiredDirectories.add(path.posix.dirname(relativePath) === "." ? "" : path.posix.dirname(relativePath));
163
- const file = await this.client.readFile(this.config.workspaceId, entry.path);
164
- desiredFiles.set(relativePath, decodeContent(file.content, file.encoding));
188
+ seenCursors.add(nextCursor);
189
+ cursor = nextCursor;
165
190
  }
166
191
  }
167
192
  scheduleNextSync() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@relayfile/sdk",
3
- "version": "0.10.54",
3
+ "version": "0.10.55",
4
4
  "description": "TypeScript SDK for relayfile — real-time filesystem for humans and agents",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -59,15 +59,15 @@
59
59
  "prepublishOnly": "npm run build"
60
60
  },
61
61
  "dependencies": {
62
- "@relayfile/core": "0.10.54",
62
+ "@relayfile/core": "0.10.55",
63
63
  "ignore": "^7.0.5",
64
64
  "tar": "^7.5.10"
65
65
  },
66
66
  "optionalDependencies": {
67
- "@relayfile/mount-darwin-arm64": "0.10.54",
68
- "@relayfile/mount-darwin-x64": "0.10.54",
69
- "@relayfile/mount-linux-arm64": "0.10.54",
70
- "@relayfile/mount-linux-x64": "0.10.54"
67
+ "@relayfile/mount-darwin-arm64": "0.10.55",
68
+ "@relayfile/mount-darwin-x64": "0.10.55",
69
+ "@relayfile/mount-linux-arm64": "0.10.55",
70
+ "@relayfile/mount-linux-x64": "0.10.55"
71
71
  },
72
72
  "devDependencies": {
73
73
  "typescript": "^5.7.3",