@openclaw/fs-safe 0.8.6 → 0.10.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.
Files changed (246) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/README.md +17 -0
  3. package/dist/advanced.d.ts +1 -0
  4. package/dist/advanced.d.ts.map +1 -1
  5. package/dist/advanced.js +1 -0
  6. package/dist/archive-crc32.d.ts.map +1 -1
  7. package/dist/archive-crc32.js +6 -1
  8. package/dist/archive-deadline.d.ts.map +1 -1
  9. package/dist/archive-deadline.js +3 -4
  10. package/dist/archive-durability.d.ts +24 -0
  11. package/dist/archive-durability.d.ts.map +1 -0
  12. package/dist/archive-durability.js +180 -0
  13. package/dist/archive-gzip-tail.d.ts +2 -0
  14. package/dist/archive-gzip-tail.d.ts.map +1 -1
  15. package/dist/archive-gzip-tail.js +22 -4
  16. package/dist/archive-input.js +4 -4
  17. package/dist/archive-kind.d.ts.map +1 -1
  18. package/dist/archive-kind.js +3 -2
  19. package/dist/archive-merge.d.ts +1 -0
  20. package/dist/archive-merge.d.ts.map +1 -1
  21. package/dist/archive-merge.js +42 -9
  22. package/dist/archive-native.d.ts +1 -0
  23. package/dist/archive-native.d.ts.map +1 -1
  24. package/dist/archive-native.js +4 -2
  25. package/dist/archive-options.d.ts +2 -0
  26. package/dist/archive-options.d.ts.map +1 -1
  27. package/dist/archive-parser.wasm +0 -0
  28. package/dist/archive-read.d.ts.map +1 -1
  29. package/dist/archive-read.js +72 -70
  30. package/dist/archive-staging.d.ts +1 -1
  31. package/dist/archive-staging.d.ts.map +1 -1
  32. package/dist/archive-staging.js +24 -19
  33. package/dist/archive-tar-stream.d.ts +11 -4
  34. package/dist/archive-tar-stream.d.ts.map +1 -1
  35. package/dist/archive-tar-stream.js +20 -8
  36. package/dist/archive-tar-wasm.d.ts.map +1 -1
  37. package/dist/archive-tar-wasm.js +2 -1
  38. package/dist/archive.d.ts.map +1 -1
  39. package/dist/archive.js +9 -4
  40. package/dist/bounded-read.d.ts +7 -0
  41. package/dist/bounded-read.d.ts.map +1 -1
  42. package/dist/bounded-read.js +73 -43
  43. package/dist/clone-metadata.d.ts +19 -0
  44. package/dist/clone-metadata.d.ts.map +1 -0
  45. package/dist/clone-metadata.js +32 -0
  46. package/dist/copy-file-input.d.ts +23 -0
  47. package/dist/copy-file-input.d.ts.map +1 -0
  48. package/dist/copy-file-input.js +91 -0
  49. package/dist/copy-policy.d.ts +3 -0
  50. package/dist/copy-policy.d.ts.map +1 -0
  51. package/dist/copy-policy.js +8 -0
  52. package/dist/copy-publication.d.ts +15 -0
  53. package/dist/copy-publication.d.ts.map +1 -0
  54. package/dist/copy-publication.js +30 -0
  55. package/dist/copy-tree-portable.d.ts +9 -0
  56. package/dist/copy-tree-portable.d.ts.map +1 -0
  57. package/dist/copy-tree-portable.js +191 -0
  58. package/dist/copy.d.ts +16 -0
  59. package/dist/copy.d.ts.map +1 -0
  60. package/dist/copy.js +123 -0
  61. package/dist/directory-mode-node.d.ts.map +1 -1
  62. package/dist/directory-mode-node.js +4 -4
  63. package/dist/durability.d.ts +1 -1
  64. package/dist/durability.d.ts.map +1 -1
  65. package/dist/error-detail.d.ts.map +1 -1
  66. package/dist/error-detail.js +4 -1
  67. package/dist/file-hash.d.ts +6 -2
  68. package/dist/file-hash.d.ts.map +1 -1
  69. package/dist/file-hash.js +49 -12
  70. package/dist/file-store-sync-write.d.ts +1 -0
  71. package/dist/file-store-sync-write.d.ts.map +1 -1
  72. package/dist/file-store-sync-write.js +9 -6
  73. package/dist/file-store.d.ts +4 -0
  74. package/dist/file-store.d.ts.map +1 -1
  75. package/dist/file-store.js +10 -1
  76. package/dist/filename.d.ts.map +1 -1
  77. package/dist/filename.js +2 -12
  78. package/dist/fs.d.ts.map +1 -1
  79. package/dist/fs.js +1 -2
  80. package/dist/guarded-mkdir.d.ts +1 -0
  81. package/dist/guarded-mkdir.d.ts.map +1 -1
  82. package/dist/guarded-mkdir.js +1 -0
  83. package/dist/guarded-mutation.d.ts +2 -0
  84. package/dist/guarded-mutation.d.ts.map +1 -1
  85. package/dist/guarded-mutation.js +9 -5
  86. package/dist/home-dir.d.ts.map +1 -1
  87. package/dist/home-dir.js +9 -7
  88. package/dist/index.d.ts +1 -1
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/install-path.d.ts.map +1 -1
  91. package/dist/install-path.js +9 -13
  92. package/dist/json-document-store.d.ts +3 -0
  93. package/dist/json-document-store.d.ts.map +1 -1
  94. package/dist/json-document-store.js +1 -0
  95. package/dist/json-durable-queue-directory.js +3 -3
  96. package/dist/json-durable-queue-ownership.js +3 -2
  97. package/dist/json-durable-queue.d.ts.map +1 -1
  98. package/dist/json-durable-queue.js +31 -27
  99. package/dist/local-roots.d.ts.map +1 -1
  100. package/dist/local-roots.js +22 -24
  101. package/dist/move-path-cleanup.d.ts.map +1 -1
  102. package/dist/move-path-cleanup.js +4 -3
  103. package/dist/move-path-stage.d.ts +8 -0
  104. package/dist/move-path-stage.d.ts.map +1 -0
  105. package/dist/move-path-stage.js +55 -0
  106. package/dist/move-path.d.ts.map +1 -1
  107. package/dist/move-path.js +55 -47
  108. package/dist/mutation-authority.d.ts +8 -0
  109. package/dist/mutation-authority.d.ts.map +1 -0
  110. package/dist/mutation-authority.js +36 -0
  111. package/dist/native-binding.d.ts +24 -1
  112. package/dist/native-binding.d.ts.map +1 -1
  113. package/dist/native-operations.d.ts +1 -1
  114. package/dist/native-operations.d.ts.map +1 -1
  115. package/dist/native-operations.js +11 -5
  116. package/dist/native-pinned-write-windows.d.ts.map +1 -1
  117. package/dist/native-pinned-write-windows.js +18 -7
  118. package/dist/native-pinned-write.d.ts.map +1 -1
  119. package/dist/native-pinned-write.js +1 -0
  120. package/dist/native-staged-file.d.ts +3 -3
  121. package/dist/native-staged-file.d.ts.map +1 -1
  122. package/dist/native-staged-file.js +35 -8
  123. package/dist/opened-file-failure.d.ts +1 -1
  124. package/dist/opened-file-failure.d.ts.map +1 -1
  125. package/dist/opened-file-failure.js +3 -2
  126. package/dist/path.d.ts.map +1 -1
  127. package/dist/path.js +3 -1
  128. package/dist/permissions-windows.d.ts.map +1 -1
  129. package/dist/permissions-windows.js +38 -48
  130. package/dist/permissions.js +3 -3
  131. package/dist/pinned-operation.js +1 -1
  132. package/dist/pinned-write.d.ts +5 -1
  133. package/dist/pinned-write.d.ts.map +1 -1
  134. package/dist/pinned-write.js +50 -30
  135. package/dist/positional-read.d.ts +9 -0
  136. package/dist/positional-read.d.ts.map +1 -0
  137. package/dist/positional-read.js +36 -0
  138. package/dist/private-temp-workspace.d.ts.map +1 -1
  139. package/dist/private-temp-workspace.js +9 -3
  140. package/dist/publish-copy-stage.d.ts +13 -0
  141. package/dist/publish-copy-stage.d.ts.map +1 -0
  142. package/dist/publish-copy-stage.js +47 -0
  143. package/dist/publish-file.d.ts.map +1 -1
  144. package/dist/publish-file.js +26 -25
  145. package/dist/replace-file-copy-fallback.d.ts.map +1 -1
  146. package/dist/replace-file-copy-fallback.js +30 -17
  147. package/dist/replace-file-copy-source.d.ts.map +1 -1
  148. package/dist/replace-file-copy-source.js +10 -5
  149. package/dist/replace-file-temp-owner.d.ts.map +1 -1
  150. package/dist/replace-file-temp-owner.js +6 -2
  151. package/dist/replace-file.d.ts.map +1 -1
  152. package/dist/replace-file.js +8 -3
  153. package/dist/root-context.d.ts +3 -0
  154. package/dist/root-context.d.ts.map +1 -1
  155. package/dist/root-context.js +51 -26
  156. package/dist/root-directory-list.d.ts +24 -0
  157. package/dist/root-directory-list.d.ts.map +1 -0
  158. package/dist/root-directory-list.js +201 -0
  159. package/dist/root-errors.d.ts +1 -0
  160. package/dist/root-errors.d.ts.map +1 -1
  161. package/dist/root-errors.js +3 -0
  162. package/dist/root-file.d.ts +2 -0
  163. package/dist/root-file.d.ts.map +1 -1
  164. package/dist/root-file.js +12 -4
  165. package/dist/root-impl.d.ts +6 -50
  166. package/dist/root-impl.d.ts.map +1 -1
  167. package/dist/root-impl.js +342 -208
  168. package/dist/root-options.d.ts +66 -0
  169. package/dist/root-options.d.ts.map +1 -0
  170. package/dist/root-options.js +18 -0
  171. package/dist/root-path-existing.d.ts +5 -0
  172. package/dist/root-path-existing.d.ts.map +1 -1
  173. package/dist/root-path-existing.js +56 -1
  174. package/dist/root-path.d.ts +1 -0
  175. package/dist/root-path.d.ts.map +1 -1
  176. package/dist/root-path.js +74 -162
  177. package/dist/root-symlink-policy.d.ts +13 -0
  178. package/dist/root-symlink-policy.d.ts.map +1 -0
  179. package/dist/root-symlink-policy.js +34 -0
  180. package/dist/root-walk.d.ts +5 -4
  181. package/dist/root-walk.d.ts.map +1 -1
  182. package/dist/root-walk.js +99 -50
  183. package/dist/root-write-mode.d.ts.map +1 -1
  184. package/dist/root-write-mode.js +1 -4
  185. package/dist/root.d.ts +3 -1
  186. package/dist/root.d.ts.map +1 -1
  187. package/dist/secret-file.d.ts +1 -0
  188. package/dist/secret-file.d.ts.map +1 -1
  189. package/dist/secret-file.js +1 -0
  190. package/dist/secret-read-async.js +5 -5
  191. package/dist/secure-file.d.ts +1 -1
  192. package/dist/secure-file.d.ts.map +1 -1
  193. package/dist/secure-file.js +23 -13
  194. package/dist/sibling-staged-file.js +7 -7
  195. package/dist/sibling-temp.d.ts.map +1 -1
  196. package/dist/sibling-temp.js +16 -7
  197. package/dist/sidecar-lock-acquire.d.ts +1 -1
  198. package/dist/sidecar-lock-acquire.d.ts.map +1 -1
  199. package/dist/sidecar-lock-acquire.js +6 -4
  200. package/dist/sidecar-lock-policy.d.ts.map +1 -1
  201. package/dist/sidecar-lock-policy.js +5 -3
  202. package/dist/sidecar-lock-reclaim.d.ts.map +1 -1
  203. package/dist/sidecar-lock-reclaim.js +16 -4
  204. package/dist/sidecar-lock.d.ts.map +1 -1
  205. package/dist/sidecar-lock.js +2 -1
  206. package/dist/temp-cleanup.d.ts.map +1 -1
  207. package/dist/temp-cleanup.js +3 -2
  208. package/dist/temp-target.d.ts.map +1 -1
  209. package/dist/temp-target.js +9 -4
  210. package/dist/timing.d.ts +1 -0
  211. package/dist/timing.d.ts.map +1 -1
  212. package/dist/timing.js +25 -6
  213. package/dist/trash.js +2 -2
  214. package/dist/walk.d.ts.map +1 -1
  215. package/dist/walk.js +7 -27
  216. package/dist/windows-owner.d.ts +9 -12
  217. package/dist/windows-owner.d.ts.map +1 -1
  218. package/dist/windows-owner.js +24 -58
  219. package/dist/write-file-handle.d.ts +6 -0
  220. package/dist/write-file-handle.d.ts.map +1 -0
  221. package/dist/write-file-handle.js +25 -0
  222. package/dist/write-open-flags.d.ts.map +1 -1
  223. package/dist/write-open-flags.js +1 -2
  224. package/docs/advanced.md +18 -4
  225. package/docs/archive.md +57 -9
  226. package/docs/atomic.md +7 -0
  227. package/docs/contributing.md +7 -0
  228. package/docs/copy.md +86 -0
  229. package/docs/durability.md +17 -2
  230. package/docs/errors.md +1 -1
  231. package/docs/file-store.md +48 -3
  232. package/docs/json-store.md +10 -0
  233. package/docs/local-roots.md +8 -1
  234. package/docs/native.md +14 -1
  235. package/docs/permissions.md +20 -10
  236. package/docs/positional-read.md +63 -0
  237. package/docs/reading.md +6 -0
  238. package/docs/root.md +168 -6
  239. package/docs/secret-file.md +6 -0
  240. package/docs/security-model.md +14 -0
  241. package/docs/sidecar-lock.md +2 -0
  242. package/docs/timing.md +2 -0
  243. package/docs/types.md +18 -11
  244. package/docs/walk.md +54 -5
  245. package/docs/writing.md +25 -5
  246. package/package.json +16 -11
