@openclaw/fs-safe 0.4.7 → 0.5.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.
- package/CHANGELOG.md +58 -0
- package/README.md +82 -43
- package/dist/archive-entry.d.ts.map +1 -1
- package/dist/archive-entry.js +5 -4
- package/dist/archive-errors.d.ts +11 -0
- package/dist/archive-errors.d.ts.map +1 -0
- package/dist/archive-errors.js +16 -0
- package/dist/archive-input.d.ts +12 -0
- package/dist/archive-input.d.ts.map +1 -0
- package/dist/archive-input.js +72 -0
- package/dist/archive-kind.d.ts +1 -1
- package/dist/archive-kind.d.ts.map +1 -1
- package/dist/archive-kind.js +18 -0
- package/dist/archive-limits.d.ts +10 -0
- package/dist/archive-limits.d.ts.map +1 -1
- package/dist/archive-limits.js +18 -0
- package/dist/archive-native.d.ts +18 -0
- package/dist/archive-native.d.ts.map +1 -0
- package/dist/archive-native.js +115 -0
- package/dist/archive-options.d.ts +21 -0
- package/dist/archive-options.d.ts.map +1 -0
- package/dist/archive-options.js +1 -0
- package/dist/archive-policy.d.ts +20 -0
- package/dist/archive-policy.d.ts.map +1 -0
- package/dist/archive-policy.js +29 -0
- package/dist/archive-read.d.ts +6 -0
- package/dist/archive-read.d.ts.map +1 -0
- package/dist/archive-read.js +200 -0
- package/dist/archive-staging.d.ts +2 -5
- package/dist/archive-staging.d.ts.map +1 -1
- package/dist/archive-staging.js +19 -10
- package/dist/archive-tar-meta.d.ts +6 -0
- package/dist/archive-tar-meta.d.ts.map +1 -0
- package/dist/archive-tar-meta.js +143 -0
- package/dist/archive-tar-runtime.d.ts +43 -0
- package/dist/archive-tar-runtime.d.ts.map +1 -0
- package/dist/archive-tar-runtime.js +8 -0
- package/dist/archive-tar.d.ts +5 -1
- package/dist/archive-tar.d.ts.map +1 -1
- package/dist/archive-tar.js +24 -6
- package/dist/archive-zip-entry.d.ts +15 -0
- package/dist/archive-zip-entry.d.ts.map +1 -0
- package/dist/archive-zip-entry.js +17 -0
- package/dist/archive.d.ts +7 -17
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +111 -108
- package/dist/atomic.d.ts +1 -1
- package/dist/atomic.d.ts.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -1
- package/dist/containment.d.ts +2 -0
- package/dist/containment.d.ts.map +1 -0
- package/dist/containment.js +1 -0
- package/dist/device-path.d.ts.map +1 -1
- package/dist/device-path.js +24 -2
- package/dist/durability.d.ts +2 -0
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +2 -0
- package/dist/errors.d.ts +4 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -0
- package/dist/file-hash.d.ts +10 -0
- package/dist/file-hash.d.ts.map +1 -0
- package/dist/file-hash.js +73 -0
- package/dist/file-lock-sync.d.ts +35 -0
- package/dist/file-lock-sync.d.ts.map +1 -0
- package/dist/file-lock-sync.js +233 -0
- package/dist/file-lock.d.ts +2 -0
- package/dist/file-lock.d.ts.map +1 -1
- package/dist/file-lock.js +1 -0
- package/dist/filename.d.ts.map +1 -1
- package/dist/filename.js +4 -1
- package/dist/guarded-mkdir.d.ts +7 -1
- package/dist/guarded-mkdir.d.ts.map +1 -1
- package/dist/guarded-mkdir.js +45 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/json-document-store.d.ts.map +1 -1
- package/dist/json-document-store.js +30 -15
- package/dist/move-path.d.ts.map +1 -1
- package/dist/move-path.js +101 -17
- package/dist/native/darwin-arm64/fs-safe-native.node +0 -0
- package/dist/native/darwin-x64/fs-safe-native.node +0 -0
- package/dist/native/linux-arm64-gnu/fs-safe-native.node +0 -0
- package/dist/native/linux-arm64-musl/fs-safe-native.node +0 -0
- package/dist/native/linux-x64-gnu/fs-safe-native.node +0 -0
- package/dist/native/linux-x64-musl/fs-safe-native.node +0 -0
- package/dist/native/win32-x64-msvc/fs-safe-native.node +0 -0
- package/dist/native-binding.d.ts +79 -0
- package/dist/native-binding.d.ts.map +1 -0
- package/dist/native-binding.js +1 -0
- package/dist/native-config.d.ts +17 -0
- package/dist/native-config.d.ts.map +1 -0
- package/dist/native-config.js +71 -0
- package/dist/native-operations.d.ts +21 -0
- package/dist/native-operations.d.ts.map +1 -0
- package/dist/native-operations.js +115 -0
- package/dist/native-pinned-write.d.ts +5 -0
- package/dist/native-pinned-write.d.ts.map +1 -0
- package/dist/native-pinned-write.js +115 -0
- package/dist/native.d.ts +14 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +204 -0
- package/dist/output-sibling.d.ts +8 -0
- package/dist/output-sibling.d.ts.map +1 -0
- package/dist/output-sibling.js +122 -0
- package/dist/output.d.ts +2 -0
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +32 -5
- package/dist/owner-dacl.d.ts +31 -0
- package/dist/owner-dacl.d.ts.map +1 -0
- package/dist/owner-dacl.js +27 -0
- package/dist/path-policy.js +1 -1
- package/dist/path.d.ts.map +1 -1
- package/dist/path.js +3 -2
- package/dist/permissions-public.d.ts +2 -0
- package/dist/permissions-public.d.ts.map +1 -1
- package/dist/permissions-public.js +2 -0
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +6 -0
- package/dist/pinned-operation.d.ts +2 -0
- package/dist/pinned-operation.d.ts.map +1 -0
- package/dist/pinned-operation.js +35 -0
- package/dist/pinned-write.d.ts +3 -16
- package/dist/pinned-write.d.ts.map +1 -1
- package/dist/pinned-write.js +20 -85
- package/dist/private-directory.d.ts +5 -0
- package/dist/private-directory.d.ts.map +1 -0
- package/dist/private-directory.js +13 -0
- package/dist/private-temp-workspace.d.ts +6 -2
- package/dist/private-temp-workspace.d.ts.map +1 -1
- package/dist/private-temp-workspace.js +40 -13
- package/dist/publish-file-failure.d.ts +27 -0
- package/dist/publish-file-failure.d.ts.map +1 -0
- package/dist/publish-file-failure.js +21 -0
- package/dist/publish-file.d.ts +21 -0
- package/dist/publish-file.d.ts.map +1 -0
- package/dist/publish-file.js +351 -0
- package/dist/read-opened-file.d.ts +3 -0
- package/dist/read-opened-file.d.ts.map +1 -1
- package/dist/read-opened-file.js +1 -0
- package/dist/replace-file-copy-fallback.d.ts +34 -0
- package/dist/replace-file-copy-fallback.d.ts.map +1 -0
- package/dist/replace-file-copy-fallback.js +339 -0
- package/dist/replace-file.d.ts +6 -2
- package/dist/replace-file.d.ts.map +1 -1
- package/dist/replace-file.js +39 -90
- package/dist/root-context.d.ts +4 -1
- package/dist/root-context.d.ts.map +1 -1
- package/dist/root-context.js +20 -1
- package/dist/root-impl.d.ts +5 -0
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +128 -225
- package/dist/root-path-existing.d.ts +3 -0
- package/dist/root-path-existing.d.ts.map +1 -0
- package/dist/root-path-existing.js +69 -0
- package/dist/root-path.d.ts +1 -2
- package/dist/root-path.d.ts.map +1 -1
- package/dist/root-path.js +67 -81
- package/dist/root-walk.d.ts +41 -0
- package/dist/root-walk.d.ts.map +1 -0
- package/dist/root-walk.js +114 -0
- package/dist/root.d.ts +2 -0
- package/dist/root.d.ts.map +1 -1
- package/dist/safe-path-segment.d.ts.map +1 -1
- package/dist/safe-path-segment.js +16 -4
- package/dist/secret-file.d.ts +5 -2
- package/dist/secret-file.d.ts.map +1 -1
- package/dist/secret-file.js +20 -2
- package/dist/secret-read-async.d.ts +4 -0
- package/dist/secret-read-async.d.ts.map +1 -0
- package/dist/secret-read-async.js +95 -0
- package/dist/secret.d.ts +2 -1
- package/dist/secret.d.ts.map +1 -1
- package/dist/secret.js +2 -1
- package/dist/sibling-temp.d.ts.map +1 -1
- package/dist/sibling-temp.js +1 -0
- package/dist/sidecar-lock-handle.d.ts +20 -0
- package/dist/sidecar-lock-handle.d.ts.map +1 -0
- package/dist/sidecar-lock-handle.js +28 -0
- package/dist/sidecar-lock-policy.d.ts +10 -0
- package/dist/sidecar-lock-policy.d.ts.map +1 -0
- package/dist/sidecar-lock-policy.js +29 -0
- package/dist/sidecar-lock-reclaim.d.ts +22 -6
- package/dist/sidecar-lock-reclaim.d.ts.map +1 -1
- package/dist/sidecar-lock-reclaim.js +106 -20
- package/dist/sidecar-lock-types.d.ts +56 -0
- package/dist/sidecar-lock-types.d.ts.map +1 -0
- package/dist/sidecar-lock-types.js +1 -0
- package/dist/sidecar-lock.d.ts +2 -45
- package/dist/sidecar-lock.d.ts.map +1 -1
- package/dist/sidecar-lock.js +94 -55
- package/dist/temp-cleanup.d.ts +7 -1
- package/dist/temp-cleanup.d.ts.map +1 -1
- package/dist/temp-cleanup.js +35 -5
- package/dist/temp-target.d.ts.map +1 -1
- package/dist/temp-target.js +51 -3
- package/dist/temp.d.ts +2 -1
- package/dist/temp.d.ts.map +1 -1
- package/dist/test-hooks.d.ts +3 -0
- package/dist/test-hooks.d.ts.map +1 -1
- package/dist/windows-permissions-native.d.ts +9 -0
- package/dist/windows-permissions-native.d.ts.map +1 -0
- package/dist/windows-permissions-native.js +31 -0
- package/docs/archive.md +131 -13
- package/docs/atomic.md +30 -1
- package/docs/config.md +51 -21
- package/docs/durability.md +211 -1
- package/docs/errors.md +36 -6
- package/docs/filename.md +0 -0
- package/docs/index.md +11 -8
- package/docs/install.md +27 -26
- package/docs/json-store.md +18 -3
- package/docs/migrating-to-0.5.md +196 -0
- package/docs/native-helper.md +85 -0
- package/docs/native.md +134 -0
- package/docs/output.md +37 -11
- package/docs/path.md +1 -1
- package/docs/permissions.md +84 -1
- package/docs/quickstart.md +5 -2
- package/docs/reading.md +4 -4
- package/docs/root.md +31 -15
- package/docs/secret-file.md +50 -1
- package/docs/security-model.md +29 -8
- package/docs/sidecar-lock.md +92 -7
- package/docs/temp.md +24 -1
- package/docs/test-hooks.md +22 -2
- package/docs/testing.md +18 -7
- package/docs/types.md +3 -1
- package/docs/walk.md +55 -0
- package/docs/writing.md +3 -3
- package/package.json +10 -4
- package/dist/pinned-helper.d.ts +0 -9
- package/dist/pinned-helper.d.ts.map +0 -1
- package/dist/pinned-helper.js +0 -19
- package/dist/pinned-path.d.ts +0 -7
- package/dist/pinned-path.d.ts.map +0 -1
- package/dist/pinned-path.js +0 -21
- package/dist/pinned-python-config.d.ts +0 -9
- package/dist/pinned-python-config.d.ts.map +0 -1
- package/dist/pinned-python-config.js +0 -38
- package/dist/pinned-python.d.ts +0 -12
- package/dist/pinned-python.d.ts.map +0 -1
- package/dist/pinned-python.js +0 -688
- package/docs/python-helper.md +0 -103
package/dist/sidecar-lock.js
CHANGED
|
@@ -2,7 +2,11 @@ import fsSync from "node:fs";
|
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { sameFileIdentity } from "./file-identity.js";
|
|
5
|
-
import { readSidecarLockSnapshot, releaseSidecarReclaimGuard, removeSidecarLockIfUnchanged, removeStaleSidecarLockIfAllowed, serializeSidecarLockPayload, sidecarLockSnapshotMatches, sidecarLockSnapshotStillPresent, sidecarReclaimGuardExists, tryAcquireSidecarReclaimGuard, } from "./sidecar-lock-reclaim.js";
|
|
5
|
+
import { readSidecarLockSnapshot, relativeSidecarLockPath, releaseSidecarReclaimGuard, removeSidecarLockIfUnchanged, removeStaleSidecarLockIfAllowed, serializeSidecarLockPayload, sidecarLockSnapshotMatches, sidecarLockSnapshotStillPresent, sidecarReclaimGuardExists, tryAcquireSidecarReclaimGuard, } from "./sidecar-lock-reclaim.js";
|
|
6
|
+
import { FsSafeError } from "./errors.js";
|
|
7
|
+
import { createNativeExclusiveFile } from "./native-operations.js";
|
|
8
|
+
import { createHeldSidecarLockHandle } from "./sidecar-lock-handle.js";
|
|
9
|
+
import { computeSidecarLockDelayMs, defaultSidecarLockShouldReclaim, } from "./sidecar-lock-policy.js";
|
|
6
10
|
const GLOBAL_STATE_KEY = Symbol.for("fsSafe.sidecarLockManagers");
|
|
7
11
|
function getGlobalManagers() {
|
|
8
12
|
const globalWithState = globalThis;
|
|
@@ -28,6 +32,9 @@ function resolveManagerState(key) {
|
|
|
28
32
|
// Backfill state created by fs-safe versions that predate reclaim guards.
|
|
29
33
|
state.reclaimCleanupRegistered ??= false;
|
|
30
34
|
state.reclaimGuards ??= new Set();
|
|
35
|
+
for (const held of state.held.values()) {
|
|
36
|
+
held.refCount ??= 1;
|
|
37
|
+
}
|
|
31
38
|
}
|
|
32
39
|
return state;
|
|
33
40
|
}
|
|
@@ -83,28 +90,6 @@ async function resolveNormalizedTargetPath(targetPath) {
|
|
|
83
90
|
return resolved;
|
|
84
91
|
}
|
|
85
92
|
}
|
|
86
|
-
function computeDelayMs(retry, attempt) {
|
|
87
|
-
const minTimeout = retry.minTimeout ?? 50;
|
|
88
|
-
const maxTimeout = retry.maxTimeout ?? 1000;
|
|
89
|
-
const factor = retry.factor ?? 1;
|
|
90
|
-
const base = Math.min(maxTimeout, Math.max(minTimeout, minTimeout * factor ** attempt));
|
|
91
|
-
const jitter = retry.randomize ? 1 + Math.random() : 1;
|
|
92
|
-
return Math.min(maxTimeout, Math.round(base * jitter));
|
|
93
|
-
}
|
|
94
|
-
async function defaultShouldReclaim(params) {
|
|
95
|
-
const createdAt = typeof params.payload?.createdAt === "string" ? params.payload.createdAt : "";
|
|
96
|
-
const createdAtMs = Date.parse(createdAt);
|
|
97
|
-
if (Number.isFinite(createdAtMs) && params.nowMs - createdAtMs > params.staleMs) {
|
|
98
|
-
return true;
|
|
99
|
-
}
|
|
100
|
-
try {
|
|
101
|
-
const stat = await fs.stat(params.lockPath);
|
|
102
|
-
return params.nowMs - stat.mtimeMs > params.staleMs;
|
|
103
|
-
}
|
|
104
|
-
catch {
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
93
|
function releaseAllReclaimGuardsSync(state) {
|
|
109
94
|
for (const reclaimGuardPath of state.reclaimGuards) {
|
|
110
95
|
try {
|
|
@@ -120,7 +105,7 @@ function releaseAllLocksSync(state) {
|
|
|
120
105
|
for (const [normalizedTargetPath, held] of state.held) {
|
|
121
106
|
void held.handle.close().catch(() => undefined);
|
|
122
107
|
try {
|
|
123
|
-
if (snapshotMatchesSync(held.lockPath, held.snapshot)) {
|
|
108
|
+
if (!held.lockRoot && snapshotMatchesSync(held.lockPath, held.snapshot)) {
|
|
124
109
|
fsSync.rmSync(held.lockPath, { force: true });
|
|
125
110
|
}
|
|
126
111
|
}
|
|
@@ -131,17 +116,17 @@ function releaseAllLocksSync(state) {
|
|
|
131
116
|
}
|
|
132
117
|
releaseAllReclaimGuardsSync(state);
|
|
133
118
|
}
|
|
134
|
-
async function releaseHeldLock(state, normalizedTargetPath, held,
|
|
119
|
+
async function releaseHeldLock(state, normalizedTargetPath, held, options = {}) {
|
|
135
120
|
const current = state.held.get(normalizedTargetPath);
|
|
136
121
|
if (current !== held) {
|
|
137
122
|
return false;
|
|
138
123
|
}
|
|
139
|
-
if (
|
|
140
|
-
held.
|
|
124
|
+
if (options.force) {
|
|
125
|
+
held.refCount = 0;
|
|
141
126
|
}
|
|
142
127
|
else {
|
|
143
|
-
held.
|
|
144
|
-
if (held.
|
|
128
|
+
held.refCount -= 1;
|
|
129
|
+
if (held.refCount > 0) {
|
|
145
130
|
return false;
|
|
146
131
|
}
|
|
147
132
|
}
|
|
@@ -150,9 +135,16 @@ async function releaseHeldLock(state, normalizedTargetPath, held, opts = {}) {
|
|
|
150
135
|
return true;
|
|
151
136
|
}
|
|
152
137
|
state.held.delete(normalizedTargetPath);
|
|
138
|
+
if (held.compromiseTimer) {
|
|
139
|
+
clearInterval(held.compromiseTimer);
|
|
140
|
+
held.compromiseTimer = undefined;
|
|
141
|
+
}
|
|
153
142
|
held.releasePromise = (async () => {
|
|
154
143
|
await held.handle.close().catch(() => undefined);
|
|
155
|
-
await removeSidecarLockIfUnchanged(held.lockPath, held.snapshot
|
|
144
|
+
await removeSidecarLockIfUnchanged(held.lockPath, held.snapshot, {
|
|
145
|
+
lockRoot: held.lockRoot,
|
|
146
|
+
parsePayload: held.parsePayload,
|
|
147
|
+
});
|
|
156
148
|
})();
|
|
157
149
|
try {
|
|
158
150
|
await held.releasePromise;
|
|
@@ -162,6 +154,13 @@ async function releaseHeldLock(state, normalizedTargetPath, held, opts = {}) {
|
|
|
162
154
|
held.releasePromise = undefined;
|
|
163
155
|
}
|
|
164
156
|
}
|
|
157
|
+
function handleForHeldLock(state, normalizedTargetPath, held) {
|
|
158
|
+
return createHeldSidecarLockHandle({
|
|
159
|
+
normalizedTargetPath,
|
|
160
|
+
held,
|
|
161
|
+
release: async () => await releaseHeldLock(state, normalizedTargetPath, held),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
165
164
|
export function createSidecarLockManager(key) {
|
|
166
165
|
const state = resolveManagerState(key);
|
|
167
166
|
function ensureExitCleanupRegistered() {
|
|
@@ -181,15 +180,12 @@ export function createSidecarLockManager(key) {
|
|
|
181
180
|
const normalizedTargetPath = await resolveNormalizedTargetPath(options.targetPath);
|
|
182
181
|
const lockPath = options.lockPath ?? `${normalizedTargetPath}.lock`;
|
|
183
182
|
const held = state.held.get(normalizedTargetPath);
|
|
184
|
-
if (held &&
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
release,
|
|
191
|
-
[Symbol.asyncDispose]: release,
|
|
192
|
-
};
|
|
183
|
+
if (held &&
|
|
184
|
+
options.reentrantOwner !== undefined &&
|
|
185
|
+
held.reentrantOwner !== undefined &&
|
|
186
|
+
options.reentrantOwner === held.reentrantOwner) {
|
|
187
|
+
held.refCount += 1;
|
|
188
|
+
return handleForHeldLock(state, normalizedTargetPath, held);
|
|
193
189
|
}
|
|
194
190
|
const startedAt = Date.now();
|
|
195
191
|
const retry = options.retry ?? {};
|
|
@@ -212,7 +208,7 @@ export function createSidecarLockManager(key) {
|
|
|
212
208
|
const remaining = options.timeoutMs === undefined || options.timeoutMs === Number.POSITIVE_INFINITY
|
|
213
209
|
? Number.POSITIVE_INFINITY
|
|
214
210
|
: Math.max(0, options.timeoutMs - elapsed);
|
|
215
|
-
const delay = Math.min(
|
|
211
|
+
const delay = Math.min(computeSidecarLockDelayMs(retry, attempt), remaining);
|
|
216
212
|
attempt += 1;
|
|
217
213
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
218
214
|
};
|
|
@@ -224,18 +220,36 @@ export function createSidecarLockManager(key) {
|
|
|
224
220
|
}
|
|
225
221
|
let handle = null;
|
|
226
222
|
try {
|
|
227
|
-
handle = await fs.open(lockPath, "wx");
|
|
228
223
|
const payload = await options.payload();
|
|
229
224
|
const { raw, ownershipToken } = serializeSidecarLockPayload(payload);
|
|
230
|
-
|
|
225
|
+
if (options.lockRoot) {
|
|
226
|
+
const relativeLockPath = relativeSidecarLockPath(options.lockRoot, lockPath);
|
|
227
|
+
try {
|
|
228
|
+
await options.lockRoot.create(relativeLockPath, raw, { mkdir: true, mode: 0o600 });
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
if (error instanceof FsSafeError && error.code === "already-exists") {
|
|
232
|
+
throw Object.assign(new Error("sidecar lock exists"), { code: "EEXIST" });
|
|
233
|
+
}
|
|
234
|
+
throw error;
|
|
235
|
+
}
|
|
236
|
+
handle = (await options.lockRoot.open(relativeLockPath)).handle;
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
handle = (await createNativeExclusiveFile(lockPath, 0o600)) ?? await fs.open(lockPath, "wx");
|
|
240
|
+
await handle.writeFile(raw, "utf8");
|
|
241
|
+
}
|
|
231
242
|
const snapshot = { raw, payload, stat: await handle.stat(), ownershipToken };
|
|
232
243
|
const createdHeld = {
|
|
233
|
-
|
|
244
|
+
refCount: 1,
|
|
245
|
+
reentrantOwner: options.reentrantOwner,
|
|
234
246
|
handle,
|
|
235
247
|
lockPath,
|
|
236
248
|
snapshot,
|
|
237
249
|
acquiredAt: Date.now(),
|
|
238
250
|
metadata: options.metadata ?? {},
|
|
251
|
+
lockRoot: options.lockRoot,
|
|
252
|
+
parsePayload: options.parsePayload,
|
|
239
253
|
};
|
|
240
254
|
state.held.set(normalizedTargetPath, createdHeld);
|
|
241
255
|
if (ownsReclaimGuard) {
|
|
@@ -248,13 +262,21 @@ export function createSidecarLockManager(key) {
|
|
|
248
262
|
throw err;
|
|
249
263
|
}
|
|
250
264
|
}
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
265
|
+
const returnedHandle = handleForHeldLock(state, normalizedTargetPath, createdHeld);
|
|
266
|
+
const interval = options.compromiseCheckIntervalMs;
|
|
267
|
+
if (options.onCompromised && interval !== undefined && interval > 0) {
|
|
268
|
+
createdHeld.compromiseTimer = setInterval(() => {
|
|
269
|
+
void returnedHandle.verifyStillHeld().then((stillHeld) => {
|
|
270
|
+
if (!stillHeld && createdHeld.compromiseTimer) {
|
|
271
|
+
clearInterval(createdHeld.compromiseTimer);
|
|
272
|
+
createdHeld.compromiseTimer = undefined;
|
|
273
|
+
options.onCompromised?.({ lockPath, normalizedTargetPath });
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
}, interval);
|
|
277
|
+
createdHeld.compromiseTimer.unref();
|
|
278
|
+
}
|
|
279
|
+
return returnedHandle;
|
|
258
280
|
}
|
|
259
281
|
catch (err) {
|
|
260
282
|
if (handle) {
|
|
@@ -271,11 +293,16 @@ export function createSidecarLockManager(key) {
|
|
|
271
293
|
}
|
|
272
294
|
// If payload serialization/write fails, the file may be empty or
|
|
273
295
|
// partial JSON, so remove while our exclusive handle is still open.
|
|
274
|
-
|
|
296
|
+
if (!options.lockRoot) {
|
|
297
|
+
await fs.rm(lockPath, { force: true }).catch(() => undefined);
|
|
298
|
+
}
|
|
275
299
|
await handle.close().catch(() => undefined);
|
|
276
300
|
// Windows can refuse removing an open file; retry after close but
|
|
277
301
|
// only if the path still points at the file identity we created.
|
|
278
|
-
await removeSidecarLockIfUnchanged(lockPath, failedSnapshot
|
|
302
|
+
await removeSidecarLockIfUnchanged(lockPath, failedSnapshot, {
|
|
303
|
+
lockRoot: options.lockRoot,
|
|
304
|
+
parsePayload: options.parsePayload,
|
|
305
|
+
});
|
|
279
306
|
}
|
|
280
307
|
if (err.code !== "EEXIST") {
|
|
281
308
|
throw err;
|
|
@@ -286,11 +313,18 @@ export function createSidecarLockManager(key) {
|
|
|
286
313
|
continue;
|
|
287
314
|
}
|
|
288
315
|
const nowMs = Date.now();
|
|
289
|
-
const snapshot = await readSidecarLockSnapshot(lockPath
|
|
316
|
+
const snapshot = await readSidecarLockSnapshot(lockPath, {
|
|
317
|
+
lockRoot: options.lockRoot,
|
|
318
|
+
parsePayload: options.parsePayload,
|
|
319
|
+
});
|
|
290
320
|
if (!snapshot) {
|
|
291
321
|
continue;
|
|
292
322
|
}
|
|
293
|
-
|
|
323
|
+
if (state.held.has(normalizedTargetPath)) {
|
|
324
|
+
await waitForRetry();
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
const shouldReclaim = options.shouldReclaim ?? defaultSidecarLockShouldReclaim;
|
|
294
328
|
if (await shouldReclaim({
|
|
295
329
|
lockPath,
|
|
296
330
|
normalizedTargetPath,
|
|
@@ -299,7 +333,10 @@ export function createSidecarLockManager(key) {
|
|
|
299
333
|
nowMs,
|
|
300
334
|
heldByThisProcess: state.held.has(normalizedTargetPath),
|
|
301
335
|
})) {
|
|
302
|
-
if (!(await sidecarLockSnapshotStillPresent(lockPath, snapshot
|
|
336
|
+
if (!(await sidecarLockSnapshotStillPresent(lockPath, snapshot, {
|
|
337
|
+
lockRoot: options.lockRoot,
|
|
338
|
+
parsePayload: options.parsePayload,
|
|
339
|
+
}))) {
|
|
303
340
|
continue;
|
|
304
341
|
}
|
|
305
342
|
const staleRecovery = options.staleRecovery ?? "fail-closed";
|
|
@@ -314,6 +351,8 @@ export function createSidecarLockManager(key) {
|
|
|
314
351
|
normalizedTargetPath,
|
|
315
352
|
snapshot,
|
|
316
353
|
shouldRemoveStaleLock: options.shouldRemoveStaleLock,
|
|
354
|
+
lockRoot: options.lockRoot,
|
|
355
|
+
parsePayload: options.parsePayload,
|
|
317
356
|
});
|
|
318
357
|
if (removal === "removed" || removal === "changed") {
|
|
319
358
|
continue;
|
package/dist/temp-cleanup.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
import { type FileIdentityStat } from "./file-identity.js";
|
|
2
|
+
export type TempPathIdentityReceipt = FileIdentityStat;
|
|
3
|
+
export type TempPathRegistration = (() => void) & {
|
|
4
|
+
setIdentity(identity: FileIdentityStat): void;
|
|
5
|
+
};
|
|
1
6
|
export declare function registerTempPathForExit(tempPath: string, options?: {
|
|
2
7
|
recursive?: boolean;
|
|
3
|
-
|
|
8
|
+
identity?: FileIdentityStat;
|
|
9
|
+
}): TempPathRegistration;
|
|
4
10
|
export declare function __cleanupRegisteredTempPathsForTest(): void;
|
|
5
11
|
export declare function __cleanupRegisteredTempPathForTest(tempPath: string): void;
|
|
6
12
|
//# sourceMappingURL=temp-cleanup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"temp-cleanup.d.ts","sourceRoot":"","sources":["../src/temp-cleanup.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"temp-cleanup.d.ts","sourceRoot":"","sources":["../src/temp-cleanup.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE7E,MAAM,MAAM,uBAAuB,GAAG,gBAAgB,CAAC;AAEvD,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG;IAChD,WAAW,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC/C,CAAC;AAmCF,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAA;CAAE,GAC7D,oBAAoB,CAyBtB;AAED,wBAAgB,mCAAmC,IAAI,IAAI,CAE1D;AAED,wBAAgB,kCAAkC,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAYzE"}
|
package/dist/temp-cleanup.js
CHANGED
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
import fsSync from "node:fs";
|
|
2
|
+
import { sameFileIdentity } from "./file-identity.js";
|
|
2
3
|
const tempCleanupEntries = new Map();
|
|
3
4
|
let cleanupRegistered = false;
|
|
5
|
+
function pathStillMatchesReceipt(entry) {
|
|
6
|
+
if (!entry.identity) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
return sameFileIdentity(fsSync.lstatSync(entry.path), entry.identity);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
return error.code === "ENOENT";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
4
16
|
function cleanupRegisteredTempPathsSync() {
|
|
5
17
|
for (const entry of tempCleanupEntries.values()) {
|
|
6
18
|
try {
|
|
7
|
-
|
|
19
|
+
if (pathStillMatchesReceipt(entry)) {
|
|
20
|
+
fsSync.rmSync(entry.path, { force: true, recursive: entry.recursive });
|
|
21
|
+
}
|
|
8
22
|
}
|
|
9
23
|
catch {
|
|
10
24
|
// Process-exit cleanup is best-effort.
|
|
@@ -17,13 +31,27 @@ export function registerTempPathForExit(tempPath, options) {
|
|
|
17
31
|
cleanupRegistered = true;
|
|
18
32
|
process.once("exit", cleanupRegisteredTempPathsSync);
|
|
19
33
|
}
|
|
20
|
-
|
|
34
|
+
const entry = {
|
|
21
35
|
path: tempPath,
|
|
22
36
|
recursive: options?.recursive === true,
|
|
23
|
-
|
|
24
|
-
|
|
37
|
+
identity: options?.identity,
|
|
38
|
+
};
|
|
39
|
+
if (!entry.identity) {
|
|
40
|
+
try {
|
|
41
|
+
entry.identity = fsSync.lstatSync(tempPath);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Callers that register before creation set the identity after opening.
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
tempCleanupEntries.set(tempPath, entry);
|
|
48
|
+
const unregister = (() => {
|
|
25
49
|
tempCleanupEntries.delete(tempPath);
|
|
50
|
+
});
|
|
51
|
+
unregister.setIdentity = (identity) => {
|
|
52
|
+
entry.identity = identity;
|
|
26
53
|
};
|
|
54
|
+
return unregister;
|
|
27
55
|
}
|
|
28
56
|
export function __cleanupRegisteredTempPathsForTest() {
|
|
29
57
|
cleanupRegisteredTempPathsSync();
|
|
@@ -34,7 +62,9 @@ export function __cleanupRegisteredTempPathForTest(tempPath) {
|
|
|
34
62
|
return;
|
|
35
63
|
}
|
|
36
64
|
try {
|
|
37
|
-
|
|
65
|
+
if (pathStillMatchesReceipt(entry)) {
|
|
66
|
+
fsSync.rmSync(entry.path, { force: true, recursive: entry.recursive });
|
|
67
|
+
}
|
|
38
68
|
}
|
|
39
69
|
finally {
|
|
40
70
|
tempCleanupEntries.delete(tempPath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"temp-target.d.ts","sourceRoot":"","sources":["../src/temp-target.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,QAAQ,GAAG;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;
|
|
1
|
+
{"version":3,"file":"temp-target.d.ts","sourceRoot":"","sources":["../src/temp-target.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,QAAQ,GAAG;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AA0EF,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI7D;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,MAAM,CAaT;AAyBD,wBAAsB,QAAQ,CAAC,MAAM,EAAE;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC3C,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqBpB;AAED,wBAAsB,YAAY,CAAC,CAAC,EAClC,MAAM,EAAE;IACN,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC3C,EACD,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAClC,OAAO,CAAC,CAAC,CAAC,CAOZ"}
|
package/dist/temp-target.js
CHANGED
|
@@ -4,8 +4,56 @@ import path from "node:path";
|
|
|
4
4
|
import { assertSafePathSegment, sanitizeSafePathSegment } from "./safe-path-segment.js";
|
|
5
5
|
import { resolveSecureTempRoot } from "./secure-temp-dir.js";
|
|
6
6
|
import { registerTempPathForExit } from "./temp-cleanup.js";
|
|
7
|
+
const HYPHEN_CHAR_CODE = 0x2d;
|
|
8
|
+
const DOT_CHAR_CODE = 0x2e;
|
|
9
|
+
const NUMBER_ZERO_CHAR_CODE = 0x30;
|
|
10
|
+
const NUMBER_NINE_CHAR_CODE = 0x39;
|
|
11
|
+
const UPPERCASE_A_CHAR_CODE = 0x41;
|
|
12
|
+
const UPPERCASE_Z_CHAR_CODE = 0x5a;
|
|
13
|
+
const UNDERSCORE_CHAR_CODE = 0x5f;
|
|
14
|
+
const LOWERCASE_A_CHAR_CODE = 0x61;
|
|
15
|
+
const LOWERCASE_Z_CHAR_CODE = 0x7a;
|
|
16
|
+
function trimHyphenEdges(value) {
|
|
17
|
+
let start = 0;
|
|
18
|
+
let end = value.length;
|
|
19
|
+
while (start < end && value.charCodeAt(start) === HYPHEN_CHAR_CODE) {
|
|
20
|
+
start += 1;
|
|
21
|
+
}
|
|
22
|
+
while (end > start && value.charCodeAt(end - 1) === HYPHEN_CHAR_CODE) {
|
|
23
|
+
end -= 1;
|
|
24
|
+
}
|
|
25
|
+
return start === 0 && end === value.length ? value : value.slice(start, end);
|
|
26
|
+
}
|
|
27
|
+
function isExtensionCharCode(charCode) {
|
|
28
|
+
return ((charCode >= NUMBER_ZERO_CHAR_CODE && charCode <= NUMBER_NINE_CHAR_CODE) ||
|
|
29
|
+
(charCode >= UPPERCASE_A_CHAR_CODE && charCode <= UPPERCASE_Z_CHAR_CODE) ||
|
|
30
|
+
(charCode >= LOWERCASE_A_CHAR_CODE && charCode <= LOWERCASE_Z_CHAR_CODE) ||
|
|
31
|
+
charCode === DOT_CHAR_CODE ||
|
|
32
|
+
charCode === UNDERSCORE_CHAR_CODE ||
|
|
33
|
+
charCode === HYPHEN_CHAR_CODE);
|
|
34
|
+
}
|
|
35
|
+
function trailingExtensionChars(value) {
|
|
36
|
+
let start = value.length;
|
|
37
|
+
while (start > 0 && isExtensionCharCode(value.charCodeAt(start - 1))) {
|
|
38
|
+
start -= 1;
|
|
39
|
+
}
|
|
40
|
+
return start === value.length ? "" : value.slice(start);
|
|
41
|
+
}
|
|
42
|
+
function trimLeadingExtensionPunctuation(value) {
|
|
43
|
+
let start = 0;
|
|
44
|
+
while (start < value.length) {
|
|
45
|
+
const charCode = value.charCodeAt(start);
|
|
46
|
+
if (charCode !== DOT_CHAR_CODE &&
|
|
47
|
+
charCode !== UNDERSCORE_CHAR_CODE &&
|
|
48
|
+
charCode !== HYPHEN_CHAR_CODE) {
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
start += 1;
|
|
52
|
+
}
|
|
53
|
+
return start === 0 ? value : value.slice(start);
|
|
54
|
+
}
|
|
7
55
|
function sanitizePrefix(prefix) {
|
|
8
|
-
const normalized = prefix.replace(/[^a-zA-Z0-9_-]+/g, "-")
|
|
56
|
+
const normalized = trimHyphenEdges(prefix.replace(/[^a-zA-Z0-9_-]+/g, "-"));
|
|
9
57
|
return normalized || "tmp";
|
|
10
58
|
}
|
|
11
59
|
function sanitizeExtension(extension) {
|
|
@@ -13,8 +61,8 @@ function sanitizeExtension(extension) {
|
|
|
13
61
|
return "";
|
|
14
62
|
}
|
|
15
63
|
const normalized = extension.startsWith(".") ? extension : `.${extension}`;
|
|
16
|
-
const suffix = normalized
|
|
17
|
-
const token = suffix
|
|
64
|
+
const suffix = trailingExtensionChars(normalized);
|
|
65
|
+
const token = trimLeadingExtensionPunctuation(suffix);
|
|
18
66
|
return token ? `.${token}` : "";
|
|
19
67
|
}
|
|
20
68
|
export function sanitizeTempFileName(fileName) {
|
package/dist/temp.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { tempWorkspace, type TempWorkspace, type TempWorkspaceOptions, tempWorkspaceSync, type TempWorkspaceSync, withTempWorkspace, withTempWorkspaceSync, } from "./private-temp-workspace.js";
|
|
1
|
+
export { tempWorkspace, type TempWorkspace, type TempWorkspaceOptions, type TempWorkspaceCleanupResult, tempWorkspaceSync, type TempWorkspaceSync, withTempWorkspace, withTempWorkspaceSync, } from "./private-temp-workspace.js";
|
|
2
|
+
export type { TempPathIdentityReceipt } from "./temp-cleanup.js";
|
|
2
3
|
export { resolveSecureTempRoot, type ResolveSecureTempRootOptions } from "./secure-temp-dir.js";
|
|
3
4
|
//# sourceMappingURL=temp.d.ts.map
|
package/dist/temp.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"temp.d.ts","sourceRoot":"","sources":["../src/temp.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,iBAAiB,EACjB,KAAK,iBAAiB,EACtB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,qBAAqB,EAAE,KAAK,4BAA4B,EAAE,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"temp.d.ts","sourceRoot":"","sources":["../src/temp.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,iBAAiB,EACjB,KAAK,iBAAiB,EACtB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,KAAK,4BAA4B,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/test-hooks.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FileHandle } from "node:fs/promises";
|
|
2
|
+
import type { FileIdentityStat } from "./file-identity.js";
|
|
2
3
|
export type FsSafeTestHooks = {
|
|
3
4
|
afterPreOpenLstat?: (filePath: string) => Promise<void> | void;
|
|
4
5
|
beforeOpen?: (filePath: string, flags: number) => Promise<void> | void;
|
|
@@ -10,6 +11,8 @@ export type FsSafeTestHooks = {
|
|
|
10
11
|
afterPinnedWriteFallbackRename?: (targetPath: string) => Promise<void> | void;
|
|
11
12
|
beforeSiblingTempWrite?: (tempPath: string) => Promise<void> | void;
|
|
12
13
|
beforeTrashMove?: (targetPath: string, destPath: string) => void;
|
|
14
|
+
afterPublishTargetCreated?: (method: "hardlink" | "exclusive-copy" | "rename-noreplace", targetPath: string, identity: FileIdentityStat) => Promise<void> | void;
|
|
15
|
+
beforePublishDirectorySync?: (method: "hardlink" | "exclusive-copy" | "rename-noreplace", targetPath: string, identity: FileIdentityStat) => Promise<void> | void;
|
|
13
16
|
};
|
|
14
17
|
export declare function getFsSafeTestHooks(): FsSafeTestHooks | undefined;
|
|
15
18
|
export declare function __setFsSafeTestHooksForTest(hooks?: FsSafeTestHooks): void;
|
package/dist/test-hooks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-hooks.d.ts","sourceRoot":"","sources":["../src/test-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"test-hooks.d.ts","sourceRoot":"","sources":["../src/test-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,MAAM,MAAM,eAAe,GAAG;IAC5B,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC/D,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACvE,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC3E,2BAA2B,CAAC,EAAE,CAC5B,SAAS,EAAE,OAAO,GAAG,OAAO,EAC5B,UAAU,EAAE,MAAM,KACf,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1B,2BAA2B,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACxE,+BAA+B,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,0BAA0B,CAAC,EAAE,CAC3B,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,EACtC,UAAU,EAAE,MAAM,KACf,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1B,8BAA8B,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9E,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACpE,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE,yBAAyB,CAAC,EAAE,CAC1B,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,kBAAkB,EAC1D,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,gBAAgB,KACvB,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1B,0BAA0B,CAAC,EAAE,CAC3B,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,kBAAkB,EAC1D,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,gBAAgB,KACvB,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC3B,CAAC;AAQF,wBAAgB,kBAAkB,IAAI,eAAe,GAAG,SAAS,CAEhE;AAED,wBAAgB,2BAA2B,CAAC,KAAK,CAAC,EAAE,eAAe,GAAG,IAAI,CAKzE"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PermissionCheck, SafeStatResult } from "./permissions.js";
|
|
2
|
+
export declare function inspectWindowsPermissionsNative(params: {
|
|
3
|
+
targetPath: string;
|
|
4
|
+
stat: SafeStatResult;
|
|
5
|
+
effectiveIsDir: boolean;
|
|
6
|
+
effectiveMode: number | null;
|
|
7
|
+
bits: number | null;
|
|
8
|
+
}): PermissionCheck | undefined;
|
|
9
|
+
//# sourceMappingURL=windows-permissions-native.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windows-permissions-native.d.ts","sourceRoot":"","sources":["../src/windows-permissions-native.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAExE,wBAAgB,+BAA+B,CAAC,MAAM,EAAE;IACtD,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,cAAc,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,GAAG,eAAe,GAAG,SAAS,CA2B9B"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { getNativeBinding } from "./native.js";
|
|
2
|
+
export function inspectWindowsPermissionsNative(params) {
|
|
3
|
+
const native = getNativeBinding();
|
|
4
|
+
if (!native)
|
|
5
|
+
return undefined;
|
|
6
|
+
try {
|
|
7
|
+
const facts = native.readOwnerAndDacl(params.targetPath);
|
|
8
|
+
if (facts.fallbackRequired)
|
|
9
|
+
return undefined;
|
|
10
|
+
return {
|
|
11
|
+
ok: true,
|
|
12
|
+
isSymlink: params.stat.isSymlink,
|
|
13
|
+
isDir: params.effectiveIsDir,
|
|
14
|
+
mode: params.effectiveMode,
|
|
15
|
+
bits: params.bits,
|
|
16
|
+
source: "windows-acl",
|
|
17
|
+
worldWritable: facts.worldWritable,
|
|
18
|
+
groupWritable: facts.groupWritable,
|
|
19
|
+
worldReadable: facts.worldReadable,
|
|
20
|
+
groupReadable: facts.groupReadable,
|
|
21
|
+
ownerSid: facts.ownerSid,
|
|
22
|
+
ownerTrusted: facts.ownerClass !== "foreign",
|
|
23
|
+
aclSummary: `native owner=${facts.ownerClass} world=` +
|
|
24
|
+
`${facts.worldReadable ? "r" : "-"}${facts.worldWritable ? "w" : "-"} ` +
|
|
25
|
+
`group=${facts.groupReadable ? "r" : "-"}${facts.groupWritable ? "w" : "-"}`,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|