@openclaw/fs-safe 0.14.0 → 0.16.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.
- package/CHANGELOG.md +88 -0
- package/README.md +38 -10
- package/dist/advanced.d.ts +2 -1
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js +2 -1
- package/dist/archive-kind.d.ts +0 -1
- package/dist/archive-kind.d.ts.map +1 -1
- package/dist/archive-kind.js +5 -17
- package/dist/archive-merge.d.ts.map +1 -1
- package/dist/archive-merge.js +113 -46
- package/dist/archive-parser.wasm +0 -0
- package/dist/archive-read.d.ts.map +1 -1
- package/dist/archive-read.js +10 -11
- package/dist/archive-tar-stream.d.ts +3 -0
- package/dist/archive-tar-stream.d.ts.map +1 -1
- package/dist/archive-tar-stream.js +56 -37
- package/dist/archive-tar-wasm.d.ts +16 -4
- package/dist/archive-tar-wasm.d.ts.map +1 -1
- package/dist/archive-tar-wasm.js +134 -34
- package/dist/archive-zip-directory.d.ts +4 -0
- package/dist/archive-zip-directory.d.ts.map +1 -1
- package/dist/archive-zip-directory.js +2 -0
- package/dist/archive-zip-entry.d.ts +6 -2
- package/dist/archive-zip-entry.d.ts.map +1 -1
- package/dist/archive-zip-entry.js +23 -8
- package/dist/archive-zip-integrity.d.ts.map +1 -1
- package/dist/archive-zip-integrity.js +3 -4
- package/dist/archive-zip-loader.d.ts.map +1 -1
- package/dist/archive-zip-loader.js +107 -31
- package/dist/archive-zip-names.d.ts +1 -0
- package/dist/archive-zip-names.d.ts.map +1 -1
- package/dist/archive-zip-names.js +6 -0
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +11 -11
- package/dist/bounded-read-stream.d.ts +0 -1
- package/dist/bounded-read-stream.d.ts.map +1 -1
- package/dist/bounded-read-stream.js +0 -6
- package/dist/clone-metadata.d.ts +1 -0
- package/dist/clone-metadata.d.ts.map +1 -1
- package/dist/clone-metadata.js +6 -2
- package/dist/copy-publication.d.ts +6 -0
- package/dist/copy-publication.d.ts.map +1 -1
- package/dist/copy-publication.js +3 -0
- package/dist/copy-tree-portable.d.ts.map +1 -1
- package/dist/copy-tree-portable.js +44 -24
- package/dist/copy.d.ts.map +1 -1
- package/dist/copy.js +29 -11
- package/dist/create-directory.d.ts +20 -0
- package/dist/create-directory.d.ts.map +1 -0
- package/dist/create-directory.js +130 -0
- package/dist/create-file-async.d.ts +7 -0
- package/dist/create-file-async.d.ts.map +1 -0
- package/dist/create-file-async.js +121 -0
- package/dist/create-file.d.ts +8 -0
- package/dist/create-file.d.ts.map +1 -0
- package/dist/create-file.js +190 -0
- package/dist/create-owned-file.d.ts +8 -0
- package/dist/create-owned-file.d.ts.map +1 -0
- package/dist/create-owned-file.js +16 -0
- package/dist/create.d.ts +4 -0
- package/dist/create.d.ts.map +1 -0
- package/dist/create.js +2 -0
- package/dist/creation-darwin.d.ts +7 -0
- package/dist/creation-darwin.d.ts.map +1 -0
- package/dist/creation-darwin.js +79 -0
- package/dist/creation-file-state.d.ts +19 -0
- package/dist/creation-file-state.d.ts.map +1 -0
- package/dist/creation-file-state.js +118 -0
- package/dist/creation-path.d.ts +21 -0
- package/dist/creation-path.d.ts.map +1 -0
- package/dist/creation-path.js +71 -0
- package/dist/creation-permissions.d.ts +19 -0
- package/dist/creation-permissions.d.ts.map +1 -0
- package/dist/creation-permissions.js +125 -0
- package/dist/directory-durability.d.ts +1 -1
- package/dist/directory-durability.d.ts.map +1 -1
- package/dist/directory-durability.js +22 -80
- package/dist/directory-guard.d.ts +3 -0
- package/dist/directory-guard.d.ts.map +1 -1
- package/dist/directory-mode-node.d.ts +2 -0
- package/dist/directory-mode-node.d.ts.map +1 -1
- package/dist/directory-mode-node.js +8 -0
- package/dist/directory-mode-owner.js +5 -5
- package/dist/directory-receipt.d.ts +24 -0
- package/dist/directory-receipt.d.ts.map +1 -0
- package/dist/directory-receipt.js +127 -0
- package/dist/file-cleanup.d.ts +19 -0
- package/dist/file-cleanup.d.ts.map +1 -0
- package/dist/file-cleanup.js +78 -0
- package/dist/file-handle-transfer.d.ts +2 -0
- package/dist/file-handle-transfer.d.ts.map +1 -1
- package/dist/file-handle-transfer.js +57 -2
- package/dist/file-identity.d.ts.map +1 -1
- package/dist/file-identity.js +18 -4
- package/dist/file-lock-sync-admission.d.ts +19 -0
- package/dist/file-lock-sync-admission.d.ts.map +1 -0
- package/dist/file-lock-sync-admission.js +93 -0
- package/dist/file-lock-sync-root-acquire.d.ts +4 -0
- package/dist/file-lock-sync-root-acquire.d.ts.map +1 -0
- package/dist/file-lock-sync-root-acquire.js +370 -0
- package/dist/file-lock-sync-root-arbitration.d.ts +18 -0
- package/dist/file-lock-sync-root-arbitration.d.ts.map +1 -0
- package/dist/file-lock-sync-root-arbitration.js +66 -0
- package/dist/file-lock-sync-root-held.d.ts +34 -0
- package/dist/file-lock-sync-root-held.d.ts.map +1 -0
- package/dist/file-lock-sync-root-held.js +393 -0
- package/dist/file-lock-sync-root-io.d.ts +44 -0
- package/dist/file-lock-sync-root-io.d.ts.map +1 -0
- package/dist/file-lock-sync-root-io.js +209 -0
- package/dist/file-lock-sync-root-mutation.d.ts +17 -0
- package/dist/file-lock-sync-root-mutation.d.ts.map +1 -0
- package/dist/file-lock-sync-root-mutation.js +277 -0
- package/dist/file-lock-sync-root-options.d.ts +20 -0
- package/dist/file-lock-sync-root-options.d.ts.map +1 -0
- package/dist/file-lock-sync-root-options.js +58 -0
- package/dist/file-lock-sync-root-registration.d.ts +2 -0
- package/dist/file-lock-sync-root-registration.d.ts.map +1 -0
- package/dist/file-lock-sync-root-registration.js +90 -0
- package/dist/file-lock-sync-root.d.ts +36 -0
- package/dist/file-lock-sync-root.d.ts.map +1 -0
- package/dist/file-lock-sync-root.js +361 -0
- package/dist/file-lock-sync-stale-admission.d.ts +24 -0
- package/dist/file-lock-sync-stale-admission.d.ts.map +1 -0
- package/dist/file-lock-sync-stale-admission.js +205 -0
- package/dist/file-lock-sync.d.ts.map +1 -1
- package/dist/file-lock-sync.js +245 -205
- package/dist/file-observation.d.ts +1 -1
- package/dist/file-observation.d.ts.map +1 -1
- package/dist/file-store-boundary.d.ts +2 -6
- package/dist/file-store-boundary.d.ts.map +1 -1
- package/dist/file-store-boundary.js +3 -9
- package/dist/file-store-prune.d.ts.map +1 -1
- package/dist/file-store-prune.js +5 -1
- package/dist/file-store-sync-write.d.ts.map +1 -1
- package/dist/file-store-sync-write.js +5 -8
- package/dist/file-store.d.ts.map +1 -1
- package/dist/file-store.js +47 -12
- package/dist/guarded-mkdir.d.ts +1 -0
- package/dist/guarded-mkdir.d.ts.map +1 -1
- package/dist/guarded-mkdir.js +36 -7
- package/dist/json-document-store.d.ts.map +1 -1
- package/dist/json-document-store.js +22 -15
- package/dist/json-durable-queue-ownership.d.ts +0 -1
- package/dist/json-durable-queue-ownership.d.ts.map +1 -1
- package/dist/json-durable-queue-ownership.js +0 -6
- package/dist/move-path.js +1 -1
- package/dist/native-binding.d.ts +13 -1
- package/dist/native-binding.d.ts.map +1 -1
- package/dist/native-fallback-warning.d.ts +4 -0
- package/dist/native-fallback-warning.d.ts.map +1 -0
- package/dist/native-fallback-warning.js +11 -0
- package/dist/native-operations.d.ts +0 -2
- package/dist/native-operations.d.ts.map +1 -1
- package/dist/native-operations.js +0 -24
- package/dist/native-parent-admission.d.ts +5 -2
- package/dist/native-parent-admission.d.ts.map +1 -1
- package/dist/native-parent-admission.js +27 -7
- package/dist/native-pinned-write-windows.d.ts +1 -1
- package/dist/native-pinned-write-windows.d.ts.map +1 -1
- package/dist/native-pinned-write-windows.js +174 -29
- package/dist/native-pinned-write.d.ts.map +1 -1
- package/dist/native-pinned-write.js +26 -14
- package/dist/native-policy-parent-windows.d.ts +14 -0
- package/dist/native-policy-parent-windows.d.ts.map +1 -0
- package/dist/native-policy-parent-windows.js +209 -0
- package/dist/native-rename-outcome.d.ts +4 -0
- package/dist/native-rename-outcome.d.ts.map +1 -0
- package/dist/native-rename-outcome.js +8 -0
- package/dist/native-staged-file.d.ts +3 -2
- package/dist/native-staged-file.d.ts.map +1 -1
- package/dist/native-staged-file.js +121 -72
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +12 -8
- package/dist/owner-dacl.d.ts.map +1 -1
- package/dist/owner-dacl.js +10 -4
- package/dist/path-prefix.d.ts.map +1 -1
- package/dist/path-prefix.js +30 -8
- package/dist/path-suffix-aliases.d.ts +2 -0
- package/dist/path-suffix-aliases.d.ts.map +1 -1
- package/dist/path-suffix-aliases.js +25 -17
- package/dist/permission-exec.d.ts +2 -0
- package/dist/permission-exec.d.ts.map +1 -1
- package/dist/permission-exec.js +150 -21
- package/dist/permissions-windows.js +1 -1
- package/dist/pinned-mutation-admission.d.ts.map +1 -1
- package/dist/pinned-mutation-admission.js +10 -5
- package/dist/pinned-mutation-observation.d.ts +0 -1
- package/dist/pinned-mutation-observation.d.ts.map +1 -1
- package/dist/pinned-mutation-observation.js +0 -19
- package/dist/pinned-mutation-shared-route.d.ts +1 -0
- package/dist/pinned-mutation-shared-route.d.ts.map +1 -1
- package/dist/pinned-mutation-shared-route.js +1 -1
- package/dist/pinned-write-input.d.ts +4 -0
- package/dist/pinned-write-input.d.ts.map +1 -0
- package/dist/pinned-write-input.js +25 -0
- package/dist/pinned-write-mode.d.ts +5 -0
- package/dist/pinned-write-mode.d.ts.map +1 -0
- package/dist/pinned-write-mode.js +24 -0
- package/dist/pinned-write-staged.d.ts +6 -0
- package/dist/pinned-write-staged.d.ts.map +1 -0
- package/dist/pinned-write-staged.js +187 -0
- package/dist/pinned-write-types.d.ts +5 -0
- package/dist/pinned-write-types.d.ts.map +1 -1
- package/dist/pinned-write.d.ts.map +1 -1
- package/dist/pinned-write.js +35 -145
- package/dist/private-directory.d.ts.map +1 -1
- package/dist/private-directory.js +18 -4
- package/dist/private-producer-handoff-sync.d.ts +14 -0
- package/dist/private-producer-handoff-sync.d.ts.map +1 -0
- package/dist/private-producer-handoff-sync.js +114 -0
- package/dist/private-producer-handoff.d.ts +22 -4
- package/dist/private-producer-handoff.d.ts.map +1 -1
- package/dist/private-producer-handoff.js +140 -77
- package/dist/private-temp-workspace.d.ts.map +1 -1
- package/dist/private-temp-workspace.js +75 -121
- package/dist/publish-copy-stage.d.ts +2 -1
- package/dist/publish-copy-stage.d.ts.map +1 -1
- package/dist/publish-copy-stage.js +16 -7
- package/dist/publish-file.d.ts.map +1 -1
- package/dist/publish-file.js +2 -2
- package/dist/regular-file.d.ts.map +1 -1
- package/dist/regular-file.js +1 -15
- package/dist/replace-directory.d.ts.map +1 -1
- package/dist/replace-directory.js +256 -18
- package/dist/replace-file-copy-fallback.d.ts.map +1 -1
- package/dist/replace-file-copy-fallback.js +62 -70
- package/dist/replace-file-copy-source.d.ts.map +1 -1
- package/dist/replace-file-copy-source.js +10 -12
- package/dist/replace-file-temp-owner.d.ts +5 -9
- package/dist/replace-file-temp-owner.d.ts.map +1 -1
- package/dist/replace-file-temp-owner.js +56 -72
- package/dist/replace-file.js +6 -6
- package/dist/retained-directory-replacement.d.ts +26 -0
- package/dist/retained-directory-replacement.d.ts.map +1 -0
- package/dist/retained-directory-replacement.js +193 -0
- package/dist/root-boundary.d.ts +1 -0
- package/dist/root-boundary.d.ts.map +1 -1
- package/dist/root-boundary.js +4 -0
- package/dist/root-context.d.ts +0 -8
- package/dist/root-context.d.ts.map +1 -1
- package/dist/root-context.js +0 -3
- package/dist/root-create-input.d.ts +8 -1
- package/dist/root-create-input.d.ts.map +1 -1
- package/dist/root-create-input.js +17 -4
- package/dist/root-directory-creation.d.ts +3 -3
- package/dist/root-directory-creation.d.ts.map +1 -1
- package/dist/root-directory-creation.js +15 -3
- package/dist/root-directory-list.d.ts +1 -0
- package/dist/root-directory-list.d.ts.map +1 -1
- package/dist/root-directory-list.js +1 -0
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +46 -17
- package/dist/root-move-noreplace.d.ts.map +1 -1
- package/dist/root-move-noreplace.js +24 -15
- package/dist/root-options.d.ts +12 -4
- package/dist/root-options.d.ts.map +1 -1
- package/dist/root-path-errors.d.ts +1 -0
- package/dist/root-path-errors.d.ts.map +1 -1
- package/dist/root-path-errors.js +11 -2
- package/dist/root-path-existing.d.ts.map +1 -1
- package/dist/root-path-existing.js +11 -35
- package/dist/root-path-stat.d.ts.map +1 -1
- package/dist/root-path-stat.js +59 -7
- package/dist/root-path.js +1 -13
- package/dist/root-remove.d.ts +1 -0
- package/dist/root-remove.d.ts.map +1 -1
- package/dist/root-remove.js +4 -0
- package/dist/root-walk.d.ts +1 -1
- package/dist/root-walk.d.ts.map +1 -1
- package/dist/root-walk.js +17 -2
- package/dist/root-write-admission.d.ts +0 -2
- package/dist/root-write-admission.d.ts.map +1 -1
- package/dist/root-write-admission.js +1 -15
- package/dist/root-write-complete-parent.d.ts.map +1 -1
- package/dist/root-write-complete-parent.js +7 -23
- package/dist/root-write-publication.js +1 -1
- package/dist/root-write-verification.d.ts.map +1 -1
- package/dist/root-write-verification.js +29 -42
- package/dist/secret-file.d.ts.map +1 -1
- package/dist/secret-file.js +3 -24
- package/dist/secret-read-async.d.ts.map +1 -1
- package/dist/secret-read-async.js +3 -24
- package/dist/secret-read-policy.d.ts +6 -2
- package/dist/secret-read-policy.d.ts.map +1 -1
- package/dist/secret-read-policy.js +26 -2
- package/dist/secure-file-windows.d.ts +6 -0
- package/dist/secure-file-windows.d.ts.map +1 -1
- package/dist/secure-file-windows.js +34 -117
- package/dist/secure-file.js +2 -2
- package/dist/sibling-temp.d.ts.map +1 -1
- package/dist/sibling-temp.js +23 -12
- package/dist/sidecar-lock-acquire.d.ts +2 -28
- package/dist/sidecar-lock-acquire.d.ts.map +1 -1
- package/dist/sidecar-lock-acquire.js +288 -199
- package/dist/sidecar-lock-admission-context.d.ts +19 -0
- package/dist/sidecar-lock-admission-context.d.ts.map +1 -0
- package/dist/sidecar-lock-admission-context.js +60 -0
- package/dist/sidecar-lock-admission-parser.d.ts +43 -0
- package/dist/sidecar-lock-admission-parser.d.ts.map +1 -0
- package/dist/sidecar-lock-admission-parser.js +113 -0
- package/dist/sidecar-lock-admission.d.ts +35 -0
- package/dist/sidecar-lock-admission.d.ts.map +1 -0
- package/dist/sidecar-lock-admission.js +7 -0
- package/dist/sidecar-lock-reclaim.d.ts +9 -4
- package/dist/sidecar-lock-reclaim.d.ts.map +1 -1
- package/dist/sidecar-lock-reclaim.js +80 -25
- package/dist/sidecar-lock-root.d.ts.map +1 -1
- package/dist/sidecar-lock-root.js +2 -1
- package/dist/sidecar-lock-stale-admission.d.ts +39 -0
- package/dist/sidecar-lock-stale-admission.d.ts.map +1 -0
- package/dist/sidecar-lock-stale-admission.js +232 -0
- package/dist/sidecar-lock-target.d.ts +8 -0
- package/dist/sidecar-lock-target.d.ts.map +1 -0
- package/dist/sidecar-lock-target.js +55 -0
- package/dist/sidecar-lock.d.ts.map +1 -1
- package/dist/sidecar-lock.js +100 -16
- package/dist/staged-directory.d.ts.map +1 -1
- package/dist/staged-directory.js +6 -6
- package/dist/staged-file-settlement.d.ts +17 -0
- package/dist/staged-file-settlement.d.ts.map +1 -0
- package/dist/staged-file-settlement.js +57 -0
- package/dist/temp-workspace-descriptor.d.ts.map +1 -1
- package/dist/temp-workspace-descriptor.js +9 -27
- package/dist/temp-workspace-owner.d.ts.map +1 -1
- package/dist/temp-workspace-owner.js +8 -8
- package/dist/walk.d.ts +5 -1
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +19 -6
- package/dist/windows-owner.d.ts.map +1 -1
- package/dist/windows-owner.js +4 -3
- package/dist/windows-security-bridge.cs +336 -0
- package/dist/windows-security-bridge.ps1 +15 -0
- package/dist/windows-security-command.d.ts +26 -0
- package/dist/windows-security-command.d.ts.map +1 -0
- package/dist/windows-security-command.js +363 -0
- package/dist/windows-security-facts.d.ts +6 -0
- package/dist/windows-security-facts.d.ts.map +1 -0
- package/dist/windows-security-facts.js +108 -0
- package/docs/advanced.md +4 -2
- package/docs/archive.md +97 -46
- package/docs/atomic.md +85 -8
- package/docs/config.md +6 -2
- package/docs/contributing.md +44 -4
- package/docs/copy.md +37 -0
- package/docs/creation.md +128 -0
- package/docs/durability.md +24 -0
- package/docs/file-store.md +19 -0
- package/docs/install.md +31 -7
- package/docs/json-store.md +5 -0
- package/docs/migrating-to-0.5.md +15 -6
- package/docs/migrating-to-0.6.md +9 -4
- package/docs/native-helper.md +32 -12
- package/docs/native.md +38 -7
- package/docs/output.md +6 -0
- package/docs/path-prefix.md +10 -0
- package/docs/path-suffix-aliases.md +51 -6
- package/docs/permissions.md +50 -14
- package/docs/public-api.md +3 -2
- package/docs/root.md +56 -3
- package/docs/secret-file.md +11 -2
- package/docs/secure-file.md +9 -4
- package/docs/sidecar-lock.md +114 -8
- package/docs/staged-file.md +12 -3
- package/docs/temp.md +20 -3
- package/docs/walk.md +67 -1
- package/docs/writing.md +76 -6
- package/package.json +19 -16
- package/dist/darwin-acl.d.ts +0 -4
- package/dist/darwin-acl.d.ts.map +0 -1
- package/dist/darwin-acl.js +0 -24
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import fs, {} from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { inspectDirectoryIdentitySync } from "./directory-guard.js";
|
|
4
|
+
import { FsSafeError } from "./errors.js";
|
|
5
|
+
import { isNotFoundPathError } from "./path.js";
|
|
6
|
+
import { admitPathInsideRoot } from "./root-boundary.js";
|
|
7
|
+
import { assertRootIdentityCurrentSync } from "./root-context.js";
|
|
8
|
+
import { directoryComponentNotDirectoryError, outsideWorkspaceError, } from "./root-errors.js";
|
|
9
|
+
import { sidecarLockSnapshotMatches, } from "./sidecar-lock-reclaim.js";
|
|
10
|
+
import { inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
11
|
+
import { createSuppressedError } from "./suppressed-error.js";
|
|
12
|
+
import { assertFileLockSyncRootMutationAllowed, assertFileLockSyncRootResolvedPathCurrent, invokeFileLockSyncRootMutationAuthority, } from "./file-lock-sync-root.js";
|
|
13
|
+
import { assertDirectoryCurrent, assertRegularFile, assertRetainedParentCurrent, exactFileIdentity, fileLockSyncRootReceiptStillCurrent, fileReceiptCurrentAfterParentCheck, observeDirectory, readFileLockSyncRootSnapshot, sameExactIdentity, } from "./file-lock-sync-root-io.js";
|
|
14
|
+
import { pathForWindowsFilesystem } from "./windows-path-alias.js";
|
|
15
|
+
function ensureParent(pathAuthority) {
|
|
16
|
+
const authority = pathAuthority.authority;
|
|
17
|
+
const context = authority.context;
|
|
18
|
+
assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
|
|
19
|
+
const targetParent = path.dirname(pathAuthority.path);
|
|
20
|
+
const admitted = admitPathInsideRoot({
|
|
21
|
+
rootPath: context.rootReal,
|
|
22
|
+
candidatePath: targetParent,
|
|
23
|
+
rootIdentity: context.rootIdentity,
|
|
24
|
+
});
|
|
25
|
+
if (!admitted)
|
|
26
|
+
throw outsideWorkspaceError();
|
|
27
|
+
const relative = admitted.relativePath;
|
|
28
|
+
let current = context.rootReal;
|
|
29
|
+
let currentReceipt = observeDirectory(current);
|
|
30
|
+
for (const segment of relative.split(path.sep).filter(Boolean)) {
|
|
31
|
+
const next = path.join(current, segment);
|
|
32
|
+
assertRootIdentityCurrentSync(context);
|
|
33
|
+
assertDirectoryCurrent(currentReceipt);
|
|
34
|
+
let missing = false;
|
|
35
|
+
let existing;
|
|
36
|
+
try {
|
|
37
|
+
existing = fs.lstatSync(pathForWindowsFilesystem(next), { bigint: true });
|
|
38
|
+
if (existing.isSymbolicLink() || !existing.isDirectory()) {
|
|
39
|
+
throw directoryComponentNotDirectoryError();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (!isNotFoundPathError(error))
|
|
44
|
+
throw error;
|
|
45
|
+
missing = true;
|
|
46
|
+
}
|
|
47
|
+
if (missing) {
|
|
48
|
+
assertFileLockSyncRootMutationAllowed(next, authority.denyMutations);
|
|
49
|
+
const mutationAuthorityInvoked = invokeFileLockSyncRootMutationAuthority(authority);
|
|
50
|
+
if (mutationAuthorityInvoked) {
|
|
51
|
+
assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
|
|
52
|
+
}
|
|
53
|
+
assertDirectoryCurrent(currentReceipt);
|
|
54
|
+
assertRootIdentityCurrentSync(context);
|
|
55
|
+
// The callback may retarget a deny-policy alias at this particular
|
|
56
|
+
// intermediate component without changing the admitted final sidecar.
|
|
57
|
+
// Refresh the actual mkdir target after the callback and immediately
|
|
58
|
+
// before mutation.
|
|
59
|
+
if (mutationAuthorityInvoked) {
|
|
60
|
+
assertFileLockSyncRootMutationAllowed(next, authority.denyMutations);
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
fs.mkdirSync(pathForWindowsFilesystem(next));
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error.code !== "EEXIST")
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const nextReceipt = observeDirectory(next, existing);
|
|
71
|
+
assertDirectoryCurrent(currentReceipt);
|
|
72
|
+
current = nextReceipt.realPath;
|
|
73
|
+
currentReceipt = nextReceipt;
|
|
74
|
+
}
|
|
75
|
+
assertRootIdentityCurrentSync(context);
|
|
76
|
+
assertDirectoryCurrent(currentReceipt);
|
|
77
|
+
return currentReceipt;
|
|
78
|
+
}
|
|
79
|
+
export function createFileLockSyncRootFile(pathAuthority, mode, options = {}) {
|
|
80
|
+
const parent = ensureParent(pathAuthority);
|
|
81
|
+
if (invokeFileLockSyncRootMutationAuthority(pathAuthority.authority)) {
|
|
82
|
+
assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
|
|
83
|
+
assertRetainedParentCurrent(pathAuthority, parent);
|
|
84
|
+
}
|
|
85
|
+
const noFollow = process.platform !== "win32" && typeof fs.constants.O_NOFOLLOW === "number"
|
|
86
|
+
? fs.constants.O_NOFOLLOW
|
|
87
|
+
: 0;
|
|
88
|
+
let fd;
|
|
89
|
+
let receipt;
|
|
90
|
+
try {
|
|
91
|
+
options.assertBeforeOpen?.();
|
|
92
|
+
try {
|
|
93
|
+
fd = fs.openSync(pathForWindowsFilesystem(pathAuthority.path), fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL | noFollow, mode);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
options.onOpenFailure?.(error);
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
const opened = inspectFileIdentitySync(() => fs.fstatSync(fd, { bigint: true }));
|
|
100
|
+
assertRegularFile(opened, pathAuthority.authority.hardlinks);
|
|
101
|
+
receipt = Object.freeze({ identity: exactFileIdentity(opened), parent });
|
|
102
|
+
if (!fileReceiptCurrentAfterParentCheck(pathAuthority, receipt)) {
|
|
103
|
+
throw new FsSafeError("path-mismatch", "created sidecar lock changed before admission");
|
|
104
|
+
}
|
|
105
|
+
return { fd, receipt };
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
if (fd === undefined)
|
|
109
|
+
throw error;
|
|
110
|
+
const failedFd = fd;
|
|
111
|
+
fd = undefined;
|
|
112
|
+
try {
|
|
113
|
+
fs.closeSync(failedFd);
|
|
114
|
+
if (receipt && !removeFileLockSyncRootFile(pathAuthority, receipt)) {
|
|
115
|
+
throw new FsSafeError("path-mismatch", "created sidecar lock changed before cleanup");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch (cleanupError) {
|
|
119
|
+
throw createSuppressedError(error, cleanupError, "file lock create admission and cleanup both failed");
|
|
120
|
+
}
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export function refreshFileLockSyncRootFileReceipt(pathAuthority, receipt) {
|
|
125
|
+
if (!fileReceiptCurrentAfterParentCheck(pathAuthority, receipt)) {
|
|
126
|
+
throw new FsSafeError("path-mismatch", "created sidecar lock changed before admission");
|
|
127
|
+
}
|
|
128
|
+
return receipt;
|
|
129
|
+
}
|
|
130
|
+
export function removeFileLockSyncRootFile(pathAuthority, receipt, expected, assertBeforeRemove) {
|
|
131
|
+
assertFileLockSyncRootMutationAllowed(pathAuthority.path, pathAuthority.authority.denyMutations);
|
|
132
|
+
const matches = () => {
|
|
133
|
+
if (!expected)
|
|
134
|
+
return fileLockSyncRootReceiptStillCurrent(pathAuthority, receipt);
|
|
135
|
+
const current = readFileLockSyncRootSnapshot(pathAuthority, {
|
|
136
|
+
expectedReceipt: receipt,
|
|
137
|
+
});
|
|
138
|
+
const matched = !!current &&
|
|
139
|
+
sameExactIdentity(current.receipt.identity, receipt.identity) &&
|
|
140
|
+
sidecarLockSnapshotMatches(current.snapshot, expected);
|
|
141
|
+
return matched;
|
|
142
|
+
};
|
|
143
|
+
if (!matches())
|
|
144
|
+
return false;
|
|
145
|
+
if (invokeFileLockSyncRootMutationAuthority(pathAuthority.authority) && !matches())
|
|
146
|
+
return false;
|
|
147
|
+
if (assertBeforeRemove?.() === false)
|
|
148
|
+
return false;
|
|
149
|
+
assertFileLockSyncRootMutationAllowed(pathAuthority.path, pathAuthority.authority.denyMutations);
|
|
150
|
+
fs.unlinkSync(pathForWindowsFilesystem(pathAuthority.path));
|
|
151
|
+
assertRetainedParentCurrent(pathAuthority, receipt.parent);
|
|
152
|
+
let successorStat;
|
|
153
|
+
try {
|
|
154
|
+
successorStat = inspectFileIdentitySync(() => fs.lstatSync(pathForWindowsFilesystem(pathAuthority.path), { bigint: true }));
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
if (isNotFoundPathError(error))
|
|
158
|
+
return true;
|
|
159
|
+
throw error;
|
|
160
|
+
}
|
|
161
|
+
assertRegularFile(successorStat, pathAuthority.authority.hardlinks);
|
|
162
|
+
assertRetainedParentCurrent(pathAuthority, receipt.parent);
|
|
163
|
+
if (!sameExactIdentity(exactFileIdentity(successorStat), receipt.identity))
|
|
164
|
+
return true;
|
|
165
|
+
if (expected) {
|
|
166
|
+
const successor = readFileLockSyncRootSnapshot(pathAuthority);
|
|
167
|
+
assertRetainedParentCurrent(pathAuthority, receipt.parent);
|
|
168
|
+
if (successor) {
|
|
169
|
+
if (!sameExactIdentity(successor.receipt.identity, receipt.identity) ||
|
|
170
|
+
!sidecarLockSnapshotMatches(successor.snapshot, expected))
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
// A null descriptor-bound snapshot can mean confirmed absence, a distinct
|
|
175
|
+
// replacement, or unverifiable identity. Re-observe once and accept only
|
|
176
|
+
// the first two states; ambiguity about the removed generation fails closed.
|
|
177
|
+
let current;
|
|
178
|
+
try {
|
|
179
|
+
current = inspectFileIdentitySync(() => fs.lstatSync(pathForWindowsFilesystem(pathAuthority.path), { bigint: true }));
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
if (isNotFoundPathError(error)) {
|
|
183
|
+
assertRetainedParentCurrent(pathAuthority, receipt.parent);
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
assertRegularFile(current, pathAuthority.authority.hardlinks);
|
|
189
|
+
assertRetainedParentCurrent(pathAuthority, receipt.parent);
|
|
190
|
+
if (!sameExactIdentity(exactFileIdentity(current), receipt.identity))
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
throw new FsSafeError("path-mismatch", "sidecar lock was replaced during removal");
|
|
195
|
+
}
|
|
196
|
+
export function fileLockSyncRootGuardExists(pathAuthority, pathAlreadyCurrent = false) {
|
|
197
|
+
if (!pathAlreadyCurrent)
|
|
198
|
+
assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
|
|
199
|
+
// A shared path admission may skip only duplicate resolution, never this
|
|
200
|
+
// operation-local Root identity fence before fresh directory inspection.
|
|
201
|
+
assertRootIdentityCurrentSync(pathAuthority.authority.context);
|
|
202
|
+
let stat;
|
|
203
|
+
try {
|
|
204
|
+
stat = fs.lstatSync(pathForWindowsFilesystem(pathAuthority.path), { bigint: true });
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
if (isNotFoundPathError(error)) {
|
|
208
|
+
assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
|
|
209
|
+
assertRootIdentityCurrentSync(pathAuthority.authority.context);
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
214
|
+
if (stat.isSymbolicLink() || (!stat.isDirectory() && !stat.isFile())) {
|
|
215
|
+
throw directoryComponentNotDirectoryError();
|
|
216
|
+
}
|
|
217
|
+
if (stat.isFile())
|
|
218
|
+
assertRegularFile(stat, pathAuthority.authority.hardlinks);
|
|
219
|
+
const parent = observeDirectory(path.dirname(pathAuthority.path));
|
|
220
|
+
if (stat.isFile()) {
|
|
221
|
+
const current = inspectFileIdentitySync(() => fs.lstatSync(pathForWindowsFilesystem(pathAuthority.path), { bigint: true }), exactFileIdentity(stat));
|
|
222
|
+
assertRegularFile(current, pathAuthority.authority.hardlinks);
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
inspectDirectoryIdentitySync(pathAuthority.path, exactFileIdentity(stat));
|
|
226
|
+
}
|
|
227
|
+
assertDirectoryCurrent(parent);
|
|
228
|
+
assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
|
|
229
|
+
assertRootIdentityCurrentSync(pathAuthority.authority.context);
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
export function createFileLockSyncRootDirectory(pathAuthority) {
|
|
233
|
+
const parent = ensureParent(pathAuthority);
|
|
234
|
+
if (invokeFileLockSyncRootMutationAuthority(pathAuthority.authority)) {
|
|
235
|
+
assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
|
|
236
|
+
assertRetainedParentCurrent(pathAuthority, parent);
|
|
237
|
+
}
|
|
238
|
+
try {
|
|
239
|
+
fs.mkdirSync(pathForWindowsFilesystem(pathAuthority.path));
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
if (error.code === "EEXIST")
|
|
243
|
+
return null;
|
|
244
|
+
throw error;
|
|
245
|
+
}
|
|
246
|
+
const stat = inspectDirectoryIdentitySync(pathAuthority.path);
|
|
247
|
+
const receipt = Object.freeze({ identity: exactFileIdentity(stat), parent });
|
|
248
|
+
assertRetainedParentCurrent(pathAuthority, parent);
|
|
249
|
+
inspectDirectoryIdentitySync(pathAuthority.path, receipt.identity);
|
|
250
|
+
return receipt;
|
|
251
|
+
}
|
|
252
|
+
export function removeFileLockSyncRootDirectory(pathAuthority, receipt) {
|
|
253
|
+
if (!fileLockSyncRootDirectoryReceiptStillCurrent(pathAuthority, receipt))
|
|
254
|
+
return false;
|
|
255
|
+
assertFileLockSyncRootMutationAllowed(pathAuthority.path, pathAuthority.authority.denyMutations, true);
|
|
256
|
+
if (invokeFileLockSyncRootMutationAuthority(pathAuthority.authority) &&
|
|
257
|
+
!fileLockSyncRootDirectoryReceiptStillCurrent(pathAuthority, receipt))
|
|
258
|
+
return false;
|
|
259
|
+
assertFileLockSyncRootMutationAllowed(pathAuthority.path, pathAuthority.authority.denyMutations, true);
|
|
260
|
+
fs.rmdirSync(pathForWindowsFilesystem(pathAuthority.path));
|
|
261
|
+
assertRetainedParentCurrent(pathAuthority, receipt.parent);
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
export function fileLockSyncRootDirectoryReceiptStillCurrent(pathAuthority, receipt) {
|
|
265
|
+
assertRetainedParentCurrent(pathAuthority, receipt.parent);
|
|
266
|
+
try {
|
|
267
|
+
inspectDirectoryIdentitySync(pathAuthority.path, receipt.identity);
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
if (isNotFoundPathError(error) ||
|
|
271
|
+
(error instanceof FsSafeError && error.code === "path-mismatch"))
|
|
272
|
+
return false;
|
|
273
|
+
throw error;
|
|
274
|
+
}
|
|
275
|
+
assertRetainedParentCurrent(pathAuthority, receipt.parent);
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { FileLockSyncAcquireOptions } from "./file-lock-sync.js";
|
|
2
|
+
import type { SidecarLockCompromisedInfo, SidecarLockRetryOptions, SidecarLockStaleRecovery } from "./sidecar-lock-types.js";
|
|
3
|
+
type CapturedRootSyncAcquireOptions<TPayload extends Record<string, unknown>> = Readonly<{
|
|
4
|
+
compromiseCheckIntervalMs?: number;
|
|
5
|
+
lockPath?: string;
|
|
6
|
+
onCompromised?: (info: SidecarLockCompromisedInfo) => void;
|
|
7
|
+
optionsReceiver: FileLockSyncAcquireOptions<TPayload>;
|
|
8
|
+
parsePayload?: (raw: string) => unknown;
|
|
9
|
+
payload: () => TPayload;
|
|
10
|
+
reentrantOwner?: string;
|
|
11
|
+
retry: Readonly<SidecarLockRetryOptions>;
|
|
12
|
+
shouldReclaim?: FileLockSyncAcquireOptions<TPayload>["shouldReclaim"];
|
|
13
|
+
shouldRemoveStaleLock?: FileLockSyncAcquireOptions<TPayload>["shouldRemoveStaleLock"];
|
|
14
|
+
staleMs: number;
|
|
15
|
+
staleRecovery?: SidecarLockStaleRecovery;
|
|
16
|
+
timeoutMs?: number;
|
|
17
|
+
}>;
|
|
18
|
+
export declare function captureRootSyncAcquireOptions<TPayload extends Record<string, unknown>>(options: FileLockSyncAcquireOptions<TPayload>): CapturedRootSyncAcquireOptions<TPayload>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=file-lock-sync-root-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-lock-sync-root-options.d.ts","sourceRoot":"","sources":["../src/file-lock-sync-root-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAItE,OAAO,KAAK,EAAE,0BAA0B,EAAE,uBAAuB,EAC/D,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,KAAK,8BAA8B,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,QAAQ,CAAC;IACvF,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,0BAA0B,KAAK,IAAI,CAAC;IAC3D,eAAe,EAAE,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IACtD,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACxC,OAAO,EAAE,MAAM,QAAQ,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,QAAQ,CAAC,uBAAuB,CAAC,CAAC;IACzC,aAAa,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,CAAC,eAAe,CAAC,CAAC;IACtE,qBAAqB,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,CAAC,uBAAuB,CAAC,CAAC;IACtF,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,wBAAwB,CAAC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,wBAAgB,6BAA6B,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpF,OAAO,EAAE,0BAA0B,CAAC,QAAQ,CAAC,GAC5C,8BAA8B,CAAC,QAAQ,CAAC,CAuD1C"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { getFsSafeLockConfig } from "./lock-config.js";
|
|
2
|
+
import { validateSidecarLockCompromiseCheckIntervalMs, validateSidecarLockRetryOptions, validateSidecarLockStaleMs, validateSidecarLockTimeoutMs } from "./sidecar-lock-policy.js";
|
|
3
|
+
export function captureRootSyncAcquireOptions(options) {
|
|
4
|
+
// Root authority is already validated and snapshotted before entering this
|
|
5
|
+
// helper. Snapshot every remaining caller-owned property before validating
|
|
6
|
+
// options; nested retry accessors must not be revisited by backoff or a
|
|
7
|
+
// callback that mutates the original options object.
|
|
8
|
+
const lockPath = options.lockPath;
|
|
9
|
+
const staleMsInput = options.staleMs;
|
|
10
|
+
const timeoutMsInput = options.timeoutMs;
|
|
11
|
+
const retryInput = options.retry;
|
|
12
|
+
const staleRecoveryInput = options.staleRecovery;
|
|
13
|
+
const reentrantOwner = options.reentrantOwner;
|
|
14
|
+
const payload = options.payload;
|
|
15
|
+
const shouldReclaim = options.shouldReclaim;
|
|
16
|
+
const shouldRemoveStaleLock = options.shouldRemoveStaleLock;
|
|
17
|
+
const parsePayload = options.parsePayload;
|
|
18
|
+
const onCompromised = options.onCompromised;
|
|
19
|
+
const compromiseCheckIntervalMs = options.compromiseCheckIntervalMs;
|
|
20
|
+
const retrySnapshot = retryInput === undefined ? undefined : Object.freeze({
|
|
21
|
+
retries: retryInput.retries,
|
|
22
|
+
factor: retryInput.factor,
|
|
23
|
+
minTimeout: retryInput.minTimeout,
|
|
24
|
+
maxTimeout: retryInput.maxTimeout,
|
|
25
|
+
randomize: retryInput.randomize,
|
|
26
|
+
});
|
|
27
|
+
const defaults = getFsSafeLockConfig();
|
|
28
|
+
const defaultRetry = defaults.retry;
|
|
29
|
+
const retry = retrySnapshot ?? Object.freeze({
|
|
30
|
+
retries: defaultRetry?.retries,
|
|
31
|
+
factor: defaultRetry?.factor,
|
|
32
|
+
minTimeout: defaultRetry?.minTimeout,
|
|
33
|
+
maxTimeout: defaultRetry?.maxTimeout,
|
|
34
|
+
randomize: defaultRetry?.randomize,
|
|
35
|
+
});
|
|
36
|
+
const timeoutMs = timeoutMsInput ?? defaults.timeoutMs;
|
|
37
|
+
const staleMs = staleMsInput ?? defaults.staleMs ?? 30_000;
|
|
38
|
+
const staleRecovery = staleRecoveryInput ?? defaults.staleRecovery;
|
|
39
|
+
validateSidecarLockRetryOptions(retry);
|
|
40
|
+
validateSidecarLockTimeoutMs(timeoutMs);
|
|
41
|
+
validateSidecarLockStaleMs(staleMs);
|
|
42
|
+
validateSidecarLockCompromiseCheckIntervalMs(compromiseCheckIntervalMs);
|
|
43
|
+
return Object.freeze({
|
|
44
|
+
compromiseCheckIntervalMs,
|
|
45
|
+
lockPath,
|
|
46
|
+
onCompromised,
|
|
47
|
+
optionsReceiver: options,
|
|
48
|
+
parsePayload,
|
|
49
|
+
payload,
|
|
50
|
+
reentrantOwner,
|
|
51
|
+
retry,
|
|
52
|
+
shouldReclaim,
|
|
53
|
+
shouldRemoveStaleLock,
|
|
54
|
+
staleMs,
|
|
55
|
+
staleRecovery,
|
|
56
|
+
timeoutMs,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-lock-sync-root-registration.d.ts","sourceRoot":"","sources":["../src/file-lock-sync-root-registration.ts"],"names":[],"mappings":"AA+BA,wBAAgB,2CAA2C,CACzD,cAAc,EAAE,MAAM,IAAI,GACzB,IAAI,CAgFN"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { FsSafeError } from "./errors.js";
|
|
2
|
+
import { createSuppressedError } from "./suppressed-error.js";
|
|
3
|
+
const ROOT_SYNC_CLEANUP_REGISTERING_KEY = Symbol.for("fsSafe.syncRootSidecarLockCleanupRegistering.v1");
|
|
4
|
+
const ROOT_SYNC_CLEANUP_REGISTERED_KEY = Symbol.for("fsSafe.syncRootSidecarLockCleanupRegistered.v1");
|
|
5
|
+
const ROOT_SYNC_CLEANUP_FAILED_KEY = Symbol.for("fsSafe.syncRootSidecarLockCleanupRegistrationFailed.v1");
|
|
6
|
+
const ROOT_SYNC_CLEANUP_HANDLER_KEY = Symbol.for("fsSafe.syncRootSidecarLockCleanupHandler.v1");
|
|
7
|
+
function unavailable(message) {
|
|
8
|
+
return new FsSafeError("helper-unavailable", message);
|
|
9
|
+
}
|
|
10
|
+
function exactListenerCount(listener) {
|
|
11
|
+
return process.listeners("exit").filter((candidate) => candidate === listener).length;
|
|
12
|
+
}
|
|
13
|
+
export function ensureFileLockSyncRootExitCleanupRegistered(cleanupHandler) {
|
|
14
|
+
const state = globalThis;
|
|
15
|
+
if (state[ROOT_SYNC_CLEANUP_REGISTERED_KEY]) {
|
|
16
|
+
if (typeof state[ROOT_SYNC_CLEANUP_HANDLER_KEY] === "function")
|
|
17
|
+
return;
|
|
18
|
+
state[ROOT_SYNC_CLEANUP_FAILED_KEY] = true;
|
|
19
|
+
throw unavailable("Root sidecar exit cleanup registration state is inconsistent");
|
|
20
|
+
}
|
|
21
|
+
if (state[ROOT_SYNC_CLEANUP_FAILED_KEY]) {
|
|
22
|
+
throw unavailable("Root sidecar exit cleanup registration previously failed");
|
|
23
|
+
}
|
|
24
|
+
if (state[ROOT_SYNC_CLEANUP_REGISTERING_KEY]) {
|
|
25
|
+
throw unavailable("Root sidecar exit cleanup registration is already in progress");
|
|
26
|
+
}
|
|
27
|
+
if (state[ROOT_SYNC_CLEANUP_HANDLER_KEY] !== undefined) {
|
|
28
|
+
state[ROOT_SYNC_CLEANUP_FAILED_KEY] = true;
|
|
29
|
+
throw unavailable("Root sidecar exit cleanup handler exists without registration");
|
|
30
|
+
}
|
|
31
|
+
state[ROOT_SYNC_CLEANUP_REGISTERING_KEY] = true;
|
|
32
|
+
let baselineCount;
|
|
33
|
+
let registrationAttempted = false;
|
|
34
|
+
let registrationStateAmbiguous = false;
|
|
35
|
+
try {
|
|
36
|
+
baselineCount = exactListenerCount(cleanupHandler);
|
|
37
|
+
if (baselineCount !== 0) {
|
|
38
|
+
registrationStateAmbiguous = true;
|
|
39
|
+
throw unavailable("Root sidecar exit cleanup listener exists without registration");
|
|
40
|
+
}
|
|
41
|
+
registrationAttempted = true;
|
|
42
|
+
process.on("exit", cleanupHandler);
|
|
43
|
+
if (exactListenerCount(cleanupHandler) !== baselineCount + 1) {
|
|
44
|
+
throw unavailable("Root sidecar exit cleanup listener was not registered exactly once");
|
|
45
|
+
}
|
|
46
|
+
// Do not expose a callable handler or report success until process.on has
|
|
47
|
+
// returned and the exact listener registration has been observed.
|
|
48
|
+
state[ROOT_SYNC_CLEANUP_HANDLER_KEY] = cleanupHandler;
|
|
49
|
+
state[ROOT_SYNC_CLEANUP_REGISTERED_KEY] = true;
|
|
50
|
+
state[ROOT_SYNC_CLEANUP_FAILED_KEY] = false;
|
|
51
|
+
state[ROOT_SYNC_CLEANUP_REGISTERING_KEY] = false;
|
|
52
|
+
}
|
|
53
|
+
catch (registrationError) {
|
|
54
|
+
let rollbackFailed = false;
|
|
55
|
+
let rollbackError;
|
|
56
|
+
if (registrationAttempted && baselineCount !== undefined) {
|
|
57
|
+
try {
|
|
58
|
+
let currentCount = exactListenerCount(cleanupHandler);
|
|
59
|
+
while (currentCount > baselineCount) {
|
|
60
|
+
process.removeListener("exit", cleanupHandler);
|
|
61
|
+
const nextCount = exactListenerCount(cleanupHandler);
|
|
62
|
+
if (nextCount >= currentCount) {
|
|
63
|
+
throw unavailable("Root sidecar exit cleanup listener rollback made no progress");
|
|
64
|
+
}
|
|
65
|
+
currentCount = nextCount;
|
|
66
|
+
}
|
|
67
|
+
if (currentCount !== baselineCount) {
|
|
68
|
+
throw unavailable("Root sidecar exit cleanup listener rollback was ambiguous");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
rollbackFailed = true;
|
|
73
|
+
rollbackError = error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
state[ROOT_SYNC_CLEANUP_HANDLER_KEY] = undefined;
|
|
77
|
+
state[ROOT_SYNC_CLEANUP_REGISTERED_KEY] = false;
|
|
78
|
+
state[ROOT_SYNC_CLEANUP_REGISTERING_KEY] = false;
|
|
79
|
+
if (registrationStateAmbiguous) {
|
|
80
|
+
state[ROOT_SYNC_CLEANUP_FAILED_KEY] = true;
|
|
81
|
+
throw registrationError;
|
|
82
|
+
}
|
|
83
|
+
if (rollbackFailed) {
|
|
84
|
+
state[ROOT_SYNC_CLEANUP_FAILED_KEY] = true;
|
|
85
|
+
throw createSuppressedError(registrationError, rollbackError, "Root sidecar exit cleanup registration and rollback both failed");
|
|
86
|
+
}
|
|
87
|
+
state[ROOT_SYNC_CLEANUP_FAILED_KEY] = false;
|
|
88
|
+
throw registrationError;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type RootContext } from "./root-context.js";
|
|
2
|
+
import type { Root, RootDefaults } from "./root-impl.js";
|
|
3
|
+
/** @internal Registers only instances constructed by RootHandle itself. */
|
|
4
|
+
export declare function registerFileLockSyncRootAdapter(handle: object, context: RootContext, defaults: RootDefaults): void;
|
|
5
|
+
export type FileLockSyncRootAuthority = Readonly<{
|
|
6
|
+
adapter: object;
|
|
7
|
+
context: RootContext;
|
|
8
|
+
assertBeforeMutation?: () => void;
|
|
9
|
+
denyMutations?: Readonly<{
|
|
10
|
+
paths?: readonly string[];
|
|
11
|
+
prefixes?: readonly string[];
|
|
12
|
+
}>;
|
|
13
|
+
hardlinks?: RootDefaults["hardlinks"];
|
|
14
|
+
mutationPolicy: RootPathResolutionPolicy;
|
|
15
|
+
readPolicy: RootPathResolutionPolicy;
|
|
16
|
+
policiesMatch: boolean;
|
|
17
|
+
}>;
|
|
18
|
+
export type FileLockSyncRootPath = Readonly<{
|
|
19
|
+
authority: FileLockSyncRootAuthority;
|
|
20
|
+
path: string;
|
|
21
|
+
relativePath: string;
|
|
22
|
+
}>;
|
|
23
|
+
export declare function captureFileLockSyncRootAuthority(lockRoot: Root): FileLockSyncRootAuthority;
|
|
24
|
+
export declare function invokeFileLockSyncRootMutationAuthority(authority: FileLockSyncRootAuthority): boolean;
|
|
25
|
+
export declare function assertFileLockSyncRootMutationAllowed(pathname: string, policy: FileLockSyncRootAuthority["denyMutations"], protectAncestors?: boolean): void;
|
|
26
|
+
type RootPathResolutionPolicy = Readonly<{
|
|
27
|
+
rejectSymlinks?: boolean;
|
|
28
|
+
rejectFinalSymlink?: boolean;
|
|
29
|
+
rejectUnresolvedSymlinks: true;
|
|
30
|
+
}>;
|
|
31
|
+
export declare function admitFileLockSyncRootPath(authority: FileLockSyncRootAuthority, requestedPath: string): FileLockSyncRootPath;
|
|
32
|
+
export declare function assertFileLockSyncRootResolvedPathCurrent(pathAuthority: FileLockSyncRootPath): void;
|
|
33
|
+
export declare function assertFileLockSyncRootPathsCurrent(paths: readonly FileLockSyncRootPath[], invokeAuthority?: boolean, pathsAlreadyCurrent?: boolean): void;
|
|
34
|
+
export declare function normalizeFileLockSyncTargetWithRoot(authority: FileLockSyncRootAuthority, resolvedTargetPath: string): string;
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=file-lock-sync-root.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-lock-sync-root.d.ts","sourceRoot":"","sources":["../src/file-lock-sync-root.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAK3B,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAgBzD,2EAA2E;AAC3E,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,GACrB,IAAI,CAON;AAED,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,WAAW,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,aAAa,CAAC,EAAE,QAAQ,CAAC;QACvB,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC1B,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;KAC9B,CAAC,CAAC;IACH,SAAS,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;IACtC,cAAc,EAAE,wBAAwB,CAAC;IACzC,UAAU,EAAE,wBAAwB,CAAC;IACrC,aAAa,EAAE,OAAO,CAAC;CACxB,CAAC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C,SAAS,EAAE,yBAAyB,CAAC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC,CAAC;AAcH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,IAAI,GACb,yBAAyB,CAkD3B;AAED,wBAAgB,uCAAuC,CACrD,SAAS,EAAE,yBAAyB,GACnC,OAAO,CAOT;AAuDD,wBAAgB,qCAAqC,CACnD,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,yBAAyB,CAAC,eAAe,CAAC,EAClD,gBAAgB,UAAQ,GACvB,IAAI,CAsBN;AAED,KAAK,wBAAwB,GAAG,QAAQ,CAAC;IACvC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,wBAAwB,EAAE,IAAI,CAAC;CAChC,CAAC,CAAC;AA6FH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,yBAAyB,EACpC,aAAa,EAAE,MAAM,GACpB,oBAAoB,CAetB;AAED,wBAAgB,yCAAyC,CACvD,aAAa,EAAE,oBAAoB,GAClC,IAAI,CASN;AAwBD,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,SAAS,oBAAoB,EAAE,EACtC,eAAe,UAAQ,EACvB,mBAAmB,UAAQ,GAC1B,IAAI,CAuBN;AAwCD,wBAAgB,mCAAmC,CACjD,SAAS,EAAE,yBAAyB,EACpC,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAeR"}
|