@openclaw/fs-safe 0.11.0 → 0.12.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 (116) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +4 -2
  3. package/dist/advanced.d.ts +1 -1
  4. package/dist/advanced.d.ts.map +1 -1
  5. package/dist/advanced.js +1 -1
  6. package/dist/archive-entry.d.ts.map +1 -1
  7. package/dist/archive-entry.js +4 -3
  8. package/dist/archive-gzip-tail.d.ts.map +1 -1
  9. package/dist/archive-gzip-tail.js +13 -9
  10. package/dist/archive-read.d.ts.map +1 -1
  11. package/dist/archive-read.js +37 -33
  12. package/dist/archive-zip-names.d.ts.map +1 -1
  13. package/dist/archive-zip-names.js +17 -5
  14. package/dist/bounded-read.js +2 -2
  15. package/dist/device-path.d.ts.map +1 -1
  16. package/dist/device-path.js +5 -3
  17. package/dist/file-hash.d.ts.map +1 -1
  18. package/dist/file-hash.js +9 -2
  19. package/dist/file-store-prune.d.ts.map +1 -1
  20. package/dist/file-store-prune.js +9 -1
  21. package/dist/filename.d.ts +1 -0
  22. package/dist/filename.d.ts.map +1 -1
  23. package/dist/filename.js +30 -13
  24. package/dist/guarded-mkdir.d.ts +2 -0
  25. package/dist/guarded-mkdir.d.ts.map +1 -1
  26. package/dist/guarded-mkdir.js +50 -15
  27. package/dist/guest.d.ts.map +1 -1
  28. package/dist/guest.js +12 -4
  29. package/dist/install-path.d.ts +6 -0
  30. package/dist/install-path.d.ts.map +1 -1
  31. package/dist/install-path.js +13 -0
  32. package/dist/json-durable-queue-ownership.d.ts +2 -0
  33. package/dist/json-durable-queue-ownership.d.ts.map +1 -1
  34. package/dist/json-durable-queue-ownership.js +47 -3
  35. package/dist/json-durable-queue-read.d.ts +6 -0
  36. package/dist/json-durable-queue-read.d.ts.map +1 -0
  37. package/dist/json-durable-queue-read.js +59 -0
  38. package/dist/json-durable-queue.d.ts +1 -1
  39. package/dist/json-durable-queue.d.ts.map +1 -1
  40. package/dist/json-durable-queue.js +37 -80
  41. package/dist/native-binding.d.ts +7 -0
  42. package/dist/native-binding.d.ts.map +1 -1
  43. package/dist/path-scope-lexical.d.ts +14 -0
  44. package/dist/path-scope-lexical.d.ts.map +1 -0
  45. package/dist/path-scope-lexical.js +27 -0
  46. package/dist/path.d.ts.map +1 -1
  47. package/dist/path.js +20 -2
  48. package/dist/pinned-write.js +1 -0
  49. package/dist/root-boundary.d.ts +25 -0
  50. package/dist/root-boundary.d.ts.map +1 -0
  51. package/dist/root-boundary.js +177 -0
  52. package/dist/root-context.d.ts.map +1 -1
  53. package/dist/root-context.js +32 -5
  54. package/dist/root-directory-list.d.ts.map +1 -1
  55. package/dist/root-directory-list.js +10 -2
  56. package/dist/root-impl.d.ts.map +1 -1
  57. package/dist/root-impl.js +53 -34
  58. package/dist/root-move-preflight.d.ts +8 -0
  59. package/dist/root-move-preflight.d.ts.map +1 -0
  60. package/dist/root-move-preflight.js +16 -0
  61. package/dist/root-path-existing.d.ts +2 -0
  62. package/dist/root-path-existing.d.ts.map +1 -1
  63. package/dist/root-path-existing.js +10 -2
  64. package/dist/root-path.d.ts +2 -0
  65. package/dist/root-path.d.ts.map +1 -1
  66. package/dist/root-path.js +54 -26
  67. package/dist/root-paths.d.ts +2 -6
  68. package/dist/root-paths.d.ts.map +1 -1
  69. package/dist/root-paths.js +14 -26
  70. package/dist/root-walk.d.ts.map +1 -1
  71. package/dist/root-walk.js +2 -1
  72. package/dist/root-write-mode.d.ts +2 -0
  73. package/dist/root-write-mode.d.ts.map +1 -1
  74. package/dist/root-write-mode.js +20 -7
  75. package/dist/root-write-verification.d.ts.map +1 -1
  76. package/dist/root-write-verification.js +12 -3
  77. package/dist/safe-path-segment.d.ts.map +1 -1
  78. package/dist/safe-path-segment.js +3 -1
  79. package/dist/secure-file-windows.d.ts +10 -0
  80. package/dist/secure-file-windows.d.ts.map +1 -0
  81. package/dist/secure-file-windows.js +186 -0
  82. package/dist/secure-file.d.ts.map +1 -1
  83. package/dist/secure-file.js +6 -3
  84. package/dist/sibling-staged-file.d.ts +1 -0
  85. package/dist/sibling-staged-file.d.ts.map +1 -1
  86. package/dist/sibling-staged-file.js +7 -0
  87. package/dist/sibling-temp.d.ts.map +1 -1
  88. package/dist/sibling-temp.js +2 -1
  89. package/dist/sidecar-lock-acquire.js +1 -1
  90. package/dist/sidecar-lock.d.ts.map +1 -1
  91. package/dist/sidecar-lock.js +2 -3
  92. package/dist/temp-target.d.ts.map +1 -1
  93. package/dist/temp-target.js +3 -1
  94. package/dist/walk.d.ts.map +1 -1
  95. package/dist/walk.js +11 -10
  96. package/docs/advanced.md +3 -1
  97. package/docs/archive.md +6 -0
  98. package/docs/contributing.md +4 -1
  99. package/docs/copy.md +1 -1
  100. package/docs/durability.md +4 -2
  101. package/docs/file-store.md +6 -0
  102. package/docs/filename.md +9 -2
  103. package/docs/guest.md +5 -0
  104. package/docs/install-path.md +59 -13
  105. package/docs/install.md +4 -1
  106. package/docs/native-helper.md +4 -2
  107. package/docs/native.md +14 -2
  108. package/docs/path.md +1 -1
  109. package/docs/permissions.md +26 -1
  110. package/docs/public-api.md +5 -0
  111. package/docs/root.md +3 -1
  112. package/docs/secure-file.md +15 -14
  113. package/docs/security-model.md +1 -1
  114. package/docs/store.md +22 -1
  115. package/docs/temp.md +4 -0
  116. package/package.json +8 -8