@@ -106,6 +106,7 @@ async function copyIntoRoot(params) {
106
106
  });
107
107
  await ensureParentInRoot(scopedRoot, relativePath, dirMode);
108
108
  await scopedRoot.copyIn(relativePath, params.sourcePath, {
109
+ durable: params.durable,
109
110
  maxBytes: params.maxBytes,
110
111
  mkdir: false,
111
112
  mode: params.mode ?? 0o600,
@@ -117,6 +118,7 @@ export function fileStore(options) {
117
118
  const privateMode = options.private ?? false;
118
119
  const dirMode = options.dirMode ?? 0o700;
119
120
  const mode = options.mode ?? 0o600;
121
+ const durable = options.durable ?? true;
120
122
  const maxBytes = normalizeMaxBytes(options.maxBytes);
121
123
  async function openRoot() {
122
124
  return await root(rootDir, { hardlinks: "reject", maxBytes });
@@ -132,6 +134,7 @@ export function fileStore(options) {
132
134
  rootDir,
133
135
  filePath: destination,
134
136
  content,
137
+ durable: writeOptions?.durable ?? durable,
135
138
  dirMode: writeOptions?.dirMode ?? dirMode,
136
139
  mode: writeOptions?.mode ?? mode,
137
140
  });
@@ -147,6 +150,7 @@ export function fileStore(options) {
147
150
  await scopedRoot.write(safeRelativePath, content, {
148
151
  mkdir: false,
149
152
  mode: writeOptions?.mode ?? mode,
153
+ durable: writeOptions?.durable ?? durable,
150
154
  });
151
155
  return destination;
152
156
  }
@@ -173,6 +177,7 @@ export function fileStore(options) {
173
177
  rootDir,
174
178
  filePath: destination,
175
179
  content: Buffer.concat(chunks),
180
+ durable: writeOptions?.durable ?? durable,
176
181
  dirMode: writeOptions?.dirMode ?? dirMode,
177
182
  mode: writeOptions?.mode ?? mode,
178
183
  });
@@ -188,6 +193,7 @@ export function fileStore(options) {
188
193
  rootDir,
189
194
  relativePath: safeRelativePath,
190
195
  sourcePath: staged.path,
196
+ durable: writeOptions?.durable ?? durable,
191
197
  maxBytes: limit,
192
198
  mode: writeOptions?.mode ?? mode,
193
199
  tempPrefix: writeOptions?.tempPrefix,
@@ -212,6 +218,7 @@ export function fileStore(options) {
212
218
  rootDir,
213
219
  relativePath,
214
220
  sourcePath,
221
+ durable: writeOptions?.durable ?? durable,
215
222
  dirMode: writeOptions?.dirMode ?? dirMode,
216
223
  maxBytes: configuredLimit,
217
224
  mode: writeOptions?.mode ?? mode,
@@ -283,7 +290,7 @@ export function fileStore(options) {
283
290
  readRequired: async () => await (await openRoot()).readJson(assertRelativePath(relativePath)),
284
291
  write: async (value, options) => {
285
292
  const json = stringifyJsonDocument(value, null, 2);
286
- await write(relativePath, options?.trailingNewline === false ? json : `${json}\n`);
293
+ await write(relativePath, options?.trailingNewline === false ? json : `${json}\n`, { durable: options?.durable });
287
294
  },
288
295
  }, jsonOptions);
289
296
  },
@@ -297,6 +304,7 @@ export function fileStoreSync(options) {
297
304
  const privateMode = options.private ?? false;
298
305
  const dirMode = options.dirMode ?? 0o700;
299
306
  const mode = options.mode ?? 0o600;
307
+ const durable = options.durable ?? true;
300
308
  const maxBytes = normalizeMaxBytes(options.maxBytes);
301
309
  function write(relativePath, data, writeOptions) {
302
310
  const destination = resolveStorePath(rootDir, relativePath);
@@ -308,6 +316,7 @@ export function fileStoreSync(options) {
308
316
  filePath: destination,
309
317
  content,
310
318
  privateMode,
319
+ durable: writeOptions?.durable ?? durable,
311
320
  dirMode: writeOptions?.dirMode ?? dirMode,
312
321
  mode: writeOptions?.mode ?? mode,
313
322
  });
@@ -1 +1 @@
1
- {"version":3,"file":"filename.d.ts","sourceRoot":"","sources":["../src/filename.ts"],"names":[],"mappings":"AAqCA,yFAAyF;AACzF,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,MAAM,CA8BT;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAgCxF"}
1
+ {"version":3,"file":"filename.d.ts","sourceRoot":"","sources":["../src/filename.ts"],"names":[],"mappings":"AAqCA,yFAAyF;AACzF,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,MAAM,CA8BT;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAoBxF"}
package/dist/filename.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import path from "node:path";
2
2
  import { WINDOWS_RESERVED_DEVICE_NAMES } from "./device-path.js";
3
- const WINDOWS_INVALID_FILE_NAME_CHARACTERS = new Set('<>:"/\\|?*');
3
+ const INVALID_FILE_NAME_CHARACTERS = /[\u0000-\u001f\u007f-\u009f<>:"/\\|?*]/g;
4
4
  function trimWindowsIgnoredSuffix(value) {
5
5
  let end = value.length;
6
6
  while (end > 0) {
@@ -65,17 +65,7 @@ export function sanitizeUntrustedFileName(fileName, fallbackName) {
65
65
  }
66
66
  let base = path.posix.basename(trimmed);
67
67
  base = path.win32.basename(base);
68
- let cleaned = "";
69
- for (let i = 0; i < base.length; i++) {
70
- const code = base.charCodeAt(i);
71
- if (code < 0x20 ||
72
- (code >= 0x7f && code <= 0x9f) ||
73
- WINDOWS_INVALID_FILE_NAME_CHARACTERS.has(base[i])) {
74
- continue;
75
- }
76
- cleaned += base[i];
77
- }
78
- base = cleaned.trim();
68
+ base = base.replace(INVALID_FILE_NAME_CHARACTERS, "").trim();
79
69
  if (!base || base === "." || base === "..") {
80
70
  return fallbackName;
81
71
  }
package/dist/fs.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAOxD"}
1
+ {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAOxD"}
package/dist/fs.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import fs from "node:fs";
2
- import fsp from "node:fs/promises";
3
2
  /**
4
3
  * Returns true when `fs.stat()` can stat the path.
5
4
  *
@@ -8,7 +7,7 @@ import fsp from "node:fs/promises";
8
7
  */
9
8
  export async function pathExists(filePath) {
10
9
  try {
11
- await fsp.stat(filePath);
10
+ fs.statSync(filePath);
12
11
  return true;
13
12
  }
14
13
  catch {
@@ -8,6 +8,7 @@ export declare function mkdirPathComponentsWithGuards(params: {
8
8
  rootReal: string;
9
9
  targetPath: string;
10
10
  beforeComponent?: (componentPath: string) => Promise<void> | void;
11
+ assertBeforeMutation?: () => void;
11
12
  mode?: number;
12
13
  rejectSymlinks?: boolean;
13
14
  }): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"guarded-mkdir.d.ts","sourceRoot":"","sources":["../src/guarded-mkdir.ts"],"names":[],"mappings":"AA0BA;;;;;GAKG;AACH,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,OAAO,CAAC,MAAM,CAAC,CAuDlB"}
1
+ {"version":3,"file":"guarded-mkdir.d.ts","sourceRoot":"","sources":["../src/guarded-mkdir.ts"],"names":[],"mappings":"AA0BA;;;;;GAKG;AACH,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAClE,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,OAAO,CAAC,MAAM,CAAC,CAwDlB"}
@@ -42,6 +42,7 @@ export async function mkdirPathComponentsWithGuards(params) {
42
42
  const parentGuard = await createAsyncDirectoryGuard(current);
43
43
  await assertAsyncDirectoryGuard(parentGuard);
44
44
  await params.beforeComponent?.(next);
45
+ params.assertBeforeMutation?.();
45
46
  try {
46
47
  await fs.mkdir(next, { mode: params.mode });
47
48
  }
@@ -24,12 +24,14 @@ export declare function guardedRenameSync(params: {
24
24
  }): void;
25
25
  export declare function guardedRm(params: {
26
26
  target: string;
27
+ assertBeforeMutation?: () => void;
27
28
  recursive?: boolean;
28
29
  force?: boolean;
29
30
  verifyAfter?: boolean;
30
31
  }): Promise<void>;
31
32
  export declare function guardedRmSync(params: {
32
33
  target: string;
34
+ assertBeforeMutation?: () => void;
33
35
  recursive?: boolean;
34
36
  force?: boolean;
35
37
  verifyAfter?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"guarded-mutation.d.ts","sourceRoot":"","sources":["../src/guarded-mutation.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAGnD,OAAO,EAOL,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AAE9B,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,MAAM,EAAE,SAAS,sBAAsB,EAAE,EACzC,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACxB,OAAO,GAAE;IACP,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACrE,GACL,OAAO,CAAC,CAAC,CAAC,CAyBZ;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,MAAM,EAAE,MAAM,CAAC,EACf,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GACtC,CAAC,CAWH;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE;IAC1C,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,CAAC;IACzE,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhB;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,IAAI,CAUP;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAYhB;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,IAAI,CAWP"}
1
+ {"version":3,"file":"guarded-mutation.d.ts","sourceRoot":"","sources":["../src/guarded-mutation.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAGnD,OAAO,EAOL,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AAE9B,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,MAAM,EAAE,SAAS,sBAAsB,EAAE,EACzC,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACxB,OAAO,GAAE;IACP,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACrE,GACL,OAAO,CAAC,CAAC,CAAC,CAyBZ;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,MAAM,EAAE,MAAM,CAAC,EACf,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GACtC,CAAC,CAWH;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE;IAC1C,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,CAAC;IACzE,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhB;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,IAAI,CAUP;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAahB;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,IAAI,CAaP"}
@@ -49,7 +49,7 @@ export async function guardedRename(params) {
49
49
  : await createAsyncDirectoryGuard(path.dirname(params.to));
50
50
  await withAsyncDirectoryGuards([sourceGuard, targetGuard], async () => {
51
51
  if (params.onSourceInspected) {
52
- params.onSourceInspected(await fs.lstat(params.from, { bigint: true }));
52
+ params.onSourceInspected(fsSync.lstatSync(params.from, { bigint: true }));
53
53
  }
54
54
  // Authority must survive all awaited guards; do not yield before rename dispatch.
55
55
  params.assertBeforeRename?.();
@@ -67,6 +67,7 @@ export function guardedRenameSync(params) {
67
67
  export async function guardedRm(params) {
68
68
  const guard = await createAsyncDirectoryGuard(path.dirname(params.target));
69
69
  await withAsyncDirectoryGuards([guard], async () => {
70
+ params.assertBeforeMutation?.();
70
71
  await fs.rm(params.target, {
71
72
  ...(params.recursive !== undefined ? { recursive: params.recursive } : {}),
72
73
  ...(params.force !== undefined ? { force: params.force } : {}),
@@ -75,8 +76,11 @@ export async function guardedRm(params) {
75
76
  }
76
77
  export function guardedRmSync(params) {
77
78
  const guard = createSyncDirectoryGuard(path.dirname(params.target));
78
- withSyncDirectoryGuards([guard], () => fsSync.rmSync(params.target, {
79
- ...(params.recursive !== undefined ? { recursive: params.recursive } : {}),
80
- ...(params.force !== undefined ? { force: params.force } : {}),
81
- }), { verifyAfter: params.verifyAfter });
79
+ withSyncDirectoryGuards([guard], () => {
80
+ params.assertBeforeMutation?.();
81
+ fsSync.rmSync(params.target, {
82
+ ...(params.recursive !== undefined ? { recursive: params.recursive } : {}),
83
+ ...(params.force !== undefined ? { force: params.force } : {}),
84
+ });
85
+ }, { verifyAfter: params.verifyAfter });
82
86
  }
@@ -1 +1 @@
1
- {"version":3,"file":"home-dir.d.ts","sourceRoot":"","sources":["../src/home-dir.ts"],"names":[],"mappings":"AAeA,wBAAgB,uBAAuB,CACrC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,GAAE,MAAM,MAAmB,GACjC,MAAM,GAAG,SAAS,CAGpB;AAyCD,wBAAgB,sBAAsB,CACpC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,GAAE,MAAM,MAAmB,GACjC,MAAM,CAER;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IACL,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;CACxB,GACA,MAAM,CAYR;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IACL,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;CACxB,GACA,MAAM,CAcR"}
1
+ {"version":3,"file":"home-dir.d.ts","sourceRoot":"","sources":["../src/home-dir.ts"],"names":[],"mappings":"AAoBA,wBAAgB,uBAAuB,CACrC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,GAAE,MAAM,MAAmB,GACjC,MAAM,GAAG,SAAS,CAGpB;AAwCD,wBAAgB,sBAAsB,CACpC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,GAAE,MAAM,MAAmB,GACjC,MAAM,CAER;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IACL,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;CACxB,GACA,MAAM,CAYR;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IACL,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;CACxB,GACA,MAAM,CAaR"}
package/dist/home-dir.js CHANGED
@@ -1,6 +1,10 @@
1
1
  import os from "node:os";
2
2
  import path from "node:path";
3
3
  import { normalizeOptionalString } from "./string-coerce.js";
4
+ function hasHomePrefix(input) {
5
+ return input === "~" || input.startsWith("~/") ||
6
+ (path.sep === "\\" && input.startsWith("~\\"));
7
+ }
4
8
  function normalize(value) {
5
9
  const trimmed = normalizeOptionalString(value);
6
10
  if (!trimmed) {
@@ -20,8 +24,7 @@ function resolveRawHomeDir(env, homedir) {
20
24
  if (!explicitHome) {
21
25
  return resolveRawOsHomeDir(env, homedir);
22
26
  }
23
- const segments = path.normalize(explicitHome).split(path.sep);
24
- if (segments[0] !== "~") {
27
+ if (!hasHomePrefix(explicitHome)) {
25
28
  return explicitHome;
26
29
  }
27
30
  // OPENCLAW_HOME starts with "~"; expand against the os home dir. Fall
@@ -56,8 +59,7 @@ export function resolveRequiredHomeDir(env = process.env, homedir = os.homedir)
56
59
  return resolveEffectiveHomeDir(env, homedir) ?? path.resolve(process.cwd());
57
60
  }
58
61
  export function expandHomePrefix(input, opts) {
59
- const segments = path.normalize(input).split(path.sep);
60
- if (segments[0] !== "~") {
62
+ if (!hasHomePrefix(input)) {
61
63
  return input;
62
64
  }
63
65
  const home = normalize(opts?.home) ??
@@ -65,14 +67,14 @@ export function expandHomePrefix(input, opts) {
65
67
  if (!home) {
66
68
  return input;
67
69
  }
68
- return path.join(home, ...segments.slice(1));
70
+ // Expand before normalizing so a following .. traverses the actual home.
71
+ return path.join(home, input.slice(2));
69
72
  }
70
73
  export function resolveHomeRelativePath(input, opts) {
71
74
  if (!input) {
72
75
  return input;
73
76
  }
74
- const segments = path.normalize(input).split(path.sep);
75
- if (segments[0] !== "~") {
77
+ if (!hasHomePrefix(input)) {
76
78
  return path.resolve(input);
77
79
  }
78
80
  const expanded = expandHomePrefix(input, {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { FsSafeError, categorizeFsSafeError, type FsSafeErrorCategory, type FsSafeErrorCode, type FsSafeErrorDetails, } from "./errors.js";
2
- export { DEFAULT_ROOT_MAX_BYTES, root, type DenyMutationPolicy, type HardlinkPolicy, type RenameIdentityPolicy, type OpenResult, type ReadResult, type Root, type RootAppendOptions, type RootCopyOptions, type RootCreateJsonOptions, type RootCreateOptions, type RootDefaults, type RootMkdirOptions, type RootMoveOptions, type RootOpenOptions, type RootOpenWritableOptions, type RootOptions, type RootReadOptions, type RootRemoveOptions, type RootWriteJsonOptions, type RootWriteOptions, type RootWalkDataEntry, type RootWalkDataEntryKind, type RootWalkDirectoryErrorBehavior, type RootWalkEntry, type RootWalkEntryFilter, type RootWalkEntryFilterResult, type RootWalkEntryKind, type RootWalkLimitBehavior, type RootWalkOptions, type RootWalkSymlinkPolicy, type SymlinkPolicy, type WritableOpenMode, type WritableOpenResult, } from "./root.js";
2
+ export { DEFAULT_ROOT_MAX_BYTES, root, type DenyMutationPolicy, type HardlinkPolicy, type RenameIdentityPolicy, type OpenResult, type ReadResult, type Root, type RootAppendOptions, type RootCopyOptions, type RootCopySource, type RootCopyPublicationReceipt, type CopyCloneMode, type RootCreateJsonOptions, type RootCreateOptions, type RootDefaults, type RootMkdirOptions, type RootMoveOptions, type RootOpenOptions, type RootOpenWritableOptions, type RootOptions, type RootReadOptions, type RootRemoveOptions, type RootWriteJsonOptions, type RootWriteOptions, type RootWalkDataEntry, type RootWalkDataEntryKind, type RootWalkDirectoryErrorBehavior, type RootWalkEntry, type RootWalkEntryFilter, type RootWalkEntryFilterResult, type RootWalkEntryKind, type RootWalkLimitBehavior, type RootWalkOptions, type RootWalkSymlinkPolicy, type SymlinkPolicy, type MutationSymlinkPolicy, type WritableOpenMode, type WritableOpenResult, } from "./root.js";
3
3
  export type { ContainmentGuarantee } from "./containment.js";
4
4
  export { configureFsSafePython, configureFsSafeNative, getFsSafeNativeConfig, type FsSafePythonConfig, type FsSafeNativeConfig, type FsSafeNativeMode, } from "./native-config.js";
5
5
  export { writeExternalFileWithinRoot, type ExternalFileWriteOptions, type ExternalFileWriteResult, } from "./output.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,sBAAsB,EACtB,IAAI,EACJ,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,IAAI,EACT,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,8BAA8B,EACnC,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,GACxB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,2BAA2B,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,GAC7B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,sBAAsB,EACtB,IAAI,EACJ,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,IAAI,EACT,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,0BAA0B,EAC/B,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,8BAA8B,EACnC,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,GACxB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,2BAA2B,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,GAC7B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"install-path.d.ts","sourceRoot":"","sources":["../src/install-path.ts"],"names":[],"mappings":"AAKA,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMjD;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAsB3D;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;CACtC,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAe5D;AAED,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkDhB"}
1
+ {"version":3,"file":"install-path.d.ts","sourceRoot":"","sources":["../src/install-path.ts"],"names":[],"mappings":"AAKA,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMjD;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAiB3D;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;CACtC,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAe5D;AAED,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkDhB"}
@@ -1,5 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
- import fs from "node:fs/promises";
2
+ import fsSync from "node:fs";
3
3
  import path from "node:path";
4
4
  import { isPathInside } from "./path.js";
5
5
  export function safeDirName(input) {
@@ -19,12 +19,8 @@ export function safePathSegmentHashed(input) {
19
19
  .replaceAll(/-+$/g, "");
20
20
  const normalized = base.length > 0 ? base : "skill";
21
21
  const safe = normalized === "." || normalized === ".." ? "skill" : normalized;
22
- const hash = createHash("sha256").update(trimmed).digest("hex").slice(0, 10);
23
- if (safe !== trimmed) {
24
- const prefix = safe.length > 50 ? safe.slice(0, 50) : safe;
25
- return `${prefix}-${hash}`;
26
- }
27
- if (safe.length > 60) {
22
+ if (safe !== trimmed || safe.length > 60) {
23
+ const hash = createHash("sha256").update(trimmed).digest("hex").slice(0, 10);
28
24
  return `${safe.slice(0, 50)}-${hash}`;
29
25
  }
30
26
  return safe;
@@ -49,9 +45,9 @@ export async function assertCanonicalPathWithinBase(params) {
49
45
  if (!isPathInside(baseDir, candidatePath)) {
50
46
  throw new Error(`Invalid path: must stay within ${params.boundaryLabel}`);
51
47
  }
52
- const baseLstat = await fs.lstat(baseDir);
48
+ const baseLstat = fsSync.lstatSync(baseDir);
53
49
  if (baseLstat.isSymbolicLink()) {
54
- const baseStat = await fs.stat(baseDir);
50
+ const baseStat = fsSync.statSync(baseDir);
55
51
  if (!baseStat.isDirectory()) {
56
52
  throw new Error(`Invalid ${params.boundaryLabel}: base directory must resolve to a directory`);
57
53
  }
@@ -59,15 +55,15 @@ export async function assertCanonicalPathWithinBase(params) {
59
55
  else if (!baseLstat.isDirectory()) {
60
56
  throw new Error(`Invalid ${params.boundaryLabel}: base directory must be a directory`);
61
57
  }
62
- const baseRealPath = await fs.realpath(baseDir);
58
+ const baseRealPath = fsSync.realpathSync.native(baseDir);
63
59
  const validateDirectory = async (dirPath) => {
64
60
  const resolvedDirPath = path.resolve(dirPath);
65
- const dirLstat = await fs.lstat(dirPath);
61
+ const dirLstat = fsSync.lstatSync(dirPath);
66
62
  if (dirLstat.isSymbolicLink()) {
67
63
  if (resolvedDirPath !== baseDir) {
68
64
  throw new Error(`Invalid path: must stay within ${params.boundaryLabel}`);
69
65
  }
70
- const dirStat = await fs.stat(dirPath);
66
+ const dirStat = fsSync.statSync(dirPath);
71
67
  if (!dirStat.isDirectory()) {
72
68
  throw new Error(`Invalid path: must stay within ${params.boundaryLabel}`);
73
69
  }
@@ -75,7 +71,7 @@ export async function assertCanonicalPathWithinBase(params) {
75
71
  else if (!dirLstat.isDirectory()) {
76
72
  throw new Error(`Invalid path: must stay within ${params.boundaryLabel}`);
77
73
  }
78
- const dirRealPath = await fs.realpath(dirPath);
74
+ const dirRealPath = fsSync.realpathSync.native(dirPath);
79
75
  if (!isPathInside(baseRealPath, dirRealPath)) {
80
76
  throw new Error(`Invalid path: must stay within ${params.boundaryLabel}`);
81
77
  }
@@ -9,6 +9,8 @@ export type JsonStoreLockOptions = {
9
9
  managerKey?: string;
10
10
  };
11
11
  export type JsonFileStoreOptions = {
12
+ /** Overrides the parent store's durability for every JSON mutation. */
13
+ durable?: boolean;
12
14
  trailingNewline?: boolean;
13
15
  lock?: boolean | JsonStoreLockOptions;
14
16
  };
@@ -29,6 +31,7 @@ export type JsonStoreAdapter<T> = {
29
31
  readRequired(): Promise<T>;
30
32
  write(value: T, options?: {
31
33
  trailingNewline?: boolean;
34
+ durable?: boolean;
32
35
  }): Promise<void>;
33
36
  };
34
37
  export declare function createJsonStore<T>(adapter: JsonStoreAdapter<T>, options?: JsonFileStoreOptions): JsonStore<T>;
@@ -1 +1 @@
1
- {"version":3,"file":"json-document-store.d.ts","sourceRoot":"","sources":["../src/json-document-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE3D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AASlE,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,aAAa,CAAC,EAAE,wBAAwB,CAAC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,IAAI,CAAC,EAAE,OAAO,GAAG,oBAAoB,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,IAAI,IAAI,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAC/B,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAChC,YAAY,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3B,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,SAAS,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACpE,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACxE,CAAC;AAEF,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,YAAY,IAAI,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACvC,YAAY,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3B,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzE,CAAC;AA2BF,wBAAgB,eAAe,CAAC,CAAC,EAC/B,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC5B,OAAO,GAAE,oBAAyB,GACjC,SAAS,CAAC,CAAC,CAAC,CAmFd"}
1
+ {"version":3,"file":"json-document-store.d.ts","sourceRoot":"","sources":["../src/json-document-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE3D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AASlE,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,aAAa,CAAC,EAAE,wBAAwB,CAAC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,uEAAuE;IACvE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,IAAI,CAAC,EAAE,OAAO,GAAG,oBAAoB,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,IAAI,IAAI,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAC/B,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAChC,YAAY,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3B,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,SAAS,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACpE,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACxE,CAAC;AAEF,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,YAAY,IAAI,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACvC,YAAY,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3B,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5F,CAAC;AA2BF,wBAAgB,eAAe,CAAC,CAAC,EAC/B,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC5B,OAAO,GAAE,oBAAyB,GACjC,SAAS,CAAC,CAAC,CAAC,CAoFd"}
@@ -38,6 +38,7 @@ export function createJsonStore(adapter, options = {}) {
38
38
  async function write(value) {
39
39
  await adapter.write(value, {
40
40
  trailingNewline: options.trailingNewline ?? true,
41
+ durable: options.durable,
41
42
  });
42
43
  }
43
44
  async function withSerializedMutation(run) {
@@ -1,10 +1,10 @@
1
- import fs from "node:fs/promises";
1
+ import fsSync from "node:fs";
2
2
  import path from "node:path";
3
3
  import { syncDirectory } from "./directory-durability.js";
4
4
  import { isPathRelativeEscape } from "./path.js";
5
5
  export async function syncQueueDirectoryCreation(dir, validationBase) {
6
- const baseReal = await fs.realpath(validationBase);
7
- const targetReal = await fs.realpath(dir);
6
+ const baseReal = fsSync.realpathSync.native(validationBase);
7
+ const targetReal = fsSync.realpathSync.native(dir);
8
8
  const relative = path.relative(baseReal, targetReal);
9
9
  if (isPathRelativeEscape(relative)) {
10
10
  throw new Error(`durable queue directory escapes validation base: ${dir}`);
@@ -1,5 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { withSidecarLock } from "./sidecar-lock.js";
3
+ import fsSync, {} from "node:fs";
3
4
  import fs from "node:fs/promises";
4
5
  import path from "node:path";
5
6
  import { syncDirectory } from "./directory-durability.js";
@@ -163,7 +164,7 @@ export function getErrorCode(error) {
163
164
  }
164
165
  async function lstatOrNull(filePath) {
165
166
  try {
166
- return await fs.lstat(filePath, { bigint: true });
167
+ return fsSync.lstatSync(filePath, { bigint: true });
167
168
  }
168
169
  catch (error) {
169
170
  if (getErrorCode(error) === "ENOENT")
@@ -205,7 +206,7 @@ async function ensureRetirementRoot(jsonPath) {
205
206
  if (getErrorCode(error) !== "EEXIST")
206
207
  throw error;
207
208
  });
208
- const root = await fs.lstat(rootPath, { bigint: true });
209
+ const root = fsSync.lstatSync(rootPath, { bigint: true });
209
210
  assertDirectory(root, "queue retirement root");
210
211
  await syncDirectory(parentPath);
211
212
  return rootPath;
@@ -1 +1 @@
1
- {"version":3,"file":"json-durable-queue.d.ts","sourceRoot":"","sources":["../src/json-durable-queue.ts"],"names":[],"mappings":"AAmBA,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,0BAA0B,CAAC,CAAC,IAAI;IAC1C,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,2BAA2B,CAAC,CAAC,IAAI;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAOF,eAAO,MAAM,0CAA0C,QAAmB,CAAC;AAM3E,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtE;AAED,wBAAsB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUpF;AAmBD,wBAAgB,iCAAiC,CAC/C,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,GACT,0BAA0B,CAO5B;AAED,wBAAsB,0BAA0B,CAAC,MAAM,EAAE;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhB;AAgLD,wBAAsB,0BAA0B,CAAC,MAAM,EAAE;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQhB;AA6DD,wBAAsB,yBAAyB,CAAC,CAAC,EAC/C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,OAAO,CAAC,CAAC,CAAC,CASZ;AAED,wBAAsB,wBAAwB,CAAC,KAAK,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/F;AAED,wBAAsB,yBAAyB,CAAC,CAAC,EAAE,MAAM,EAAE;IACzD,KAAK,EAAE,0BAA0B,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAsBpB;AAED,wBAAsB,kCAAkC,CAAC,CAAC,EACxD,OAAO,EAAE,2BAA2B,CAAC,CAAC,CAAC,GACtC,OAAO,CAAC,CAAC,EAAE,CAAC,CA8Dd;AAED,wBAAsB,iCAAiC,CAAC,MAAM,EAAE;IAC9D,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;CACZ,GAAG,OAAO,CAAC,IAAI,CAAC,CAShB"}
1
+ {"version":3,"file":"json-durable-queue.d.ts","sourceRoot":"","sources":["../src/json-durable-queue.ts"],"names":[],"mappings":"AAoBA,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,0BAA0B,CAAC,CAAC,IAAI;IAC1C,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,2BAA2B,CAAC,CAAC,IAAI;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAOF,eAAO,MAAM,0CAA0C,QAAmB,CAAC;AAM3E,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtE;AAED,wBAAsB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUpF;AAmBD,wBAAgB,iCAAiC,CAC/C,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,GACT,0BAA0B,CAO5B;AAED,wBAAsB,0BAA0B,CAAC,MAAM,EAAE;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhB;AAiLD,wBAAsB,0BAA0B,CAAC,MAAM,EAAE;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQhB;AAyDD,wBAAsB,yBAAyB,CAAC,CAAC,EAC/C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,OAAO,CAAC,CAAC,CAAC,CASZ;AAED,wBAAsB,wBAAwB,CAAC,KAAK,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/F;AAED,wBAAsB,yBAAyB,CAAC,CAAC,EAAE,MAAM,EAAE;IACzD,KAAK,EAAE,0BAA0B,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAsBpB;AAED,wBAAsB,kCAAkC,CAAC,CAAC,EACxD,OAAO,EAAE,2BAA2B,CAAC,CAAC,CAAC,GACtC,OAAO,CAAC,CAAC,EAAE,CAAC,CA+Dd;AAED,wBAAsB,iCAAiC,CAAC,MAAM,EAAE;IAC9D,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;CACZ,GAAG,OAAO,CAAC,IAAI,CAAC,CAShB"}
@@ -1,6 +1,7 @@
1
1
  import fs, {} from "node:fs";
2
2
  import path from "node:path";
3
3
  import { normalizeMaxBytes } from "./byte-budget.js";
4
+ import { readBoundedAsync } from "./bounded-read.js";
4
5
  import { syncDirectory } from "./directory-durability.js";
5
6
  import { syncQueueDirectoryCreation } from "./json-durable-queue-directory.js";
6
7
  import { getErrorCode, acknowledgeDurableQueueEntry, claimDurableQueueEntry, completeDeliveredQueueEntry, moveDurableQueueEntryToFailed, } from "./json-durable-queue-ownership.js";
@@ -18,7 +19,7 @@ export async function unlinkBestEffort(filePath) {
18
19
  }
19
20
  export async function jsonDurableQueueEntryExists(filePath) {
20
21
  try {
21
- const stat = await fs.promises.lstat(filePath);
22
+ const stat = fs.lstatSync(filePath);
22
23
  return stat.isFile();
23
24
  }
24
25
  catch (error) {
@@ -30,7 +31,7 @@ export async function jsonDurableQueueEntryExists(filePath) {
30
31
  }
31
32
  async function unlinkStaleTmpBestEffort(filePath, now, maxAgeMs) {
32
33
  try {
33
- const stat = await fs.promises.stat(filePath);
34
+ const stat = fs.statSync(filePath);
34
35
  if (stat.isFile() && now - stat.mtimeMs >= maxAgeMs) {
35
36
  await unlinkBestEffort(filePath);
36
37
  }
@@ -113,22 +114,27 @@ async function isDarwinSystemAlias(dir, stat) {
113
114
  if (resolved !== "/tmp" && resolved !== "/var") {
114
115
  return false;
115
116
  }
116
- return await fs.promises.realpath(resolved).then((realPath) => realPath === `/private${resolved}`, () => false);
117
+ try {
118
+ return fs.realpathSync.native(resolved) === `/private${resolved}`;
119
+ }
120
+ catch {
121
+ return false;
122
+ }
117
123
  }
118
124
  async function assertNoSymlinkDirectorySegments(validationRoot, dir, allowMissing) {
119
125
  let base = path.resolve(validationRoot.path);
120
126
  let target = path.resolve(dir);
121
127
  let current = base;
122
- let baseStat = await fs.promises.lstat(base);
128
+ let baseStat = fs.lstatSync(base);
123
129
  if (baseStat.isSymbolicLink() && validationRoot.allowSymlinkBase) {
124
130
  const relative = path.relative(base, target);
125
131
  if (relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
126
132
  throw new Error(`durable queue path is not a directory: ${dir}`);
127
133
  }
128
- base = await fs.promises.realpath(base);
134
+ base = fs.realpathSync.native(base);
129
135
  target = path.join(base, ...relative.split(path.sep).filter(Boolean));
130
136
  current = base;
131
- baseStat = await fs.promises.lstat(base);
137
+ baseStat = fs.lstatSync(base);
132
138
  }
133
139
  if (baseStat.isSymbolicLink() || !baseStat.isDirectory()) {
134
140
  throw new Error(`durable queue path is not a directory: ${dir}`);
@@ -142,7 +148,7 @@ async function assertNoSymlinkDirectorySegments(validationRoot, dir, allowMissin
142
148
  current = path.join(current, segment);
143
149
  let stat;
144
150
  try {
145
- stat = await fs.promises.lstat(current);
151
+ stat = fs.lstatSync(current);
146
152
  }
147
153
  catch (error) {
148
154
  if (allowMissing && error.code === "ENOENT") {
@@ -153,7 +159,7 @@ async function assertNoSymlinkDirectorySegments(validationRoot, dir, allowMissin
153
159
  if (stat.isSymbolicLink() || !stat.isDirectory()) {
154
160
  if (stat.isSymbolicLink() && validationRoot.allowSymlinkBase) {
155
161
  if (await isDarwinSystemAlias(current, stat)) {
156
- current = await fs.promises.realpath(current);
162
+ current = fs.realpathSync.native(current);
157
163
  continue;
158
164
  }
159
165
  }
@@ -172,7 +178,7 @@ async function chmodQueueDirectory(dir) {
172
178
  let handle;
173
179
  try {
174
180
  handle = await fs.promises.open(dir, fs.constants.O_RDONLY | noFollow | directoryFlag);
175
- const stat = await handle.stat();
181
+ const stat = fs.fstatSync(handle.fd);
176
182
  if (!stat.isDirectory()) {
177
183
  throw new Error(`durable queue path is not a directory: ${dir}`);
178
184
  }
@@ -193,7 +199,7 @@ async function chmodQueueDirectory(dir) {
193
199
  }
194
200
  }
195
201
  }
196
- const stat = await fs.promises.lstat(dir);
202
+ const stat = fs.lstatSync(dir);
197
203
  if (stat.isSymbolicLink() || !stat.isDirectory()) {
198
204
  throw new Error(`durable queue path is not a directory: ${dir}`);
199
205
  }
@@ -218,7 +224,7 @@ async function inspectQueueEntry(inspect, maxBytes, expected) {
218
224
  try {
219
225
  return await inspectFileIdentity(async () => {
220
226
  try {
221
- const stat = await inspect();
227
+ const stat = inspect();
222
228
  if (stat.isSymbolicLink() || !stat.isFile()) {
223
229
  throw new Error("queue entry is not a regular file");
224
230
  }
@@ -242,26 +248,18 @@ async function inspectQueueEntry(inspect, maxBytes, expected) {
242
248
  }
243
249
  }
244
250
  async function readBoundedUtf8File(params) {
245
- const inspectPath = () => fs.promises.lstat(params.filePath, { bigint: true });
251
+ const inspectPath = () => fs.lstatSync(params.filePath, { bigint: true });
246
252
  const initialStat = await inspectQueueEntry(inspectPath, params.maxBytes);
247
253
  const handle = await fs.promises.open(params.filePath, resolveReadOpenFlags());
248
254
  try {
249
- const openedStat = await inspectQueueEntry(() => handle.stat({ bigint: true }), params.maxBytes, initialStat);
255
+ const openedStat = await inspectQueueEntry(() => fs.fstatSync(handle.fd, { bigint: true }), params.maxBytes, initialStat);
250
256
  await inspectQueueEntry(inspectPath, params.maxBytes, openedStat);
251
- const chunks = [];
252
- const scratch = Buffer.allocUnsafe(Math.min(64 * 1024, params.maxBytes + 1));
253
- let total = 0;
254
- while (true) {
255
- const { bytesRead } = await handle.read(scratch, 0, scratch.length, null);
256
- if (bytesRead === 0) {
257
- return Buffer.concat(chunks, total).toString("utf8");
258
- }
259
- total += bytesRead;
260
- if (total > params.maxBytes) {
261
- throw new Error(`queue entry exceeds ${params.maxBytes} bytes`);
262
- }
263
- chunks.push(Buffer.from(scratch.subarray(0, bytesRead)));
264
- }
257
+ const bytes = await readBoundedAsync(params.maxBytes, async (buffer, length) => (await handle.read(buffer, 0, length, null)).bytesRead, {
258
+ initialSize: openedStat.size >= 0n && Number.isSafeInteger(Number(openedStat.size))
259
+ ? Number(openedStat.size) : undefined,
260
+ createLimitError: () => new Error(`queue entry exceeds ${params.maxBytes} bytes`),
261
+ });
262
+ return bytes.toString("utf8");
265
263
  }
266
264
  finally {
267
265
  await handle.close();
@@ -318,6 +316,12 @@ export async function loadPendingJsonDurableQueueEntries(options) {
318
316
  for (const file of files) {
319
317
  if (file.endsWith(".delivered")) {
320
318
  const id = file.slice(0, -".delivered".length);
319
+ try {
320
+ assertSafeQueueEntryId(id);
321
+ }
322
+ catch {
323
+ continue;
324
+ }
321
325
  await completeDeliveredQueueEntry(resolveJsonDurableQueueEntryPaths(options.queueDir, id));
322
326
  }
323
327
  else if (options.cleanupTmpMaxAgeMs !== undefined && file.endsWith(".tmp")) {
@@ -1 +1 @@
1
- {"version":3,"file":"local-roots.d.ts","sourceRoot":"","sources":["../src/local-roots.ts"],"names":[],"mappings":"AAQA,OAAO,EAAQ,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAE3F,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,UAAU,GAAG;IAC9C,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG,sBAAsB,GAAG;IAC1E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,sBAAsB,GAAG;IACnE,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B,CAAC;AAgDF,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,oCAAoC,GAC5C,oBAAoB,GAAG,IAAI,CAuC7B;AAED,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CA2CtC"}
1
+ {"version":3,"file":"local-roots.d.ts","sourceRoot":"","sources":["../src/local-roots.ts"],"names":[],"mappings":"AAOA,OAAO,EAAQ,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAE3F,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,UAAU,GAAG;IAC9C,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG,sBAAsB,GAAG;IAC1E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,sBAAsB,GAAG;IACnE,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B,CAAC;AAsDF,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,oCAAoC,GAC5C,oBAAoB,GAAG,IAAI,CAqC7B;AAED,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAiCtC"}