@openclaw/feishu 2026.9.8 → 2026.10.1-beta.1

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 (225) hide show
  1. package/dist/.setup/{channel-DV4hM2Uf.mjs → channel-CX62T71S.mjs} +146 -245
  2. package/dist/.setup/{channel.runtime-CXQcH5zZ.mjs → channel.runtime-COiaq-Rv.mjs} +6 -12
  3. package/dist/.setup/{chat-D8MlFAZi.mjs → chat-BdyvImsY.mjs} +6 -9
  4. package/dist/.setup/{client-BYG-_IZl.mjs → client-BsBVWJzN.mjs} +1 -1
  5. package/dist/.setup/{doctor-contract-3XC0vbIw.mjs → doctor-contract-B1B9ogdd.mjs} +212 -27
  6. package/dist/.setup/{monitor-D_rsHBZ6.mjs → monitor-7DvwUs4Y.mjs} +5 -6
  7. package/dist/.setup/{monitor.account-DvvY7i6k.mjs → monitor.account-7xVu7XWY.mjs} +190 -393
  8. package/dist/.setup/{probe-_ViqSi0j.mjs → probe-B9o7iey6.mjs} +13 -39
  9. package/dist/.setup/{reply-delivery-result-COAjaukc.mjs → reply-delivery-result-Bt-BWBEA.mjs} +151 -297
  10. package/dist/.setup/{setup-api-C4S5I3ac.mjs → setup-api-DmzX9S01.mjs} +1 -1
  11. package/dist/.setup/{subagent-hooks-BaFoMu8W.mjs → subagent-hooks-CUXg0pC-.mjs} +5 -11
  12. package/dist/.setup/{thread-bindings-EdLXPXzw.mjs → thread-bindings-jW2x5VuN.mjs} +23 -41
  13. package/dist/api.js +234 -297
  14. package/dist/channel-plugin-api.js +1 -1
  15. package/dist/doctor-contract-api.js +2 -2
  16. package/dist/session-binding-contract-api.js +1 -1
  17. package/dist/setup-api.js +1 -1
  18. package/dist/setup-entry.js +1 -1
  19. package/dist/subagent-hooks-api.js +1 -1
  20. package/node_modules/@openclaw/fs-safe/CHANGELOG.md +95 -0
  21. package/node_modules/@openclaw/fs-safe/README.md +70 -379
  22. package/node_modules/@openclaw/fs-safe/dist/absolute-path.js +35 -51
  23. package/node_modules/@openclaw/fs-safe/dist/advanced.d.ts +2 -0
  24. package/node_modules/@openclaw/fs-safe/dist/advanced.js +1 -0
  25. package/node_modules/@openclaw/fs-safe/dist/archive-input.js +2 -0
  26. package/node_modules/@openclaw/fs-safe/dist/archive-parser.wasm +0 -0
  27. package/node_modules/@openclaw/fs-safe/dist/archive-staging.d.ts +1 -1
  28. package/node_modules/@openclaw/fs-safe/dist/archive-staging.js +9 -10
  29. package/node_modules/@openclaw/fs-safe/dist/archive.js +2 -5
  30. package/node_modules/@openclaw/fs-safe/dist/atomic-io.d.ts +51 -0
  31. package/node_modules/@openclaw/fs-safe/dist/atomic-io.js +242 -0
  32. package/node_modules/@openclaw/fs-safe/dist/config.d.ts +1 -1
  33. package/node_modules/@openclaw/fs-safe/dist/config.js +1 -1
  34. package/node_modules/@openclaw/fs-safe/dist/copy-file-input.d.ts +1 -1
  35. package/node_modules/@openclaw/fs-safe/dist/copy-file-input.js +2 -2
  36. package/node_modules/@openclaw/fs-safe/dist/copy-tree-portable.js +2 -0
  37. package/node_modules/@openclaw/fs-safe/dist/create.js +12 -5
  38. package/node_modules/@openclaw/fs-safe/dist/directory-guard.d.ts +11 -0
  39. package/node_modules/@openclaw/fs-safe/dist/directory-guard.js +4 -7
  40. package/node_modules/@openclaw/fs-safe/dist/entry-publication-types.d.ts +55 -0
  41. package/node_modules/@openclaw/fs-safe/dist/entry-publication-types.js +1 -0
  42. package/node_modules/@openclaw/fs-safe/dist/entry-publication.d.ts +8 -0
  43. package/node_modules/@openclaw/fs-safe/dist/entry-publication.js +262 -0
  44. package/node_modules/@openclaw/fs-safe/dist/exclusive-create.d.ts +3 -0
  45. package/node_modules/@openclaw/fs-safe/dist/exclusive-create.js +22 -0
  46. package/node_modules/@openclaw/fs-safe/dist/file-cleanup.d.ts +1 -6
  47. package/node_modules/@openclaw/fs-safe/dist/file-cleanup.js +3 -6
  48. package/node_modules/@openclaw/fs-safe/dist/file-identity.js +3 -6
  49. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-io.js +2 -2
  50. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-mutation.js +9 -0
  51. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root.js +4 -6
  52. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-stale-admission.js +1 -1
  53. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync.js +8 -0
  54. package/node_modules/@openclaw/fs-safe/dist/file-store-boundary.js +2 -0
  55. package/node_modules/@openclaw/fs-safe/dist/file-store-sync-write.js +20 -18
  56. package/node_modules/@openclaw/fs-safe/dist/file-store.js +4 -10
  57. package/node_modules/@openclaw/fs-safe/dist/fs.d.ts +2 -10
  58. package/node_modules/@openclaw/fs-safe/dist/fs.js +2 -10
  59. package/node_modules/@openclaw/fs-safe/dist/guarded-mkdir.d.ts +3 -4
  60. package/node_modules/@openclaw/fs-safe/dist/guarded-mkdir.js +6 -18
  61. package/node_modules/@openclaw/fs-safe/dist/guest-dispatch-python.js +1 -1
  62. package/node_modules/@openclaw/fs-safe/dist/guest-native-python.js +0 -2
  63. package/node_modules/@openclaw/fs-safe/dist/guest.js +3 -9
  64. package/node_modules/@openclaw/fs-safe/dist/index.d.ts +1 -1
  65. package/node_modules/@openclaw/fs-safe/dist/index.js +1 -1
  66. package/node_modules/@openclaw/fs-safe/dist/json-durable-queue-directory.js +1 -5
  67. package/node_modules/@openclaw/fs-safe/dist/json.js +19 -37
  68. package/node_modules/@openclaw/fs-safe/dist/move-path.js +2 -0
  69. package/node_modules/@openclaw/fs-safe/dist/mutation-authority.d.ts +1 -0
  70. package/node_modules/@openclaw/fs-safe/dist/mutation-authority.js +9 -1
  71. package/node_modules/@openclaw/fs-safe/dist/native-binding.d.ts +47 -2
  72. package/node_modules/@openclaw/fs-safe/dist/native-config.d.ts +1 -9
  73. package/node_modules/@openclaw/fs-safe/dist/native-config.js +6 -40
  74. package/node_modules/@openclaw/fs-safe/dist/native-parent-admission.d.ts +2 -0
  75. package/node_modules/@openclaw/fs-safe/dist/native-parent-admission.js +5 -2
  76. package/node_modules/@openclaw/fs-safe/dist/native-pinned-write.js +11 -316
  77. package/node_modules/@openclaw/fs-safe/dist/native-policy-parent-windows.d.ts +7 -7
  78. package/node_modules/@openclaw/fs-safe/dist/native-policy-parent-windows.js +28 -175
  79. package/node_modules/@openclaw/fs-safe/dist/native-policy-parent.d.ts +15 -0
  80. package/node_modules/@openclaw/fs-safe/dist/native-policy-parent.js +418 -0
  81. package/node_modules/@openclaw/fs-safe/dist/native-rename-outcome.js +9 -4
  82. package/node_modules/@openclaw/fs-safe/dist/native-staged-file.js +17 -13
  83. package/node_modules/@openclaw/fs-safe/dist/native-staged-symlink.js +6 -24
  84. package/node_modules/@openclaw/fs-safe/dist/native.js +5 -1
  85. package/node_modules/@openclaw/fs-safe/dist/path-case.js +10 -9
  86. package/node_modules/@openclaw/fs-safe/dist/path-scope-lexical.js +4 -1
  87. package/node_modules/@openclaw/fs-safe/dist/path-segment-route.d.ts +1 -0
  88. package/node_modules/@openclaw/fs-safe/dist/path-segment-route.js +3 -0
  89. package/node_modules/@openclaw/fs-safe/dist/path.js +4 -1
  90. package/node_modules/@openclaw/fs-safe/dist/permissions-windows.d.ts +0 -1
  91. package/node_modules/@openclaw/fs-safe/dist/pinned-mutation-admission.js +1 -3
  92. package/node_modules/@openclaw/fs-safe/dist/pinned-write-staged.js +2 -0
  93. package/node_modules/@openclaw/fs-safe/dist/pinned-write.js +9 -10
  94. package/node_modules/@openclaw/fs-safe/dist/private-producer-handoff.js +3 -6
  95. package/node_modules/@openclaw/fs-safe/dist/publish-copy-stage.js +2 -2
  96. package/node_modules/@openclaw/fs-safe/dist/publish-file.js +4 -3
  97. package/node_modules/@openclaw/fs-safe/dist/replace-file-buffer.d.ts +3 -4
  98. package/node_modules/@openclaw/fs-safe/dist/replace-file-buffer.js +18 -32
  99. package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-fallback.d.ts +5 -17
  100. package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-fallback.js +92 -230
  101. package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-source.d.ts +4 -15
  102. package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-source.js +22 -63
  103. package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.d.ts +9 -34
  104. package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.js +78 -83
  105. package/node_modules/@openclaw/fs-safe/dist/replace-file-destination.d.ts +18 -20
  106. package/node_modules/@openclaw/fs-safe/dist/replace-file-destination.js +64 -98
  107. package/node_modules/@openclaw/fs-safe/dist/replace-file-temp-owner.d.ts +16 -33
  108. package/node_modules/@openclaw/fs-safe/dist/replace-file-temp-owner.js +61 -200
  109. package/node_modules/@openclaw/fs-safe/dist/replace-file-types.d.ts +1 -6
  110. package/node_modules/@openclaw/fs-safe/dist/replace-file.js +76 -216
  111. package/node_modules/@openclaw/fs-safe/dist/root-boundary.js +14 -24
  112. package/node_modules/@openclaw/fs-safe/dist/root-context.d.ts +1 -4
  113. package/node_modules/@openclaw/fs-safe/dist/root-context.js +4 -19
  114. package/node_modules/@openclaw/fs-safe/dist/root-create-native.d.ts +52 -0
  115. package/node_modules/@openclaw/fs-safe/dist/root-create-native.js +350 -0
  116. package/node_modules/@openclaw/fs-safe/dist/root-directory-list-types.d.ts +35 -0
  117. package/node_modules/@openclaw/fs-safe/dist/root-directory-list-types.js +1 -0
  118. package/node_modules/@openclaw/fs-safe/dist/root-directory-list.d.ts +2 -27
  119. package/node_modules/@openclaw/fs-safe/dist/root-directory-list.js +31 -28
  120. package/node_modules/@openclaw/fs-safe/dist/root-directory.js +1 -4
  121. package/node_modules/@openclaw/fs-safe/dist/root-errors.js +34 -0
  122. package/node_modules/@openclaw/fs-safe/dist/root-file.js +9 -21
  123. package/node_modules/@openclaw/fs-safe/dist/root-impl.js +105 -37
  124. package/node_modules/@openclaw/fs-safe/dist/root-move-noreplace.d.ts +7 -2
  125. package/node_modules/@openclaw/fs-safe/dist/root-move-noreplace.js +67 -38
  126. package/node_modules/@openclaw/fs-safe/dist/root-observed-path.d.ts +1 -1
  127. package/node_modules/@openclaw/fs-safe/dist/root-observed-path.js +0 -2
  128. package/node_modules/@openclaw/fs-safe/dist/root-options.d.ts +2 -3
  129. package/node_modules/@openclaw/fs-safe/dist/root-path-existing.js +3 -1
  130. package/node_modules/@openclaw/fs-safe/dist/root-path-stat.js +68 -85
  131. package/node_modules/@openclaw/fs-safe/dist/root-path.js +6 -1
  132. package/node_modules/@openclaw/fs-safe/dist/root-paths-lexical.d.ts +4 -0
  133. package/node_modules/@openclaw/fs-safe/dist/root-paths-lexical.js +1 -1
  134. package/node_modules/@openclaw/fs-safe/dist/root-paths.js +4 -9
  135. package/node_modules/@openclaw/fs-safe/dist/root-remove-native.d.ts +4 -0
  136. package/node_modules/@openclaw/fs-safe/dist/root-remove-native.js +311 -0
  137. package/node_modules/@openclaw/fs-safe/dist/root-remove.d.ts +11 -0
  138. package/node_modules/@openclaw/fs-safe/dist/root-remove.js +3 -1
  139. package/node_modules/@openclaw/fs-safe/dist/root-walk.d.ts +2 -2
  140. package/node_modules/@openclaw/fs-safe/dist/root-walk.js +1 -3
  141. package/node_modules/@openclaw/fs-safe/dist/root-write-admission.d.ts +3 -3
  142. package/node_modules/@openclaw/fs-safe/dist/root-write-admission.js +8 -10
  143. package/node_modules/@openclaw/fs-safe/dist/safe-path-segment.d.ts +0 -1
  144. package/node_modules/@openclaw/fs-safe/dist/safe-path-segment.js +0 -4
  145. package/node_modules/@openclaw/fs-safe/dist/secret-file.js +12 -9
  146. package/node_modules/@openclaw/fs-safe/dist/secure-temp-dir.d.ts +0 -2
  147. package/node_modules/@openclaw/fs-safe/dist/sibling-staged-file.js +2 -0
  148. package/node_modules/@openclaw/fs-safe/dist/sibling-temp.js +7 -4
  149. package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-acquire.js +13 -6
  150. package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.d.ts +0 -3
  151. package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.js +5 -23
  152. package/node_modules/@openclaw/fs-safe/dist/staged-file-settlement.d.ts +2 -1
  153. package/node_modules/@openclaw/fs-safe/dist/staged-file-settlement.js +11 -6
  154. package/node_modules/@openclaw/fs-safe/dist/temp-cleanup.js +1 -8
  155. package/node_modules/@openclaw/fs-safe/dist/temp-workspace-child-admission.d.ts +1 -1
  156. package/node_modules/@openclaw/fs-safe/dist/temp-workspace-child-admission.js +2 -9
  157. package/node_modules/@openclaw/fs-safe/dist/text-atomic.d.ts +1 -6
  158. package/node_modules/@openclaw/fs-safe/dist/trash.js +6 -2
  159. package/node_modules/@openclaw/fs-safe/dist/walk.js +100 -46
  160. package/node_modules/@openclaw/fs-safe/dist/watch-hints.d.ts +7 -0
  161. package/node_modules/@openclaw/fs-safe/dist/watch-hints.js +235 -19
  162. package/node_modules/@openclaw/fs-safe/dist/watch-native.d.ts +21 -2
  163. package/node_modules/@openclaw/fs-safe/dist/watch-native.js +21 -3
  164. package/node_modules/@openclaw/fs-safe/dist/watch-rescan.d.ts +6 -0
  165. package/node_modules/@openclaw/fs-safe/dist/watch-rescan.js +111 -0
  166. package/node_modules/@openclaw/fs-safe/dist/watch-scan.d.ts +13 -0
  167. package/node_modules/@openclaw/fs-safe/dist/watch-scan.js +27 -4
  168. package/node_modules/@openclaw/fs-safe/dist/watch-stream.js +2 -0
  169. package/node_modules/@openclaw/fs-safe/dist/watch.js +131 -40
  170. package/node_modules/@openclaw/fs-safe/dist/windows-path-alias.d.ts +8 -0
  171. package/node_modules/@openclaw/fs-safe/dist/windows-path-alias.js +24 -6
  172. package/node_modules/@openclaw/fs-safe/dist/windows-path-syntax.d.ts +13 -0
  173. package/node_modules/@openclaw/fs-safe/dist/windows-path-syntax.js +51 -0
  174. package/node_modules/@openclaw/fs-safe/docs/advanced.md +4 -0
  175. package/node_modules/@openclaw/fs-safe/docs/atomic.md +4 -1
  176. package/node_modules/@openclaw/fs-safe/docs/config.md +6 -14
  177. package/node_modules/@openclaw/fs-safe/docs/contributing.md +4 -14
  178. package/node_modules/@openclaw/fs-safe/docs/durability.md +6 -29
  179. package/node_modules/@openclaw/fs-safe/docs/entry-publication.md +146 -0
  180. package/node_modules/@openclaw/fs-safe/docs/errors.md +16 -0
  181. package/node_modules/@openclaw/fs-safe/docs/file-store.md +28 -5
  182. package/node_modules/@openclaw/fs-safe/docs/index.md +2 -31
  183. package/node_modules/@openclaw/fs-safe/docs/install.md +10 -31
  184. package/node_modules/@openclaw/fs-safe/docs/json.md +1 -1
  185. package/node_modules/@openclaw/fs-safe/docs/local-roots.md +0 -1
  186. package/node_modules/@openclaw/fs-safe/docs/migrating-to-0.5.md +12 -12
  187. package/node_modules/@openclaw/fs-safe/docs/native-helper.md +35 -96
  188. package/node_modules/@openclaw/fs-safe/docs/native.md +22 -20
  189. package/node_modules/@openclaw/fs-safe/docs/path.md +1 -1
  190. package/node_modules/@openclaw/fs-safe/docs/permissions.md +1 -2
  191. package/node_modules/@openclaw/fs-safe/docs/public-api.md +1 -2
  192. package/node_modules/@openclaw/fs-safe/docs/reading.md +1 -2
  193. package/node_modules/@openclaw/fs-safe/docs/root.md +26 -184
  194. package/node_modules/@openclaw/fs-safe/docs/secret-file.md +1 -1
  195. package/node_modules/@openclaw/fs-safe/docs/security-model.md +115 -3
  196. package/node_modules/@openclaw/fs-safe/docs/store.md +2 -2
  197. package/node_modules/@openclaw/fs-safe/docs/temp.md +29 -65
  198. package/node_modules/@openclaw/fs-safe/docs/testing.md +90 -58
  199. package/node_modules/@openclaw/fs-safe/docs/types.md +3 -16
  200. package/node_modules/@openclaw/fs-safe/docs/walk.md +33 -5
  201. package/node_modules/@openclaw/fs-safe/docs/watch.md +96 -14
  202. package/node_modules/@openclaw/fs-safe/docs/writing.md +172 -16
  203. package/node_modules/@openclaw/fs-safe/package.json +10 -10
  204. package/node_modules/@openclaw/fs-safe-darwin-arm64/fs-safe-native.node +0 -0
  205. package/node_modules/@openclaw/fs-safe-darwin-arm64/package.json +1 -1
  206. package/node_modules/@openclaw/fs-safe-darwin-x64/fs-safe-native.node +0 -0
  207. package/node_modules/@openclaw/fs-safe-darwin-x64/package.json +1 -1
  208. package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/fs-safe-native.node +0 -0
  209. package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/package.json +1 -1
  210. package/node_modules/@openclaw/fs-safe-linux-arm64-musl/fs-safe-native.node +0 -0
  211. package/node_modules/@openclaw/fs-safe-linux-arm64-musl/package.json +1 -1
  212. package/node_modules/@openclaw/fs-safe-linux-x64-gnu/fs-safe-native.node +0 -0
  213. package/node_modules/@openclaw/fs-safe-linux-x64-gnu/package.json +1 -1
  214. package/node_modules/@openclaw/fs-safe-linux-x64-musl/fs-safe-native.node +0 -0
  215. package/node_modules/@openclaw/fs-safe-linux-x64-musl/package.json +1 -1
  216. package/node_modules/@openclaw/fs-safe-win32-x64-msvc/fs-safe-native.node +0 -0
  217. package/node_modules/@openclaw/fs-safe-win32-x64-msvc/package.json +1 -1
  218. package/package.json +5 -5
  219. package/skills/feishu-wiki/SKILL.md +1 -1
  220. package/dist/.setup/accounts-wRqItHug.mjs +0 -206
  221. package/node_modules/@openclaw/fs-safe/dist/watch-alias.d.ts +0 -6
  222. package/node_modules/@openclaw/fs-safe/dist/watch-alias.js +0 -88
  223. package/node_modules/@openclaw/fs-safe/docs/mutation-policy-proof.md +0 -69
  224. package/node_modules/@openclaw/fs-safe/docs/private-file-store.md +0 -68
  225. package/node_modules/@openclaw/fs-safe/docs/test-hooks.md +0 -110