@@ -1,14 +1,21 @@
1
1
  import fsSync from "node:fs";
2
2
  import fs from "node:fs/promises";
3
3
  import path from "node:path";
4
- import { assertAsyncDirectoryGuard, createAsyncDirectoryGuard } from "./directory-guard.js";
4
+ import { assertAsyncDirectoryGuard, createAsyncDirectoryGuard, } from "./directory-guard.js";
5
5
  import { FsSafeError } from "./errors.js";
6
6
  import { isNotFoundPathError, isPathRelativeEscape } from "./path.js";
7
- import { directoryComponentNotDirectoryError } from "./root-errors.js";
7
+ import { directoryComponentNotDirectoryError, rootPathChangedError } from "./root-errors.js";
8
8
  import { realpathSync } from "./realpath.js";
9
- function isSameOrChildPath(candidate, parent) {
10
- const parentPrefix = parent.endsWith(path.sep) ? parent : `${parent}${path.sep}`;
11
- return candidate === parent || candidate.startsWith(parentPrefix);
9
+ import { admitPathInsideRoot } from "./root-boundary.js";
10
+ function suppliedExactRootIdentity(identity) {
11
+ return typeof identity?.dev === "bigint" && typeof identity.ino === "bigint"
12
+ ? { dev: identity.dev, ino: identity.ino }
13
+ : undefined;
14
+ }
15
+ function assertGuardMatchesRootIdentity(guard, expected) {
16
+ if (guard.stat.dev !== expected.dev || guard.stat.ino !== expected.ino) {
17
+ throw rootPathChangedError();
18
+ }
12
19
  }
13
20
  async function realpathOrThrowNotFile(target) {
14
21
  try {
@@ -31,16 +38,38 @@ async function realpathOrThrowNotFile(target) {
31
38
  */
32
39
  export async function mkdirPathComponentsWithGuards(params) {
33
40
  const root = path.resolve(params.rootReal);
34
- const rootCanonical = path.resolve(realpathSync.native(root));
41
+ const configuredRootGuard = await createAsyncDirectoryGuard(root, { bigint: true });
42
+ const suppliedIdentity = suppliedExactRootIdentity(params.rootIdentity);
43
+ const checkedRootIdentity = suppliedIdentity ?? {
44
+ dev: configuredRootGuard.stat.dev,
45
+ ino: configuredRootGuard.stat.ino,
46
+ };
47
+ assertGuardMatchesRootIdentity(configuredRootGuard, checkedRootIdentity);
48
+ const rootCanonical = path.resolve(configuredRootGuard.realPath);
49
+ const rootGuard = rootCanonical === root
50
+ ? configuredRootGuard
51
+ : await createAsyncDirectoryGuard(rootCanonical, { bigint: true });
52
+ assertGuardMatchesRootIdentity(rootGuard, checkedRootIdentity);
35
53
  const target = path.resolve(params.targetPath);
36
- const relative = path.relative(root, target);
37
- if (isPathRelativeEscape(relative)) {
54
+ const admissionParams = {
55
+ candidatePath: target,
56
+ rootIdentity: checkedRootIdentity,
57
+ };
58
+ // Derive the suffix from the caller's trusted root spelling first. The
59
+ // canonical spelling is also accepted after both names have been bound to
60
+ // the same exact root object above.
61
+ const admittedTarget = admitPathInsideRoot({ rootPath: root, ...admissionParams }) ??
62
+ (rootCanonical === root
63
+ ? undefined
64
+ : admitPathInsideRoot({ rootPath: rootCanonical, ...admissionParams }));
65
+ if (!admittedTarget || isPathRelativeEscape(admittedTarget.relativePath)) {
38
66
  throw new FsSafeError("outside-workspace", "directory is outside workspace root");
39
67
  }
40
- let current = root;
41
- for (const part of relative.split(path.sep).filter(Boolean)) {
68
+ let current = rootCanonical;
69
+ let currentGuard = rootGuard;
70
+ for (const part of admittedTarget.relativePath.split(path.sep).filter(Boolean)) {
42
71
  const next = path.join(current, part);
43
- const parentGuard = await createAsyncDirectoryGuard(current);
72
+ const parentGuard = currentGuard;
44
73
  await assertAsyncDirectoryGuard(parentGuard);
45
74
  await params.beforeComponent?.(next);
46
75
  params.assertBeforeMutation?.();
@@ -58,10 +87,16 @@ export async function mkdirPathComponentsWithGuards(params) {
58
87
  }
59
88
  // Node's recursive mkdir follows symlinks in missing components. Build one
60
89
  // segment at a time and realpath-check each segment before descending.
61
- const nextReal = await realpathOrThrowNotFile(next);
62
- if (!isSameOrChildPath(nextReal, rootCanonical)) {
90
+ const observedNextReal = await realpathOrThrowNotFile(next);
91
+ const admittedNextReal = admitPathInsideRoot({
92
+ rootPath: rootCanonical,
93
+ candidatePath: observedNextReal,
94
+ rootIdentity: checkedRootIdentity,
95
+ });
96
+ if (!admittedNextReal) {
63
97
  throw new FsSafeError("outside-workspace", "directory escaped workspace root");
64
98
  }
99
+ const nextReal = admittedNextReal.path;
65
100
  if (stat.isSymbolicLink()) {
66
101
  // An existing path component may legitimately be a symlink to a real
67
102
  // directory inside the root (e.g. a skill-bank layout). We already
@@ -76,12 +111,12 @@ export async function mkdirPathComponentsWithGuards(params) {
76
111
  if (!targetStat.isDirectory()) {
77
112
  throw directoryComponentNotDirectoryError();
78
113
  }
79
- await createAsyncDirectoryGuard(nextReal);
114
+ currentGuard = await createAsyncDirectoryGuard(nextReal);
80
115
  await assertAsyncDirectoryGuard(parentGuard);
81
116
  current = nextReal;
82
117
  continue;
83
118
  }
84
- await createAsyncDirectoryGuard(next);
119
+ currentGuard = await createAsyncDirectoryGuard(next);
85
120
  await assertAsyncDirectoryGuard(parentGuard);
86
121
  current = next;
87
122
  }
@@ -1 +1 @@
1
- {"version":3,"file":"guest.d.ts","sourceRoot":"","sources":["../src/guest.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,yCAAyC,EAC1C,MAAM,0BAA0B,CAAC;AAElC,yFAAyF;AACzF,eAAO,MAAM,wCAAwC,KAAK,CAAC;AAC3D,8EAA8E;AAC9E,eAAO,MAAM,yCAAyC,IAAI,CAAC;AAE3D,gGAAgG;AAChG,eAAO,MAAM,uBAAuB,QAmZxB,CAAC;AAEb,OAAO,EAAE,yCAAyC,EAAE,CAAC"}
1
+ {"version":3,"file":"guest.d.ts","sourceRoot":"","sources":["../src/guest.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,yCAAyC,EAC1C,MAAM,0BAA0B,CAAC;AAElC,yFAAyF;AACzF,eAAO,MAAM,wCAAwC,KAAK,CAAC;AAC3D,8EAA8E;AAC9E,eAAO,MAAM,yCAAyC,IAAI,CAAC;AAE3D,gGAAgG;AAChG,eAAO,MAAM,uBAAuB,QA2ZxB,CAAC;AAEb,OAAO,EAAE,yCAAyC,EAAE,CAAC"}
package/dist/guest.js CHANGED
@@ -356,11 +356,19 @@ export const GUEST_FILESYSTEM_PYTHON = [
356
356
  " return",
357
357
  " if stat.S_ISLNK(src_stat.st_mode):",
358
358
  " link_target = os.readlink(src_basename, dir_fd=src_parent_fd)",
359
+ " temp_dir_name, temp_dir_fd = create_staging_dir(dst_parent_fd)",
359
360
  " try:",
360
- " os.unlink(dst_basename, dir_fd=dst_parent_fd)",
361
- " except FileNotFoundError:",
362
- " pass",
363
- " os.symlink(link_target, dst_basename, dir_fd=dst_parent_fd)",
361
+ " os.symlink(link_target, 'link', dir_fd=temp_dir_fd)",
362
+ " os.replace('link', dst_basename, src_dir_fd=temp_dir_fd, dst_dir_fd=dst_parent_fd)",
363
+ " finally:",
364
+ " try:",
365
+ " try:",
366
+ " os.unlink('link', dir_fd=temp_dir_fd)",
367
+ " except FileNotFoundError:",
368
+ " pass",
369
+ " finally:",
370
+ " os.close(temp_dir_fd)",
371
+ " os.rmdir(temp_dir_name, dir_fd=dst_parent_fd)",
364
372
  " os.unlink(src_basename, dir_fd=src_parent_fd)",
365
373
  " os.fsync(dst_parent_fd)",
366
374
  " os.fsync(src_parent_fd)",
@@ -1,5 +1,11 @@
1
1
  export declare function safeDirName(input: string): string;
2
+ /** Legacy readable encoding; distinct IDs can share a result. Use V2 for untrusted IDs. */
2
3
  export declare function safePathSegmentHashed(input: string): string;
4
+ /**
5
+ * Versioned install-ID encoding: every trimmed ID receives a domain-separated
6
+ * SHA-256 digest. Only surrounding whitespace is intentionally equivalent.
7
+ */
8
+ export declare function safePathSegmentHashedV2(input: string): string;
3
9
  export declare function resolveSafeInstallDir(params: {
4
10
  baseDir: string;
5
11
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"install-path.d.ts","sourceRoot":"","sources":["../src/install-path.ts"],"names":[],"mappings":"AAMA,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
+ {"version":3,"file":"install-path.d.ts","sourceRoot":"","sources":["../src/install-path.ts"],"names":[],"mappings":"AAMA,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMjD;AAED,2FAA2F;AAC3F,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAiB3D;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAO7D;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"}
@@ -10,6 +10,7 @@ export function safeDirName(input) {
10
10
  }
11
11
  return trimmed.replaceAll("/", "__").replaceAll("\\", "__");
12
12
  }
13
+ /** Legacy readable encoding; distinct IDs can share a result. Use V2 for untrusted IDs. */
13
14
  export function safePathSegmentHashed(input) {
14
15
  const trimmed = input.trim();
15
16
  const base = trimmed
@@ -26,6 +27,18 @@ export function safePathSegmentHashed(input) {
26
27
  }
27
28
  return safe;
28
29
  }
30
+ /**
31
+ * Versioned install-ID encoding: every trimmed ID receives a domain-separated
32
+ * SHA-256 digest. Only surrounding whitespace is intentionally equivalent.
33
+ */
34
+ export function safePathSegmentHashedV2(input) {
35
+ const hash = createHash("sha256")
36
+ .update("@openclaw/fs-safe:install-path:v2\0", "utf8")
37
+ // UTF-16LE preserves every JavaScript code unit, including lone surrogates.
38
+ .update(input.trim(), "utf16le")
39
+ .digest("hex");
40
+ return `id-v2-${hash}`;
41
+ }
29
42
  export function resolveSafeInstallDir(params) {
30
43
  const encodedName = (params.nameEncoder ?? safeDirName)(params.id);
31
44
  const targetDir = path.join(params.baseDir, encodedName);
@@ -1,3 +1,4 @@
1
+ import { type BigIntStats } from "node:fs";
1
2
  export type DurableQueueEntryPathsLike = {
2
3
  jsonPath: string;
3
4
  deliveredPath: string;
@@ -7,6 +8,7 @@ export declare function durableQueueProcessingPath(paths: DurableQueueEntryPaths
7
8
  export declare function claimDurableQueueEntry(paths: DurableQueueEntryPathsLike, options?: {
8
9
  skipUnowned?: boolean;
9
10
  }): Promise<string | null>;
11
+ export declare function migrateDurableQueueEntry<T>(paths: DurableQueueEntryPathsLike, expected: BigIntStats, releaseReadPin: () => Promise<void>, run: (filePath: string, beforePublish: () => Promise<void>) => Promise<T>): Promise<T>;
10
12
  export declare function completeDeliveredQueueEntry(paths: DurableQueueEntryPathsLike): Promise<boolean>;
11
13
  export declare function acknowledgeDurableQueueEntry(paths: DurableQueueEntryPathsLike): Promise<void>;
12
14
  export declare function moveDurableQueueEntryToFailed(params: {
@@ -1 +1 @@
1
- {"version":3,"file":"json-durable-queue-ownership.d.ts","sourceRoot":"","sources":["../src/json-durable-queue-ownership.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,0BAA0B,GAAG,MAAM,CAKpF;AA+DD,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,0BAA0B,EACjC,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GACtC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGxB;AAED,wBAAsB,2BAA2B,CAC/C,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,OAAO,CAAC,CAalB;AAED,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,KAAK,EAAE,0BAA0B,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDhB;AAKD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAI1D"}
1
+ {"version":3,"file":"json-durable-queue-ownership.d.ts","sourceRoot":"","sources":["../src/json-durable-queue-ownership.ts"],"names":[],"mappings":"AAEA,OAAe,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AASnD,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,0BAA0B,GAAG,MAAM,CAKpF;AAwED,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,0BAA0B,EACjC,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GACtC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGxB;AAGD,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,KAAK,EAAE,0BAA0B,EACjC,QAAQ,EAAE,WAAW,EACrB,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EACnC,GAAG,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GACxE,OAAO,CAAC,CAAC,CAAC,CAkCZ;AAED,wBAAsB,2BAA2B,CAC/C,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,OAAO,CAAC,CAalB;AAED,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,KAAK,EAAE,0BAA0B,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDhB;AAKD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAI1D"}
@@ -6,6 +6,7 @@ import path from "node:path";
6
6
  import { syncDirectory } from "./directory-durability.js";
7
7
  import { FsSafeError } from "./errors.js";
8
8
  import { sameFileIdentityForCleanup, sha256Hex } from "./file-identity.js";
9
+ import { inspectFileIdentity } from "./strict-file-identity.js";
9
10
  import { serializePathWrite } from "./write-queue.js";
10
11
  export function durableQueueProcessingPath(paths) {
11
12
  if (paths.processingPath)
@@ -32,10 +33,17 @@ async function claimDurableQueueEntryUnlocked(paths, options = {}) {
32
33
  const existingProcessing = await regularQueueFileIdentity(processingPath);
33
34
  if (existingProcessing) {
34
35
  const pending = await lstatOrNull(paths.jsonPath);
35
- if (pending &&
36
+ const retiresPending = pending !== null &&
36
37
  !pending.isSymbolicLink() &&
37
38
  pending.isFile() &&
38
- sameFileIdentityForCleanup(pending, existingProcessing)) {
39
+ sameFileIdentityForCleanup(pending, existingProcessing);
40
+ if (!retiresPending ||
41
+ path.resolve(path.dirname(processingPath)) !== path.resolve(path.dirname(paths.jsonPath))) {
42
+ // An existing claim can contain a migration whose publication sync failed.
43
+ // Retirement already syncs this edge when both names share a parent.
44
+ await syncDirectory(path.dirname(processingPath));
45
+ }
46
+ if (retiresPending) {
39
47
  await retireDurableQueueSource({ jsonPath: paths.jsonPath, processingPath });
40
48
  }
41
49
  return processingPath;
@@ -54,7 +62,10 @@ async function claimDurableQueueEntryUnlocked(paths, options = {}) {
54
62
  }
55
63
  catch (error) {
56
64
  if (getErrorCode(error) === "EEXIST") {
57
- return (await regularQueueFileIdentity(processingPath)) ? processingPath : null;
65
+ if (!(await regularQueueFileIdentity(processingPath)))
66
+ return null;
67
+ await syncDirectory(path.dirname(processingPath));
68
+ return processingPath;
58
69
  }
59
70
  if (getErrorCode(error) === "ENOENT")
60
71
  return null;
@@ -73,6 +84,39 @@ export async function claimDurableQueueEntry(paths, options = {}) {
73
84
  return null;
74
85
  return await withQueueEntryLock(paths, async () => await claimDurableQueueEntryUnlocked(paths, options));
75
86
  }
87
+ // The caller retains its read pin until this owner releases it or migration settles.
88
+ export async function migrateDurableQueueEntry(paths, expected, releaseReadPin, run) {
89
+ return await withQueueEntryLock(paths, async () => {
90
+ const processingPath = durableQueueProcessingPath(paths);
91
+ const assertCurrent = async () => {
92
+ try {
93
+ await inspectFileIdentity(() => {
94
+ const current = fsSync.lstatSync(processingPath, { bigint: true });
95
+ if (current.isSymbolicLink() || !current.isFile() || current.nlink !== 1n) {
96
+ throw new FsSafeError("path-mismatch", "queue migration requires its original processing claim");
97
+ }
98
+ return current;
99
+ }, expected);
100
+ }
101
+ catch (error) {
102
+ if (getErrorCode(error) === "ENOENT") {
103
+ throw new FsSafeError("path-mismatch", "queue processing claim disappeared before migration", { cause: error });
104
+ }
105
+ throw error;
106
+ }
107
+ };
108
+ await assertCurrent();
109
+ return await run(processingPath, async () => {
110
+ await assertCurrent();
111
+ if (process.platform === "win32") {
112
+ // Windows cannot replace our still-open target. Keep the transfer lock
113
+ // across release and reject changes made while the async close settles.
114
+ await releaseReadPin();
115
+ await assertCurrent();
116
+ }
117
+ });
118
+ });
119
+ }
76
120
  export async function completeDeliveredQueueEntry(paths) {
77
121
  if (!(await lstatOrNull(path.dirname(paths.deliveredPath))))
78
122
  return false;
@@ -0,0 +1,6 @@
1
+ import { type BigIntStats } from "node:fs";
2
+ export declare const DEFAULT_JSON_DURABLE_QUEUE_ENTRY_MAX_BYTES: number;
3
+ export declare function withJsonDurableQueueEntry<T, R>(filePath: string, options: {
4
+ maxBytes?: number;
5
+ }, run: (entry: T, identity: BigIntStats, releaseReadPin: () => Promise<void>) => Promise<R>): Promise<R>;
6
+ //# sourceMappingURL=json-durable-queue-read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-durable-queue-read.d.ts","sourceRoot":"","sources":["../src/json-durable-queue-read.ts"],"names":[],"mappings":"AAAA,OAAW,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAM/C,eAAO,MAAM,0CAA0C,QAAmB,CAAC;AA8B3E,wBAAsB,yBAAyB,CAAC,CAAC,EAAE,CAAC,EAClD,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EAC9B,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GACxF,OAAO,CAAC,CAAC,CAAC,CA8BZ"}
@@ -0,0 +1,59 @@
1
+ import fs, {} from "node:fs";
2
+ import { normalizeMaxBytes } from "./byte-budget.js";
3
+ import { readBoundedAsync } from "./bounded-read.js";
4
+ import { resolveReadOpenFlags } from "./read-open-flags.js";
5
+ import { inspectFileIdentity } from "./strict-file-identity.js";
6
+ export const DEFAULT_JSON_DURABLE_QUEUE_ENTRY_MAX_BYTES = 16 * 1024 * 1024;
7
+ async function inspectQueueEntry(inspect, maxBytes, expected) {
8
+ let inspectionFailed = false;
9
+ try {
10
+ return await inspectFileIdentity(async () => {
11
+ try {
12
+ const stat = inspect();
13
+ if (stat.isSymbolicLink() || !stat.isFile()) {
14
+ throw new Error("queue entry is not a regular file");
15
+ }
16
+ if (stat.nlink > 1n)
17
+ throw new Error("queue entry hardlinks are not allowed");
18
+ if (stat.size > maxBytes)
19
+ throw new Error(`queue entry exceeds ${maxBytes} bytes`);
20
+ return stat;
21
+ }
22
+ catch (error) {
23
+ inspectionFailed = true;
24
+ throw error;
25
+ }
26
+ }, expected);
27
+ }
28
+ catch (error) {
29
+ // Translate only the identity helper's rejection, never inspection errors.
30
+ if (inspectionFailed)
31
+ throw error;
32
+ throw new Error("queue entry changed during read", { cause: error });
33
+ }
34
+ }
35
+ export async function withJsonDurableQueueEntry(filePath, options, run) {
36
+ const maxBytes = normalizeMaxBytes(options.maxBytes, {
37
+ defaultValue: DEFAULT_JSON_DURABLE_QUEUE_ENTRY_MAX_BYTES,
38
+ });
39
+ const inspectPath = () => fs.lstatSync(filePath, { bigint: true });
40
+ const initialStat = await inspectQueueEntry(inspectPath, maxBytes);
41
+ const handle = await fs.promises.open(filePath, resolveReadOpenFlags());
42
+ let closePromise;
43
+ const releaseReadPin = () => closePromise ??= (async () => { await handle.close(); })();
44
+ try {
45
+ const openedStat = await inspectQueueEntry(() => fs.fstatSync(handle.fd, { bigint: true }), maxBytes, initialStat);
46
+ await inspectQueueEntry(inspectPath, maxBytes, openedStat);
47
+ const bytes = await readBoundedAsync(maxBytes, async (buffer, length) => (await handle.read(buffer, 0, length, null)).bytesRead, {
48
+ initialSize: openedStat.size >= 0n && Number.isSafeInteger(Number(openedStat.size))
49
+ ? Number(openedStat.size) : undefined,
50
+ createLimitError: () => new Error(`queue entry exceeds ${maxBytes} bytes`),
51
+ });
52
+ // The migration owner may release this pin only at the verified publication
53
+ // boundary; until then an unlinked inode cannot be recycled into a new claim.
54
+ return await run(JSON.parse(bytes.toString("utf8")), openedStat, releaseReadPin);
55
+ }
56
+ finally {
57
+ await releaseReadPin();
58
+ }
59
+ }
@@ -1,3 +1,4 @@
1
+ export { DEFAULT_JSON_DURABLE_QUEUE_ENTRY_MAX_BYTES } from "./json-durable-queue-read.js";
1
2
  export type JsonDurableQueueEntryPaths = {
2
3
  jsonPath: string;
3
4
  deliveredPath: string;
@@ -14,7 +15,6 @@ export type JsonDurableQueueLoadOptions<T> = {
14
15
  cleanupTmpMaxAgeMs?: number;
15
16
  maxBytes?: number;
16
17
  };
17
- export declare const DEFAULT_JSON_DURABLE_QUEUE_ENTRY_MAX_BYTES: number;
18
18
  export declare function unlinkBestEffort(filePath: string): Promise<void>;
19
19
  export declare function jsonDurableQueueEntryExists(filePath: string): Promise<boolean>;
20
20
  export declare function resolveJsonDurableQueueEntryPaths(queueDir: string, id: string): JsonDurableQueueEntryPaths;
@@ -1 +1 @@
1
- {"version":3,"file":"json-durable-queue.d.ts","sourceRoot":"","sources":["../src/json-durable-queue.ts"],"names":[],"mappings":"AAsBA,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
+ {"version":3,"file":"json-durable-queue.d.ts","sourceRoot":"","sources":["../src/json-durable-queue.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,0CAA0C,EAAE,MAAM,8BAA8B,CAAC;AAE1F,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;AAWF,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,CAEhB;AAgBD,wBAAsB,yBAAyB,CAAC,CAAC,EAC/C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,OAAO,CAAC,CAAC,CAAC,CAEZ;AAgBD,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,CAqBpB;AAED,wBAAsB,kCAAkC,CAAC,CAAC,EACxD,OAAO,EAAE,2BAA2B,CAAC,CAAC,CAAC,GACtC,OAAO,CAAC,CAAC,EAAE,CAAC,CAqEd;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,18 +1,15 @@
1
1
  import fs, {} from "node:fs";
2
2
  import path from "node:path";
3
- import { normalizeMaxBytes } from "./byte-budget.js";
4
- import { readBoundedAsync } from "./bounded-read.js";
5
3
  import { syncDirectory } from "./directory-durability.js";
6
4
  import { syncQueueDirectoryCreation } from "./json-durable-queue-directory.js";
7
- import { getErrorCode, acknowledgeDurableQueueEntry, claimDurableQueueEntry, completeDeliveredQueueEntry, moveDurableQueueEntryToFailed, } from "./json-durable-queue-ownership.js";
5
+ import { getErrorCode, acknowledgeDurableQueueEntry, claimDurableQueueEntry, completeDeliveredQueueEntry, migrateDurableQueueEntry, moveDurableQueueEntryToFailed, } from "./json-durable-queue-ownership.js";
6
+ import { withJsonDurableQueueEntry } from "./json-durable-queue-read.js";
8
7
  import { stringifyJsonDocument } from "./json-stringify.js";
9
- import { resolveReadOpenFlags } from "./read-open-flags.js";
10
8
  import { realpathSync } from "./realpath.js";
11
9
  import { recursiveMkdirPath } from "./recursive-mkdir-path.js";
12
10
  import { replaceFileAtomicWithDirectorySync } from "./replace-file.js";
13
11
  import { assertSafePathSegment } from "./safe-path-segment.js";
14
- import { inspectFileIdentity } from "./strict-file-identity.js";
15
- export const DEFAULT_JSON_DURABLE_QUEUE_ENTRY_MAX_BYTES = 16 * 1024 * 1024;
12
+ export { DEFAULT_JSON_DURABLE_QUEUE_ENTRY_MAX_BYTES } from "./json-durable-queue-read.js";
16
13
  function assertSafeQueueEntryId(id) {
17
14
  assertSafePathSegment(id, { label: "queue entry id" });
18
15
  }
@@ -213,67 +210,25 @@ async function chmodQueueDirectory(dir) {
213
210
  }
214
211
  }
215
212
  export async function writeJsonDurableQueueEntry(params) {
213
+ await writeQueueEntry(params);
214
+ }
215
+ async function writeQueueEntry(params, beforeRename) {
216
216
  await replaceFileAtomicWithDirectorySync({
217
217
  filePath: params.filePath,
218
218
  content: stringifyJsonDocument(params.entry, null, 2),
219
219
  mode: 0o600,
220
220
  tempPrefix: params.tempPrefix,
221
221
  syncTempFile: true,
222
+ beforeRename,
222
223
  }, syncDirectory);
223
224
  }
224
- async function inspectQueueEntry(inspect, maxBytes, expected) {
225
- let inspectionFailed = false;
226
- try {
227
- return await inspectFileIdentity(async () => {
228
- try {
229
- const stat = inspect();
230
- if (stat.isSymbolicLink() || !stat.isFile()) {
231
- throw new Error("queue entry is not a regular file");
232
- }
233
- if (stat.nlink > 1n)
234
- throw new Error("queue entry hardlinks are not allowed");
235
- if (stat.size > maxBytes)
236
- throw new Error(`queue entry exceeds ${maxBytes} bytes`);
237
- return stat;
238
- }
239
- catch (error) {
240
- inspectionFailed = true;
241
- throw error;
242
- }
243
- }, expected);
244
- }
245
- catch (error) {
246
- // Translate only the identity helper's rejection, never inspection errors.
247
- if (inspectionFailed)
248
- throw error;
249
- throw new Error("queue entry changed during read", { cause: error });
250
- }
251
- }
252
- async function readBoundedUtf8File(params) {
253
- const inspectPath = () => fs.lstatSync(params.filePath, { bigint: true });
254
- const initialStat = await inspectQueueEntry(inspectPath, params.maxBytes);
255
- const handle = await fs.promises.open(params.filePath, resolveReadOpenFlags());
256
- try {
257
- const openedStat = await inspectQueueEntry(() => fs.fstatSync(handle.fd, { bigint: true }), params.maxBytes, initialStat);
258
- await inspectQueueEntry(inspectPath, params.maxBytes, openedStat);
259
- const bytes = await readBoundedAsync(params.maxBytes, async (buffer, length) => (await handle.read(buffer, 0, length, null)).bytesRead, {
260
- initialSize: openedStat.size >= 0n && Number.isSafeInteger(Number(openedStat.size))
261
- ? Number(openedStat.size) : undefined,
262
- createLimitError: () => new Error(`queue entry exceeds ${params.maxBytes} bytes`),
263
- });
264
- return bytes.toString("utf8");
265
- }
266
- finally {
267
- await handle.close();
268
- }
269
- }
270
225
  export async function readJsonDurableQueueEntry(filePath, options = {}) {
271
- return JSON.parse(await readBoundedUtf8File({
272
- filePath,
273
- maxBytes: normalizeMaxBytes(options.maxBytes, {
274
- defaultValue: DEFAULT_JSON_DURABLE_QUEUE_ENTRY_MAX_BYTES,
275
- }),
276
- }));
226
+ return await withJsonDurableQueueEntry(filePath, options, async (entry) => entry);
227
+ }
228
+ async function migrateClaimedQueueEntry(params) {
229
+ await migrateDurableQueueEntry(params.paths, params.identity, params.releaseReadPin, async (filePath, beforePublish) => {
230
+ await writeQueueEntry({ filePath, entry: params.entry, tempPrefix: params.tempPrefix }, beforePublish);
231
+ });
277
232
  }
278
233
  export async function ackJsonDurableQueueEntry(paths) {
279
234
  await acknowledgeDurableQueueEntry(paths);
@@ -283,18 +238,17 @@ export async function loadJsonDurableQueueEntry(params) {
283
238
  const claimedPath = await claimDurableQueueEntry(params.paths);
284
239
  if (!claimedPath)
285
240
  return null;
286
- const raw = await readJsonDurableQueueEntry(claimedPath, {
241
+ return await withJsonDurableQueueEntry(claimedPath, {
287
242
  maxBytes: params.maxBytes,
243
+ }, async (raw, identity, releaseReadPin) => {
244
+ const result = params.read ? await params.read(raw, params.paths.jsonPath) : { entry: raw };
245
+ if (result.migrated) {
246
+ await migrateClaimedQueueEntry({
247
+ paths: params.paths, identity, releaseReadPin, entry: result.entry, tempPrefix: params.tempPrefix,
248
+ });
249
+ }
250
+ return result.entry;
288
251
  });
289
- const result = params.read ? await params.read(raw, params.paths.jsonPath) : { entry: raw };
290
- if (result.migrated) {
291
- await writeJsonDurableQueueEntry({
292
- filePath: claimedPath,
293
- entry: result.entry,
294
- tempPrefix: params.tempPrefix,
295
- });
296
- }
297
- return result.entry;
298
252
  }
299
253
  catch (error) {
300
254
  if (getErrorCode(error) === "ENOENT") {
@@ -358,22 +312,25 @@ export async function loadPendingJsonDurableQueueEntries(options) {
358
312
  const claimedPath = await claimDurableQueueEntry(paths, { skipUnowned: true });
359
313
  if (!claimedPath)
360
314
  continue;
361
- let result;
315
+ let migrationStarted = false;
362
316
  try {
363
- const raw = await readJsonDurableQueueEntry(claimedPath, { maxBytes: options.maxBytes });
364
- result = options.read ? await options.read(raw, paths.jsonPath) : { entry: raw };
317
+ const entry = await withJsonDurableQueueEntry(claimedPath, { maxBytes: options.maxBytes }, async (raw, identity, releaseReadPin) => {
318
+ const result = options.read ? await options.read(raw, paths.jsonPath) : { entry: raw };
319
+ if (result.migrated) {
320
+ migrationStarted = true;
321
+ await migrateClaimedQueueEntry({
322
+ paths, identity, releaseReadPin, entry: result.entry, tempPrefix: options.tempPrefix,
323
+ });
324
+ }
325
+ return result.entry;
326
+ });
327
+ entries.push(entry);
365
328
  }
366
- catch {
329
+ catch (error) {
330
+ if (migrationStarted)
331
+ throw error;
367
332
  continue;
368
333
  }
369
- if (result.migrated) {
370
- await writeJsonDurableQueueEntry({
371
- filePath: claimedPath,
372
- entry: result.entry,
373
- tempPrefix: options.tempPrefix,
374
- });
375
- }
376
- entries.push(result.entry);
377
334
  }
378
335
  return entries;
379
336
  }
@@ -75,6 +75,11 @@ export interface NativeWindowsSecurityFacts {
75
75
  unsupportedAceTypes: number[];
76
76
  aces: NativeWindowsAccessControlEntry[];
77
77
  }
78
+ export interface NativeWindowsDescriptorSecurityFacts {
79
+ /** Canonical lowercase 32-bit volume serial and 64-bit file-index projection used by Node. */
80
+ identity: string;
81
+ security: NativeWindowsSecurityFacts;
82
+ }
78
83
  export interface NativeBinding {
79
84
  /** POSIX system canonicalization; confinement and identity policy stay with callers. */
80
85
  canonicalizePath?(path: string, ordinary: boolean): {
@@ -111,6 +116,8 @@ export interface NativeBinding {
111
116
  openBeneath(rootFd: number, relPath: string, flags: number): NativeOpenBeneathResult;
112
117
  readArchiveEntryNative(path: string, kind: string, requested: string, maxBytes: number, limits: TarMeterLimits, signal: AbortSignal): Promise<Buffer>;
113
118
  readOwnerAndDacl(path: string): NativeWindowsSecurityFacts;
119
+ /** Internal Windows-only inspection of the exact borrowed Node descriptor. */
120
+ inspectWindowsSecureFileHandle?(fd: number): NativeWindowsDescriptorSecurityFacts;
114
121
  ownedTreeRemovalAvailable?(parentFd: number): boolean;
115
122
  removeOwnedTree?(parentFd: number, basename: string, directoryFd: number): Promise<NativeOwnedTreeRemovalResult>;
116
123
  removeOwnedTreeSync?(parentFd: number, basename: string, directoryFd: number): NativeOwnedTreeRemovalResult;
@@ -1 +1 @@
1
- {"version":3,"file":"native-binding.d.ts","sourceRoot":"","sources":["../src/native-binding.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"native-binding.d.ts","sourceRoot":"","sources":["../src/native-binding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export type ResolvePathWithinRootParams = {
2
+ rootDir: string;
3
+ requestedPath: string;
4
+ scopeLabel: string;
5
+ defaultFileName?: string;
6
+ };
7
+ export declare function resolvePathWithinNormalizedRoot(params: ResolvePathWithinRootParams, root: string): {
8
+ ok: true;
9
+ path: string;
10
+ } | {
11
+ ok: false;
12
+ error: string;
13
+ };
14
+ //# sourceMappingURL=path-scope-lexical.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-scope-lexical.d.ts","sourceRoot":"","sources":["../src/path-scope-lexical.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,2BAA2B,GAAG;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAUF,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,2BAA2B,EACnC,IAAI,EAAE,MAAM,GACX;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAiB3D"}