@@ -1,28 +1,21 @@
1
1
  import fsSync, {} from "node:fs";
2
- import path from "node:path";
3
- import { assertDirectoryIdentitySync, inspectDirectoryIdentitySync, } from "./directory-guard.js";
2
+ import { assertDirectoryIdentitySync, } from "./directory-guard.js";
4
3
  import { FsSafeError } from "./errors.js";
5
4
  import { openNativeParentAdmission } from "./native-parent-admission.js";
6
- import { captureNativeFdClose } from "./native-binding.js";
7
5
  import { inspectNativeDirectoryObservation } from "./native-directory-observation.js";
8
- import { createPathSegmentRoute, joinPathSegmentRoute } from "./path-segment-route.js";
9
6
  import { isSymlinkOpenError } from "./path.js";
10
7
  import { checkedMutationDirectory } from "./pinned-mutation-observation.js";
11
- import { canReuseParentWithMutationAssertion } from "./root-write-lock-binding.js";
12
8
  import { inspectFileIdentitySync } from "./strict-file-identity.js";
13
9
  import { createSuppressedError } from "./suppressed-error.js";
14
- function assertParentCurrent(parent) {
15
- const current = inspectFileIdentitySync(() => fsSync.fstatSync(parent.fd, { bigint: true }), parent.guard.stat);
10
+ export function assertWindowsPolicyParentCurrent(parent) {
11
+ inspectFileIdentitySync(() => fsSync.fstatSync(parent.fd, { bigint: true }), parent.guard.stat);
16
12
  assertDirectoryIdentitySync(parent.guard.dir, {
17
13
  dev: parent.guard.stat.dev,
18
14
  ino: parent.guard.stat.ino,
19
15
  realPath: parent.guard.realPath,
20
16
  });
21
- return current;
22
17
  }
23
- function closeAfterFailure(closeFd, fd, failure, report = false) {
24
- if (fd === undefined)
25
- return;
18
+ export function closeWindowsPolicyParentAfterFailure(closeFd, fd, failure, report = false) {
26
19
  try {
27
20
  closeFd(fd);
28
21
  }
@@ -33,177 +26,37 @@ function closeAfterFailure(closeFd, fd, failure, report = false) {
33
26
  : error;
34
27
  }
35
28
  }
36
- export async function capturePolicyAwareWindowsParent(binding, params, rootAdmission) {
37
- const closeFd = captureNativeFdClose(binding);
38
- let session;
39
- function parentObservation(fd, guard) {
40
- return checkedMutationDirectory(guard.dir, guard.realPath, guard.stat, typeof binding.observeDirectory === "function" ? () => {
41
- const stat = inspectFileIdentitySync(() => fsSync.fstatSync(fd, { bigint: true }), guard.stat);
42
- let observed;
43
- try {
44
- observed = inspectNativeDirectoryObservation(binding, guard.dir, stat);
45
- }
46
- catch (error) {
47
- if (error?.code === "OBSERVATION_UNAVAILABLE")
48
- return undefined;
49
- throw error;
50
- }
51
- return { canonicalPath: observed.realPath,
52
- identity: { dev: stat.dev, ino: stat.ino, mode: stat.mode, nlink: stat.nlink } };
53
- } : undefined);
54
- }
55
- async function openParent(fd, parentPath, relativePath) {
56
- try {
57
- const admitted = await openNativeParentAdmission(binding, {
58
- ...rootAdmission,
59
- root: { fd },
60
- rootPath: parentPath,
61
- // Policy fences retain every identity bit even with a legacy numeric root.
62
- exactRoot: true,
63
- }, relativePath, "native-directory");
64
- const guard = { ...admitted.guard, stat: admitted.guard.stat };
65
- return { fd: admitted.fd, guard, observation: parentObservation(admitted.fd, guard) };
66
- }
67
- catch (error) {
68
- if (!isSymlinkOpenError(error))
69
- throw error;
70
- throw new FsSafeError(params.mutationAdmission.rejectParentSymlinks ? "symlink" : "path-mismatch", "native write parent changed during policy admission", { cause: error instanceof Error ? error : undefined });
71
- }
72
- }
73
- async function authorize(targetPath, mutationPath = targetPath, phase = "parent") {
74
- const request = Object.freeze({ targetPath, mutationPath, phase });
75
- return await (session ? session.authorize(request) : params.mutationAdmission.authorize(request));
76
- }
77
- // Existing complete parents need one open and one target admission. Exact
78
- // parent denies apply only to creation, never to merely using a directory.
79
- let complete;
80
- try {
81
- complete = await openParent(rootAdmission.root.fd, params.rootPath, params.relativeParentPath);
82
- }
83
- catch (error) {
84
- if (error?.code !== "ENOENT" || !params.mkdir)
85
- throw error;
86
- }
87
- if (complete) {
29
+ export function windowsParentObservation(binding, fd, guard) {
30
+ return checkedMutationDirectory(guard.dir, guard.realPath, guard.stat, typeof binding.observeDirectory === "function" ? () => {
31
+ const stat = inspectFileIdentitySync(() => fsSync.fstatSync(fd, { bigint: true }), guard.stat);
32
+ let observed;
88
33
  try {
89
- await authorize(path.join(complete.guard.realPath, params.basename));
90
- assertParentCurrent(complete);
91
- return complete;
34
+ observed = inspectNativeDirectoryObservation(binding, guard.dir, stat);
92
35
  }
93
36
  catch (error) {
94
- closeAfterFailure(closeFd, complete.fd, { error }, rootAdmission.reportCloseErrors);
37
+ if (error?.code === "OBSERVATION_UNAVAILABLE")
38
+ return undefined;
95
39
  throw error;
96
40
  }
97
- }
98
- const segments = params.relativeParentPath.split("/").filter(Boolean);
99
- const route = createPathSegmentRoute(segments);
100
- const rootStat = inspectDirectoryIdentitySync(params.rootPath, inspectFileIdentitySync(() => fsSync.fstatSync(rootAdmission.root.fd, { bigint: true })));
101
- let current = {
102
- fd: rootAdmission.root.fd,
103
- guard: { dir: params.rootPath, realPath: params.rootPath, stat: rootStat },
104
- observation: parentObservation(rootAdmission.root.fd, {
105
- dir: params.rootPath, realPath: params.rootPath, stat: rootStat,
106
- }),
107
- };
108
- let ownedFd;
109
- let failure;
110
- const initialTarget = joinPathSegmentRoute(params.rootPath, route, 0, params.basename);
111
- if (canReuseParentWithMutationAssertion(params.assertBeforeMutation, params.rootPath, initialTarget)) {
112
- session = params.mutationAdmission?.beginNativeParentWalk?.() ??
113
- params.mutationAdmission?.beginSharedParentWalk?.();
114
- if (session && session.retainedTargetPath !== initialTarget) {
115
- session.dispose();
116
- session = undefined;
117
- }
118
- }
41
+ return { canonicalPath: observed.realPath,
42
+ identity: { dev: stat.dev, ino: stat.ino, mode: stat.mode, nlink: stat.nlink } };
43
+ } : undefined);
44
+ }
45
+ export async function openWindowsPolicyParent(binding, params, rootAdmission, fd, parentPath, relativePath) {
119
46
  try {
120
- for (let index = 0; index < segments.length; index += 1) {
121
- const segment = segments[index];
122
- const parentPath = current.guard.realPath;
123
- let child;
124
- let createdByMkdir = false;
125
- let createReceipt;
126
- try {
127
- child = await openParent(current.fd, parentPath, segment);
128
- }
129
- catch (error) {
130
- if (error?.code !== "ENOENT")
131
- throw error;
132
- // The request admits both the prospective leaf and this missing direct
133
- // child. A deeper denial can leave already admitted ancestors intact.
134
- const targetPath = session?.retainedTargetPath ??
135
- joinPathSegmentRoute(parentPath, route, index, params.basename);
136
- const mutationPath = path.join(parentPath, segment);
137
- const request = Object.freeze({ targetPath, mutationPath, phase: "parent-create" });
138
- createReceipt = session?.tryAuthorizeAtParent(request, current.observation);
139
- if (!createReceipt) {
140
- createReceipt = await authorize(targetPath, mutationPath, "parent-create");
141
- assertParentCurrent(current);
142
- }
143
- if (params.assertBeforeMutation) {
144
- // Opaque callbacks retain their post-callback descriptor/path fence.
145
- params.assertBeforeMutation();
146
- assertParentCurrent(current);
147
- }
148
- // Synchronous session admission already ends at the exact parent fence.
149
- const mkdirChild = binding.mkdirChildBeneath;
150
- if (typeof mkdirChild !== "function") {
151
- throw new FsSafeError("helper-unavailable", "native direct-child parent creation is unavailable");
152
- }
153
- createdByMkdir = mkdirChild.call(binding, current.fd, segment, 0o777) === true;
154
- child = await openParent(current.fd, parentPath, segment);
155
- }
156
- try {
157
- const targetPath = joinPathSegmentRoute(child.guard.realPath, route, index + 1, params.basename);
158
- if (session && targetPath !== session.retainedTargetPath) {
159
- session.dispose();
160
- session = undefined;
161
- }
162
- let evidence;
163
- if (session && createdByMkdir && createReceipt) {
164
- try {
165
- evidence = Object.freeze({
166
- admission: createReceipt,
167
- parent: parentObservation(current.fd, { ...current.guard,
168
- stat: inspectFileIdentitySync(() => fsSync.fstatSync(current.fd, { bigint: true }), current.guard.stat),
169
- }),
170
- child: child.observation,
171
- });
172
- }
173
- catch {
174
- // Incomplete optional evidence returns to ordered admission below.
175
- }
176
- }
177
- // Advancement refreshes both named directories after all Root/policy
178
- // observations; these receipts supply expectations, not cached authority.
179
- const advanced = evidence && session.advanceCreatedDirectory(evidence);
180
- if (!advanced) {
181
- await authorize(targetPath);
182
- assertParentCurrent(child);
183
- }
184
- }
185
- catch (error) {
186
- closeAfterFailure(closeFd, child.fd, { error }, rootAdmission.reportCloseErrors);
187
- throw error;
188
- }
189
- const previousFd = ownedFd;
190
- current = child;
191
- ownedFd = child.fd;
192
- if (previousFd !== undefined)
193
- closeFd(previousFd);
194
- }
195
- if (ownedFd === undefined) {
196
- throw new FsSafeError("path-mismatch", "native write parent admission did not complete");
197
- }
198
- ownedFd = undefined;
199
- return current;
47
+ const admitted = await openNativeParentAdmission(binding, {
48
+ ...rootAdmission,
49
+ root: { fd },
50
+ rootPath: parentPath,
51
+ // Policy fences retain every identity bit even with a legacy numeric root.
52
+ exactRoot: true,
53
+ }, relativePath, "native-directory");
54
+ const guard = { ...admitted.guard, stat: admitted.guard.stat };
55
+ return { fd: admitted.fd, guard, observation: windowsParentObservation(binding, admitted.fd, guard) };
200
56
  }
201
57
  catch (error) {
202
- failure = { error };
203
- throw error;
204
- }
205
- finally {
206
- session?.dispose();
207
- closeAfterFailure(closeFd, ownedFd, failure, rootAdmission.reportCloseErrors);
58
+ if (!isSymlinkOpenError(error))
59
+ throw error;
60
+ throw new FsSafeError(params.mutationAdmission.rejectParentSymlinks ? "symlink" : "path-mismatch", "native write parent changed during policy admission", { cause: error instanceof Error ? error : undefined });
208
61
  }
209
62
  }
@@ -0,0 +1,15 @@
1
+ import { type BigIntStats } from "node:fs";
2
+ import { type AsyncDirectoryGuard } from "./directory-guard.js";
3
+ import type { NativeBinding } from "./native.js";
4
+ import type { NativeRootAdmission } from "./native-parent-admission.js";
5
+ import type { PinnedWriteParams } from "./pinned-write-types.js";
6
+ import { describeStagedDirectory, type PolicyStagedDirectory } from "./staged-directory.js";
7
+ import { type MutationDirectoryObservation } from "./pinned-mutation-observation.js";
8
+ export type NativePolicyParent = {
9
+ fd: number;
10
+ guard: AsyncDirectoryGuard<BigIntStats>;
11
+ observation: MutationDirectoryObservation;
12
+ stagedDirectory?: ReturnType<typeof describeStagedDirectory>;
13
+ policyDirectory?: PolicyStagedDirectory;
14
+ };
15
+ export declare function capturePolicyAwareNativeParent(binding: NativeBinding, params: PinnedWriteParams, rootAdmission: NativeRootAdmission, windows: boolean, directoryFlags: number, fuseChildCreation?: boolean): Promise<NativePolicyParent>;
@@ -0,0 +1,418 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
53
+ import fsSync, {} from "node:fs";
54
+ import path from "node:path";
55
+ import { inspectDirectoryIdentity, inspectDirectoryIdentitySync, } from "./directory-guard.js";
56
+ import { FsSafeError } from "./errors.js";
57
+ import { captureNativeFdClose } from "./native-binding.js";
58
+ import { NativePolicyDirectoryMismatch } from "./native-policy-directory-observation.js";
59
+ import { assertWindowsPolicyParentCurrent, closeWindowsPolicyParentAfterFailure, openWindowsPolicyParent, windowsParentObservation, } from "./native-policy-parent-windows.js";
60
+ import { assertPolicyStagedDirectoryCurrent, assertStagedDirectoryCurrent, describePolicyStagedDirectory, describeStagedDirectory, refreshPolicyStagedDirectoryObservation, } from "./staged-directory.js";
61
+ import { inspectFileIdentitySync } from "./strict-file-identity.js";
62
+ import { realpathSync } from "./realpath.js";
63
+ import { errorCauseOptions } from "./root-errors.js";
64
+ import { isNotFoundPathError, isSymlinkOpenError } from "./path.js";
65
+ import { checkedMutationDirectory, } from "./pinned-mutation-observation.js";
66
+ import { createPathSegmentRoute, joinPathSegmentRoute, sameAbsolutePath } from "./path-segment-route.js";
67
+ import { canReuseParentWithMutationAssertion } from "./root-write-lock-binding.js";
68
+ function mkdirPosixPolicyChild(binding, parentFd, basename) {
69
+ if (!basename || basename === "." || basename === ".." || basename.includes("/") ||
70
+ basename.includes("\0") || (process.platform === "win32" && basename.includes("\\"))) {
71
+ throw new FsSafeError("invalid-path", "native parent creation requires one direct-child basename");
72
+ }
73
+ const mkdirChild = binding.mkdirChildBeneath;
74
+ if (typeof mkdirChild === "function") {
75
+ const created = mkdirChild.call(binding, parentFd, basename, 0o777);
76
+ if (typeof created === "boolean")
77
+ return created;
78
+ }
79
+ binding.mkdirBeneath(parentFd, basename, 0o777);
80
+ return false;
81
+ }
82
+ function normalizePosixParentOpenError(error, params) {
83
+ if (!isSymlinkOpenError(error))
84
+ return error;
85
+ return params.mutationAdmission?.rejectParentSymlinks
86
+ ? new FsSafeError("symlink", "symlink path component not allowed", errorCauseOptions(error))
87
+ : new FsSafeError("path-mismatch", "native write parent changed during policy admission", errorCauseOptions(error));
88
+ }
89
+ async function describePosixParent(fd, pathname) {
90
+ const parentPath = realpathSync.native(pathname);
91
+ const stagedDirectory = describeStagedDirectory(fd, parentPath);
92
+ const stat = await inspectDirectoryIdentity(parentPath, stagedDirectory.identity);
93
+ return {
94
+ fd,
95
+ guard: { dir: parentPath, realPath: parentPath, stat },
96
+ stagedDirectory,
97
+ observation: checkedMutationDirectory(parentPath, stagedDirectory.realPath, stat),
98
+ };
99
+ }
100
+ function tryDescribePolicyPosixParent(binding, fd, pathname) {
101
+ try {
102
+ const policyDirectory = describePolicyStagedDirectory(fd, pathname, binding);
103
+ return {
104
+ fd,
105
+ guard: {
106
+ dir: policyDirectory.directory.realPath,
107
+ realPath: policyDirectory.directory.realPath,
108
+ stat: policyDirectory.stat,
109
+ },
110
+ stagedDirectory: policyDirectory.directory,
111
+ observation: policyDirectory.observation,
112
+ policyDirectory,
113
+ };
114
+ }
115
+ catch (error) {
116
+ if (!(error instanceof FsSafeError) || error instanceof NativePolicyDirectoryMismatch ||
117
+ (error.code !== "path-mismatch" && error.code !== "not-file"))
118
+ throw error;
119
+ return undefined;
120
+ }
121
+ }
122
+ export async function capturePolicyAwareNativeParent(binding, params, rootAdmission, windows, directoryFlags, fuseChildCreation = false) {
123
+ const env_1 = { stack: [], error: void 0, hasError: false };
124
+ try {
125
+ const rootFd = rootAdmission.root.fd;
126
+ const closeFd = captureNativeFdClose(binding);
127
+ const observationDisposers = windows ? undefined : new Map();
128
+ const disposeObservation = (fd) => {
129
+ const dispose = observationDisposers?.get(fd);
130
+ observationDisposers?.delete(fd);
131
+ dispose?.();
132
+ };
133
+ const observationScope = __addDisposableResource(env_1, {
134
+ [Symbol.dispose]() { for (const dispose of observationDisposers?.values() ?? [])
135
+ dispose(); },
136
+ }, false);
137
+ const capturePolicyParent = (fd, pathname) => {
138
+ const captured = tryDescribePolicyPosixParent(binding, fd, pathname);
139
+ const dispose = captured?.policyDirectory?.disposeObservation;
140
+ if (dispose)
141
+ observationDisposers.set(fd, dispose);
142
+ return captured;
143
+ };
144
+ const assertCurrent = (parent) => windows
145
+ ? assertWindowsPolicyParentCurrent(parent)
146
+ : parent.policyDirectory
147
+ ? assertPolicyStagedDirectoryCurrent(parent.policyDirectory)
148
+ : assertStagedDirectoryCurrent(parent.stagedDirectory);
149
+ const closeAfterFailure = (fd, failure) => {
150
+ disposeObservation(fd);
151
+ if (windows)
152
+ closeWindowsPolicyParentAfterFailure(closeFd, fd, failure, rootAdmission.reportCloseErrors);
153
+ else
154
+ closeFd(fd);
155
+ };
156
+ let session;
157
+ async function authorize(request) {
158
+ const frozen = Object.freeze(request);
159
+ return await (session ? session.authorize(frozen) : windows
160
+ ? params.mutationAdmission.authorize(frozen)
161
+ : params.mutationAdmission?.authorize(frozen));
162
+ }
163
+ // POSIX begins its retained observation before the complete-parent open;
164
+ // Windows starts a walk session only after that fast path misses.
165
+ let segments = windows ? undefined : params.relativeParentPath.split("/").filter(Boolean);
166
+ let route = segments && createPathSegmentRoute(segments);
167
+ let initialTarget = route && joinPathSegmentRoute(params.rootPath, route, 0, params.basename);
168
+ const parentSpelling = segments?.length ? path.join(params.rootPath, ...segments) : params.rootPath;
169
+ let retainedTargetPath = windows ? undefined : params.mutationAdmission?.beginParentWalk?.();
170
+ if (retainedTargetPath && !sameAbsolutePath(retainedTargetPath, initialTarget)) {
171
+ retainedTargetPath = undefined;
172
+ }
173
+ let complete;
174
+ let completeFd;
175
+ try {
176
+ if (windows) {
177
+ complete = await openWindowsPolicyParent(binding, params, rootAdmission, rootFd, params.rootPath, params.relativeParentPath);
178
+ completeFd = complete.fd;
179
+ }
180
+ else {
181
+ completeFd = binding.openBeneath(rootFd, params.relativeParentPath, directoryFlags).fd;
182
+ }
183
+ }
184
+ catch (error) {
185
+ if (error?.code !== "ENOENT" || !params.mkdir) {
186
+ if (windows)
187
+ throw error;
188
+ await authorize({ targetPath: initialTarget, mutationPath: initialTarget, phase: "parent" });
189
+ throw normalizePosixParentOpenError(error, params);
190
+ }
191
+ }
192
+ if (completeFd !== undefined) {
193
+ try {
194
+ complete ??= retainedTargetPath ? capturePolicyParent(completeFd, parentSpelling) : undefined;
195
+ if (!complete) {
196
+ retainedTargetPath = undefined;
197
+ complete = await describePosixParent(completeFd, parentSpelling);
198
+ }
199
+ const targetPath = path.join(complete.guard.realPath, params.basename);
200
+ await authorize({ targetPath, mutationPath: targetPath, phase: "parent" });
201
+ assertCurrent(complete);
202
+ return complete;
203
+ }
204
+ catch (error) {
205
+ closeAfterFailure(completeFd, { error });
206
+ throw error;
207
+ }
208
+ }
209
+ segments ??= params.relativeParentPath.split("/").filter(Boolean);
210
+ route ??= createPathSegmentRoute(segments);
211
+ let current;
212
+ if (windows) {
213
+ const rootStat = inspectDirectoryIdentitySync(params.rootPath, inspectFileIdentitySync(() => fsSync.fstatSync(rootFd, { bigint: true })));
214
+ const guard = { dir: params.rootPath, realPath: params.rootPath, stat: rootStat };
215
+ current = { fd: rootFd, guard, observation: windowsParentObservation(binding, rootFd, guard) };
216
+ }
217
+ else {
218
+ const captured = retainedTargetPath ? capturePolicyParent(rootFd, params.rootPath) : undefined;
219
+ if (!captured)
220
+ retainedTargetPath = undefined;
221
+ current = captured ?? await describePosixParent(rootFd, params.rootPath);
222
+ }
223
+ let ownedFd;
224
+ let currentPath = params.rootPath;
225
+ let failure;
226
+ initialTarget ??= joinPathSegmentRoute(params.rootPath, route, 0, params.basename);
227
+ if (windows && canReuseParentWithMutationAssertion(params.assertBeforeMutation, params.rootPath, initialTarget)) {
228
+ session = params.mutationAdmission?.beginNativeParentWalk?.() ?? params.mutationAdmission?.beginSharedParentWalk?.();
229
+ if (session && session.retainedTargetPath !== initialTarget) {
230
+ session.dispose();
231
+ session = undefined;
232
+ }
233
+ }
234
+ const secureDirectoryFlags = directoryFlags | (fsSync.constants.O_NOFOLLOW ?? 0);
235
+ try {
236
+ if (!windows) {
237
+ const targetPath = retainedTargetPath ?? initialTarget;
238
+ await authorize({ targetPath, mutationPath: targetPath, phase: "parent" });
239
+ assertCurrent(current);
240
+ }
241
+ for (let index = 0; index < segments.length; index += 1) {
242
+ const segment = segments[index];
243
+ let childPath = windows ? undefined : path.join(currentPath, segment);
244
+ let child;
245
+ let childFd;
246
+ let createdByMkdir = false;
247
+ let createReceipt;
248
+ try {
249
+ if (windows) {
250
+ child = await openWindowsPolicyParent(binding, params, rootAdmission, current.fd, currentPath, segment);
251
+ childFd = child.fd;
252
+ }
253
+ else {
254
+ childFd = binding.openBeneath(current.fd, segment, secureDirectoryFlags).fd;
255
+ }
256
+ }
257
+ catch (error) {
258
+ const missing = windows
259
+ ? error?.code === "ENOENT"
260
+ : isNotFoundPathError(error);
261
+ if (!missing)
262
+ throw windows ? error : normalizePosixParentOpenError(error, params);
263
+ const targetPath = (windows ? session?.retainedTargetPath : retainedTargetPath) ??
264
+ joinPathSegmentRoute(currentPath, route, index, params.basename);
265
+ childPath ??= path.join(currentPath, segment);
266
+ const request = Object.freeze({
267
+ targetPath, mutationPath: childPath, phase: "parent-create",
268
+ });
269
+ createReceipt = windows
270
+ ? session?.tryAuthorizeAtParent(request, current.observation)
271
+ : params.mutationAdmission?.tryAuthorizeAtParent?.(request, current.observation);
272
+ if (!createReceipt) {
273
+ createReceipt = await authorize(windows ? { ...request } : request);
274
+ assertCurrent(current);
275
+ }
276
+ // POSIX always refreshes here; Windows refreshes only after a live callback.
277
+ if (windows) {
278
+ if (params.assertBeforeMutation) {
279
+ params.assertBeforeMutation();
280
+ assertCurrent(current);
281
+ }
282
+ }
283
+ else {
284
+ params.assertBeforeMutation?.();
285
+ assertCurrent(current);
286
+ }
287
+ if (windows) {
288
+ const mkdirChild = binding.mkdirChildBeneath;
289
+ if (typeof mkdirChild !== "function") {
290
+ throw new FsSafeError("helper-unavailable", "native direct-child parent creation is unavailable");
291
+ }
292
+ createdByMkdir = mkdirChild.call(binding, current.fd, segment, 0o777) === true;
293
+ child = await openWindowsPolicyParent(binding, params, rootAdmission, current.fd, currentPath, segment);
294
+ childFd = child.fd;
295
+ }
296
+ else {
297
+ if (fuseChildCreation && binding.mkdirOpenChildBeneath) {
298
+ try {
299
+ const child = binding.mkdirOpenChildBeneath(current.fd, segment, 0o777, secureDirectoryFlags);
300
+ childFd = child.fd;
301
+ createdByMkdir = child.created;
302
+ }
303
+ catch (error) {
304
+ throw normalizePosixParentOpenError(error, params);
305
+ }
306
+ }
307
+ else {
308
+ createdByMkdir = mkdirPosixPolicyChild(binding, current.fd, segment);
309
+ try {
310
+ childFd = binding.openBeneath(current.fd, segment, secureDirectoryFlags).fd;
311
+ }
312
+ catch (error) {
313
+ throw normalizePosixParentOpenError(error, params);
314
+ }
315
+ }
316
+ }
317
+ }
318
+ try {
319
+ if (!child) {
320
+ child = retainedTargetPath ? capturePolicyParent(childFd, childPath) : undefined;
321
+ if (!child) {
322
+ retainedTargetPath = undefined;
323
+ child = await describePosixParent(childFd, childPath);
324
+ }
325
+ if (!sameAbsolutePath(child.guard.realPath, childPath))
326
+ retainedTargetPath = undefined;
327
+ }
328
+ const windowsTarget = windows
329
+ ? joinPathSegmentRoute(child.guard.realPath, route, index + 1, params.basename)
330
+ : undefined;
331
+ if (session && windowsTarget !== session.retainedTargetPath) {
332
+ session.dispose();
333
+ session = undefined;
334
+ }
335
+ let childAuthorization;
336
+ if (createdByMkdir && createReceipt &&
337
+ (windows ? session : params.mutationAdmission?.advanceCreatedDirectory)) {
338
+ let evidence;
339
+ try {
340
+ const parent = windows
341
+ ? windowsParentObservation(binding, current.fd, { ...current.guard,
342
+ stat: inspectFileIdentitySync(() => fsSync.fstatSync(current.fd, { bigint: true }), current.guard.stat),
343
+ })
344
+ : current.policyDirectory
345
+ ? refreshPolicyStagedDirectoryObservation(current.policyDirectory)
346
+ : checkedMutationDirectory(currentPath, current.stagedDirectory.realPath, assertStagedDirectoryCurrent(current.stagedDirectory));
347
+ evidence = Object.freeze({
348
+ admission: createReceipt,
349
+ parent,
350
+ child: child.observation,
351
+ });
352
+ }
353
+ catch {
354
+ // Failed optional evidence falls back to the existing ordered admission.
355
+ }
356
+ if (evidence) {
357
+ childAuthorization = windows
358
+ ? session.advanceCreatedDirectory(evidence)
359
+ : params.mutationAdmission.advanceCreatedDirectory(evidence);
360
+ }
361
+ }
362
+ const targetPath = windowsTarget ?? retainedTargetPath ??
363
+ joinPathSegmentRoute(child.guard.realPath, route, index + 1, params.basename);
364
+ if (!windows || !childAuthorization) {
365
+ const request = {
366
+ targetPath, mutationPath: targetPath, phase: "parent",
367
+ };
368
+ if (!windows) {
369
+ Object.freeze(request);
370
+ // Existing prefixes are not the epoch's nearest parent. Their
371
+ // admission uses the full epoch fence below; offering an unrelated
372
+ // parent receipt would discard otherwise-current target evidence.
373
+ if (createdByMkdir) {
374
+ childAuthorization ??= params.mutationAdmission?.tryAuthorizeAtParent?.(request, child.observation);
375
+ }
376
+ }
377
+ if (!childAuthorization) {
378
+ await authorize(request);
379
+ assertCurrent(child);
380
+ }
381
+ }
382
+ }
383
+ catch (error) {
384
+ closeAfterFailure(childFd, { error });
385
+ throw error;
386
+ }
387
+ const previousFd = ownedFd;
388
+ disposeObservation(current.fd);
389
+ current = child;
390
+ ownedFd = child.fd;
391
+ currentPath = child.guard.realPath;
392
+ if (previousFd !== undefined)
393
+ closeFd(previousFd);
394
+ }
395
+ if (ownedFd === undefined) {
396
+ throw new FsSafeError("path-mismatch", "native write parent admission did not complete");
397
+ }
398
+ ownedFd = undefined;
399
+ return current;
400
+ }
401
+ catch (error) {
402
+ failure = { error };
403
+ throw error;
404
+ }
405
+ finally {
406
+ session?.dispose();
407
+ if (ownedFd !== undefined)
408
+ closeAfterFailure(ownedFd, failure);
409
+ }
410
+ }
411
+ catch (e_1) {
412
+ env_1.error = e_1;
413
+ env_1.hasError = true;
414
+ }
415
+ finally {
416
+ __disposeResources(env_1);
417
+ }
418
+ }