@openclaw/fs-safe 0.18.0 → 0.18.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 (145) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/advanced.d.ts +2 -1
  3. package/dist/archive-durability.d.ts +1 -1
  4. package/dist/archive-parser.wasm +0 -0
  5. package/dist/archive-plan.d.ts +64 -3
  6. package/dist/archive-plan.js +55 -1
  7. package/dist/archive-tar-wasm.d.ts +1 -1
  8. package/dist/archive-zip-directory.d.ts +1 -1
  9. package/dist/archive-zip-entry.d.ts +1 -1
  10. package/dist/archive-zip-entry.js +1 -1
  11. package/dist/archive.d.ts +8 -5
  12. package/dist/archive.js +122 -9
  13. package/dist/atomic.d.ts +3 -1
  14. package/dist/copy-publication.d.ts +1 -1
  15. package/dist/create.d.ts +16 -2
  16. package/dist/create.js +388 -2
  17. package/dist/creation-boundary.d.ts +60 -0
  18. package/dist/creation-boundary.js +371 -0
  19. package/dist/directory-mode-node.js +12 -2
  20. package/dist/durability.d.ts +2 -1
  21. package/dist/file-lock-sync-acquisition.js +2 -2
  22. package/dist/file-lock-sync-root-acquire.js +2 -6
  23. package/dist/file-lock-sync-root.d.ts +2 -1
  24. package/dist/file-lock-sync-stale-admission.js +3 -10
  25. package/dist/file-lock-sync.d.ts +4 -21
  26. package/dist/file-store-boundary.d.ts +7 -0
  27. package/dist/file-store-boundary.js +58 -1
  28. package/dist/file-store-sync-write.js +2 -3
  29. package/dist/file-store.js +1 -6
  30. package/dist/guarded-mkdir.d.ts +1 -1
  31. package/dist/index.d.ts +9 -6
  32. package/dist/json-durable-queue-read.js +7 -3
  33. package/dist/json-durable-queue.js +1 -2
  34. package/dist/json-store.js +1 -2
  35. package/dist/json.js +1 -2
  36. package/dist/move-path.js +1 -2
  37. package/dist/native-operations.js +0 -1
  38. package/dist/native-pinned-write-windows.d.ts +1 -1
  39. package/dist/native-pinned-write-windows.js +1 -1
  40. package/dist/native-pinned-write.d.ts +1 -1
  41. package/dist/native-pinned-write.js +3 -6
  42. package/dist/native-policy-parent-windows.d.ts +1 -1
  43. package/dist/native-staged-file.d.ts +2 -2
  44. package/dist/native-staged-file.js +1 -2
  45. package/dist/pinned-mutation-admission.d.ts +1 -1
  46. package/dist/pinned-open.js +6 -1
  47. package/dist/pinned-operation.d.ts +1 -1
  48. package/dist/pinned-operation.js +3 -16
  49. package/dist/pinned-write-mode.js +1 -1
  50. package/dist/pinned-write-staged.js +1 -2
  51. package/dist/pinned-write.d.ts +0 -1
  52. package/dist/pinned-write.js +3 -5
  53. package/dist/private-producer-handoff-sync.d.ts +2 -12
  54. package/dist/private-producer-handoff-sync.js +1 -1
  55. package/dist/private-producer-handoff.d.ts +3 -3
  56. package/dist/private-temp-workspace.js +1 -2
  57. package/dist/publish-copy-stage.d.ts +1 -1
  58. package/dist/publish-file.d.ts +0 -1
  59. package/dist/publish-file.js +1 -2
  60. package/dist/replace-directory.js +1 -2
  61. package/dist/replace-file-rename-policy.d.ts +1 -2
  62. package/dist/replace-file.d.ts +3 -3
  63. package/dist/replace-file.js +1 -1
  64. package/dist/root-context.js +3 -7
  65. package/dist/root-create-input.d.ts +1 -1
  66. package/dist/root-directory-creation.d.ts +1 -1
  67. package/dist/root-directory-creation.js +1 -1
  68. package/dist/root-directory-list.js +3 -7
  69. package/dist/root-entries.js +2 -2
  70. package/dist/root-errors.d.ts +4 -0
  71. package/dist/root-errors.js +5 -3
  72. package/dist/root-impl.d.ts +0 -5
  73. package/dist/root-impl.js +22 -21
  74. package/dist/root-move-noreplace.js +4 -10
  75. package/dist/root-observed-path.js +2 -4
  76. package/dist/root-options.d.ts +1 -1
  77. package/dist/root-path-existing.js +2 -3
  78. package/dist/root-path-stat.js +2 -4
  79. package/dist/root-public-types.d.ts +11 -0
  80. package/dist/root-remove-identity.js +2 -4
  81. package/dist/root-remove.js +2 -4
  82. package/dist/root-write-admission.d.ts +1 -1
  83. package/dist/root-write-admission.js +3 -7
  84. package/dist/root-write-complete-parent.js +2 -3
  85. package/dist/root-write-verification.d.ts +1 -1
  86. package/dist/root.d.ts +2 -6
  87. package/dist/secret-file.js +0 -1
  88. package/dist/secure-temp-repair.js +5 -1
  89. package/dist/sidecar-lock-acquire.js +7 -10
  90. package/dist/sidecar-lock-policy.d.ts +1 -0
  91. package/dist/sidecar-lock-policy.js +7 -0
  92. package/dist/sidecar-lock-stale-admission.js +2 -6
  93. package/dist/sidecar-lock-types.d.ts +22 -16
  94. package/dist/temp-workspace-admission.js +1 -3
  95. package/dist/temp-workspace-child-admission.d.ts +16 -2
  96. package/dist/temp-workspace-child-admission.js +71 -3
  97. package/dist/temp-workspace-descriptor.d.ts +1 -1
  98. package/dist/temp-workspace-descriptor.js +1 -2
  99. package/dist/text-atomic.js +1 -1
  100. package/dist/windows-owner.js +1 -1
  101. package/dist/windows-path-alias.d.ts +1 -0
  102. package/dist/windows-path-alias.js +5 -0
  103. package/docs/advanced.md +3 -1
  104. package/docs/secret-file.md +4 -0
  105. package/docs/sidecar-lock.md +4 -0
  106. package/docs/store.md +6 -0
  107. package/docs/temp.md +8 -1
  108. package/docs/writing.md +5 -0
  109. package/package.json +8 -8
  110. package/dist/archive-native.d.ts +0 -10
  111. package/dist/archive-native.js +0 -73
  112. package/dist/archive-options.d.ts +0 -30
  113. package/dist/archive-policy.d.ts +0 -21
  114. package/dist/archive-policy.js +0 -38
  115. package/dist/archive-tar-inspect.d.ts +0 -6
  116. package/dist/archive-tar-inspect.js +0 -62
  117. package/dist/archive-tar.d.ts +0 -18
  118. package/dist/archive-tar.js +0 -21
  119. package/dist/create-directory.d.ts +0 -18
  120. package/dist/create-directory.js +0 -111
  121. package/dist/create-file-async.d.ts +0 -6
  122. package/dist/create-file-async.js +0 -121
  123. package/dist/create-file.d.ts +0 -7
  124. package/dist/create-file.js +0 -179
  125. package/dist/creation-darwin.d.ts +0 -5
  126. package/dist/creation-darwin.js +0 -70
  127. package/dist/creation-file-state.d.ts +0 -18
  128. package/dist/creation-file-state.js +0 -118
  129. package/dist/creation-path.d.ts +0 -22
  130. package/dist/creation-path.js +0 -83
  131. package/dist/creation-permissions.d.ts +0 -18
  132. package/dist/creation-permissions.js +0 -115
  133. package/dist/file-store-copy-source.d.ts +0 -4
  134. package/dist/file-store-copy-source.js +0 -31
  135. package/dist/file-store-limit.d.ts +0 -1
  136. package/dist/file-store-limit.js +0 -7
  137. package/dist/file-store-path.d.ts +0 -2
  138. package/dist/file-store-path.js +0 -30
  139. package/dist/standalone-publication-path.d.ts +0 -1
  140. package/dist/standalone-publication-path.js +0 -6
  141. package/dist/temp-workspace-identity.d.ts +0 -14
  142. package/dist/temp-workspace-identity.js +0 -41
  143. package/dist/temp-workspace-permissions.d.ts +0 -3
  144. package/dist/temp-workspace-permissions.js +0 -32
  145. /package/dist/{archive-options.js → root-public-types.js} +0 -0
package/dist/root-impl.js CHANGED
@@ -56,7 +56,7 @@ import fs from "node:fs/promises";
56
56
  import path from "node:path";
57
57
  import { normalizeMaxBytes } from "./byte-budget.js";
58
58
  import { assertCopySourceCurrent, resolveFileCopyCloneMode } from "./copy-file-input.js";
59
- import { assertPrivateFileCreationAvailable, resolveCreationPermissions } from "./creation-permissions.js";
59
+ import { assertPrivateFileCreationAvailable, resolveCreationPermissions } from "./creation-boundary.js";
60
60
  import { assertAsyncDirectoryGuard, assertSyncDirectoryGuard, createAsyncDirectoryGuard, createNearestExistingDirectoryGuard } from "./directory-guard.js";
61
61
  import { FsSafeError } from "./errors.js";
62
62
  import { syncDirectoryBestEffort } from "./directory-durability.js";
@@ -68,7 +68,7 @@ import { openedPathResolutionError, recordExclusiveCreateFailure, recordOpenedFi
68
68
  import { runPinnedWriteHelper, runPinnedWriteWithRenamePolicy } from "./pinned-write.js";
69
69
  import { preparePinnedWriteMutationAdmission, snapshotPinnedMutationPolicy } from "./pinned-mutation-admission.js";
70
70
  import { getNativeBinding } from "./native.js";
71
- import { validatePinnedOperationPayload } from "./pinned-operation.js";
71
+ import { validatePinnedRelativePath } from "./pinned-operation.js";
72
72
  import { PATH_ALIAS_POLICIES } from "./path-policy.js";
73
73
  import { assertNoNulPathInput, hasNodeErrorCode, isNotFoundPathError, isSymlinkOpenError, } from "./path.js";
74
74
  import { readOpenedFileSafely } from "./read-opened-file.js";
@@ -86,7 +86,7 @@ import { statResolvedPathInRoot } from "./root-path-stat.js";
86
86
  import { entriesInRoot } from "./root-entries.js";
87
87
  import { assertMoveMutationAllowed } from "./root-move-preflight.js";
88
88
  import { assertRootIdentityCurrent, assertRootIdentityCurrentSync, assertValidRootDestinationPath, assertValidRootRelativePath, ensureTrailingSep, expandRelativePathWithHome, resolvePathInRoot, resolveRootContext, rootRelativeReadPath, } from "./root-context.js";
89
- import { fileNotFoundError, hardlinkedPathNotAllowedError, isAlreadyExistsError, normalizePinnedPathError, normalizePinnedWriteError, outsideWorkspaceError, } from "./root-errors.js";
89
+ import { errorCauseOptions, fileNotFoundError, hardlinkedPathNotAllowedError, isAlreadyExistsError, normalizePinnedPathError, normalizePinnedWriteError, outsideWorkspaceError, } from "./root-errors.js";
90
90
  import { getFsSafeTestHooks } from "./test-hooks.js";
91
91
  import { stringifyJsonDocument } from "./json-stringify.js";
92
92
  import { walkRoot } from "./root-walk.js";
@@ -304,6 +304,9 @@ export class RootHandle {
304
304
  mode: this.defaults.mode,
305
305
  renameIdentity: this.defaults.renameIdentity,
306
306
  ...this.mutationOptions(options),
307
+ atomic: undefined,
308
+ private: undefined,
309
+ strictFileSync: undefined,
307
310
  relativePath,
308
311
  data,
309
312
  durable: options.durable ?? this.defaults.durable ?? true,
@@ -364,18 +367,19 @@ export class RootHandle {
364
367
  }
365
368
  async stat(relativePath) {
366
369
  assertValidRootRelativePath(relativePath);
367
- validatePinnedOperationPayload({ relativePath });
370
+ validatePinnedRelativePath(relativePath);
368
371
  return await statPathFallback(this.context, relativePath);
369
372
  }
370
373
  async list(relativePath, options = {}) {
371
374
  assertValidRootRelativePath(relativePath);
372
- validatePinnedOperationPayload({ relativePath });
375
+ validatePinnedRelativePath(relativePath);
373
376
  return await listPathFallback(this.context, relativePath, options.withFileTypes === true);
374
377
  }
375
378
  async move(fromRelative, toRelative, options = {}) {
376
379
  assertValidRootRelativePath(fromRelative);
377
380
  assertValidRootDestinationPath(toRelative);
378
- validatePinnedOperationPayload({ from: fromRelative, to: toRelative });
381
+ validatePinnedRelativePath(fromRelative);
382
+ validatePinnedRelativePath(toRelative);
379
383
  const mutationOptions = this.mutationOptions(options);
380
384
  const { assertBeforeMutation } = mutationOptions;
381
385
  const { denyMutations, mutationSymlinks } = snapshotPinnedMutationPolicy(mutationOptions.denyMutations, mutationOptions.mutationSymlinks) ?? {};
@@ -407,7 +411,7 @@ export class RootHandle {
407
411
  rootReal: this.context.rootReal,
408
412
  stat: relative => this.stat(relative),
409
413
  list: async (relative, listingOptions) => {
410
- validatePinnedOperationPayload({ relativePath: relative });
414
+ validatePinnedRelativePath(relative);
411
415
  const resolved = await resolvePinnedPathInRoot(this.context, { relativePath: relative, allowRoot: true });
412
416
  return await openRootDirectoryListing(this.context, resolved.resolved, listingOptions);
413
417
  },
@@ -503,7 +507,6 @@ async function openWritableFileInRoot(root, params, options) {
503
507
  relativePath: params.relativePath, guardedTarget, mkdir: params.mkdir,
504
508
  assertBeforeMutation: params.assertBeforeMutation,
505
509
  }) : undefined;
506
- const mutationAdmission = prepared?.mutationAdmission;
507
510
  const preparedParent = prepared?.preparedParent;
508
511
  let ioPath = prepared?.targetPath ?? (params.mkdir === false ? resolved :
509
512
  await prepareRootWriteTarget(root, resolved, params.assertBeforeMutation));
@@ -763,7 +766,7 @@ async function appendFileInRoot(root, params) {
763
766
  }
764
767
  }
765
768
  async function removePathInRoot(root, params) {
766
- validatePinnedOperationPayload({ relativePath: params.relativePath });
769
+ validatePinnedRelativePath(params.relativePath);
767
770
  const removalReceipts = params.recursive ? undefined : new RemovalPathReceipts();
768
771
  const resolved = await resolvePinnedPathInRoot(root, {
769
772
  relativePath: params.relativePath,
@@ -783,7 +786,7 @@ async function removePathInRoot(root, params) {
783
786
  }
784
787
  async function mkdirPathInRoot(root, params) {
785
788
  const privateMode = resolveCreationPermissions(params, true).private;
786
- validatePinnedOperationPayload({ relativePath: params.relativePath });
789
+ validatePinnedRelativePath(params.relativePath);
787
790
  const policy = params.denyMutations === undefined && params.mutationSymlinks === undefined
788
791
  ? undefined
789
792
  : snapshotPinnedMutationPolicy(params.denyMutations, params.mutationSymlinks);
@@ -862,7 +865,7 @@ async function commitPinnedWriteInRoot(root, pinned, params, input) {
862
865
  overwrite: params.overwrite,
863
866
  rejectFinalSymlink: params.mutationSymlinks !== undefined,
864
867
  input,
865
- maxBytes: params.maxBytes,
868
+ maxBytes: input.kind === "buffer" ? undefined : params.maxBytes,
866
869
  rootIdentity: root.rootIdentity,
867
870
  mutationAdmission: pinned.mutationAdmission,
868
871
  assertBeforeMutation: params.assertBeforeMutation,
@@ -892,9 +895,7 @@ async function commitPinnedWriteInRoot(root, pinned, params, input) {
892
895
  throw error;
893
896
  }
894
897
  if (params.overwrite === false && isAlreadyExistsError(error)) {
895
- throw new FsSafeError("already-exists", "file already exists", {
896
- cause: error instanceof Error ? error : undefined,
897
- });
898
+ throw new FsSafeError("already-exists", "file already exists", errorCauseOptions(error));
898
899
  }
899
900
  throw normalizePinnedWriteError(error);
900
901
  }
@@ -1173,9 +1174,7 @@ async function movePathFallback(root, params) {
1173
1174
  throw fileNotFoundError(error instanceof Error ? error : undefined);
1174
1175
  }
1175
1176
  if (hasNodeErrorCode(error, "EEXIST")) {
1176
- throw new FsSafeError("already-exists", "destination exists", {
1177
- cause: error instanceof Error ? error : undefined,
1178
- });
1177
+ throw new FsSafeError("already-exists", "destination exists", errorCauseOptions(error));
1179
1178
  }
1180
1179
  throw error;
1181
1180
  }
@@ -1193,7 +1192,11 @@ async function writeFileFallback(root, params) {
1193
1192
  const policy = snapshotPinnedMutationPolicy(params.denyMutations, params.mutationSymlinks);
1194
1193
  if (policy)
1195
1194
  params = { ...params, ...policy };
1196
- const { rootReal, resolved } = await resolveGuardedWritePathInRoot(root, params);
1195
+ const { rootReal, resolved } = await resolveGuardedWritePathInRoot(root, {
1196
+ relativePath: params.relativePath,
1197
+ denyMutations: params.denyMutations,
1198
+ mutationSymlinks: params.mutationSymlinks,
1199
+ });
1197
1200
  await withRootFallbackCompatibilityLock({
1198
1201
  rootPath: rootReal, rootIdentity: root.rootIdentity, targetPath: resolved, assertBeforeMutation: params.assertBeforeMutation,
1199
1202
  }, async ({ targetPath, ...binding }) => await writeFileFallbackUnlocked(root, { ...params, ...binding }, targetPath));
@@ -1422,9 +1425,7 @@ async function writeMissingFileFallback(root, params, expectedWritePath) {
1422
1425
  if (verifyingPublication)
1423
1426
  throw err;
1424
1427
  if (hasNodeErrorCode(err, "EEXIST")) {
1425
- throw new FsSafeError("already-exists", "file already exists", {
1426
- cause: err instanceof Error ? err : undefined,
1427
- });
1428
+ throw new FsSafeError("already-exists", "file already exists", errorCauseOptions(err));
1428
1429
  }
1429
1430
  throw err;
1430
1431
  }
@@ -9,7 +9,7 @@ import { isNotFoundPathError } from "./path.js";
9
9
  import { assertRootIdentityCurrent, assertRootIdentityCurrentSync } from "./root-context.js";
10
10
  import { resolveRootPathSync } from "./root-path.js";
11
11
  import { admitPathInsideRoot } from "./root-boundary.js";
12
- import { fileNotFoundError, hardlinkedPathNotAllowedError, isAlreadyExistsError, normalizePinnedPathError, outsideWorkspaceError, } from "./root-errors.js";
12
+ import { errorCauseOptions, fileNotFoundError, hardlinkedPathNotAllowedError, isAlreadyExistsError, normalizePinnedPathError, outsideWorkspaceError, } from "./root-errors.js";
13
13
  import { assertFinalSymlinkRejected } from "./root-symlink-policy.js";
14
14
  import { createSuppressedError } from "./suppressed-error.js";
15
15
  import { inspectFileIdentitySync } from "./strict-file-identity.js";
@@ -44,17 +44,13 @@ function normalizeMoveError(error) {
44
44
  return fileNotFoundError(error instanceof Error ? error : undefined);
45
45
  }
46
46
  if (nativePrimitiveUnavailable(error)) {
47
- return new FsSafeError("helper-unavailable", "native no-replace move is unavailable", {
48
- cause: error instanceof Error ? error : undefined,
49
- });
47
+ return new FsSafeError("helper-unavailable", "native no-replace move is unavailable", errorCauseOptions(error));
50
48
  }
51
49
  return error;
52
50
  }
53
51
  function normalizeRenameNoReplaceError(error) {
54
52
  if (error?.code === "EINVAL") {
55
- return new FsSafeError("helper-unavailable", "native no-replace move is unavailable on this filesystem", {
56
- cause: error instanceof Error ? error : undefined,
57
- });
53
+ return new FsSafeError("helper-unavailable", "native no-replace move is unavailable on this filesystem", errorCauseOptions(error));
58
54
  }
59
55
  return normalizeMoveError(error);
60
56
  }
@@ -157,9 +153,7 @@ export async function movePathNoReplaceNative(root, params, paths) {
157
153
  }
158
154
  catch (error) {
159
155
  if (isAlreadyExistsError(error) || error?.code === "ENOTEMPTY") {
160
- throw new FsSafeError("already-exists", "destination exists", {
161
- cause: error instanceof Error ? error : undefined,
162
- });
156
+ throw new FsSafeError("already-exists", "destination exists", errorCauseOptions(error));
163
157
  }
164
158
  throw normalizeRenameNoReplaceError(error);
165
159
  }
@@ -7,7 +7,7 @@ import { admitPathInsideRoot } from "./root-boundary.js";
7
7
  import { assertRootPathObservationReceiptCurrent } from "./root-directory-list.js";
8
8
  import { RootPathObservationError, resolveRootPathWithObservation, } from "./root-path.js";
9
9
  import { createRootObservationGuard, ensureTrailingSep, expandRelativePathWithHome, } from "./root-context.js";
10
- import { fileNotFoundError, outsideWorkspaceError } from "./root-errors.js";
10
+ import { errorCauseOptions, fileNotFoundError, outsideWorkspaceError } from "./root-errors.js";
11
11
  import { getFsSafeTestHooks } from "./test-hooks.js";
12
12
  export async function resolvePinnedObservedPathInRoot(root, relativePath, kind) {
13
13
  const rootGuard = await createRootObservationGuard(root);
@@ -50,9 +50,7 @@ export async function resolvePinnedObservedPathInRoot(root, relativePath, kind)
50
50
  if (kind === "stat") {
51
51
  throw fileNotFoundError(error.error instanceof Error ? error.error : undefined);
52
52
  }
53
- throw new FsSafeError("not-found", "directory not found", {
54
- cause: error.error instanceof Error ? error.error : undefined,
55
- });
53
+ throw new FsSafeError("not-found", "directory not found", errorCauseOptions(error.error));
56
54
  }
57
55
  throw error.error;
58
56
  }
@@ -1,5 +1,5 @@
1
1
  import type { DenyMutationPolicy } from "./deny-mutations.js";
2
- import type { RenameIdentityPolicy } from "./pinned-write.js";
2
+ import type { RenameIdentityPolicy } from "./pinned-write-types.js";
3
3
  import type { MutationSymlinkPolicy, SymlinkPolicy } from "./root-symlink-policy.js";
4
4
  import type { CopyCloneMode } from "./copy-policy.js";
5
5
  import type { RootCopyPublicationReceipt } from "./copy-publication.js";
@@ -6,6 +6,7 @@ import { isNotFoundPathError, isPathInside, isSymlinkOpenError } from "./path.js
6
6
  import { realpathSync } from "./realpath.js";
7
7
  import { assertNoWindowsPathAlias, pathForWindowsFilesystem, resolvePathFromBasePreservingWindowsRoot, resolvePathPreservingWindowsRoot, } from "./windows-path-alias.js";
8
8
  import { admitPathInsideRoot } from "./root-boundary.js";
9
+ import { errorCauseOptions } from "./root-errors.js";
9
10
  export function absolutePathWithRawSegments(candidate) {
10
11
  if (path.sep !== "\\") {
11
12
  if (path.isAbsolute(candidate))
@@ -144,9 +145,7 @@ export function resolveSymlinkHopPath(symlinkPath, mode, rejectUnresolved) {
144
145
  }
145
146
  catch (error) {
146
147
  if (isSymlinkOpenError(error) || (rejectUnresolved && isNotFoundPathError(error))) {
147
- throw new FsSafeError("symlink", "symlink path could not be resolved", {
148
- cause: error instanceof Error ? error : undefined,
149
- });
148
+ throw new FsSafeError("symlink", "symlink path could not be resolved", errorCauseOptions(error));
150
149
  }
151
150
  if (!isNotFoundPathError(error))
152
151
  throw error;
@@ -4,7 +4,7 @@ import { FsSafeError } from "./errors.js";
4
4
  import { fileObservation, recordFileObservationFailure } from "./file-observation.js";
5
5
  import { hasNodeErrorCode, isNotFoundPathError } from "./path.js";
6
6
  import { assertRootDirectoryObservationGuard, assertRootPathObservationReceiptCurrent, createRootDirectoryObservationGuard, pathStatFromStats, } from "./root-directory-list.js";
7
- import { fileNotFoundError } from "./root-errors.js";
7
+ import { errorCauseOptions, fileNotFoundError } from "./root-errors.js";
8
8
  import { inspectFileIdentitySync } from "./strict-file-identity.js";
9
9
  import { assertStatObservationSync } from "./stat-observation.js";
10
10
  import { getFsSafeTestHooks } from "./test-hooks.js";
@@ -32,9 +32,7 @@ async function captureChangedObservedFile(error, pathname, before, observed, ass
32
32
  }
33
33
  }
34
34
  async function missingObservedFileError(cause, pathname, before, assertParents, proof) {
35
- const failure = new FsSafeError("path-mismatch", "file changed during operation", {
36
- cause: cause instanceof Error ? cause : undefined,
37
- });
35
+ const failure = new FsSafeError("path-mismatch", "file changed during operation", errorCauseOptions(cause));
38
36
  if (hasNodeErrorCode(cause, "ENOENT") && before?.isFile() && !before.isSymbolicLink() &&
39
37
  (before.nlink === 1 || before.nlink === 1n)) {
40
38
  try {
@@ -0,0 +1,11 @@
1
+ export type { OpenResult, WritableOpenResult, } from "./root-impl.js";
2
+ export type { HardlinkPolicy, RootAppendOptions, RootCopyOptions, RootCopySource, RootCreateJsonOptions, RootCreateOptions, RootCreateStreamOptions, RootDefaults, RootMkdirOptions, RootMoveOptions, RootOpenOptions, RootOpenWritableOptions, RootOptions, RootReadOptions, RootRemoveOptions, RootWriteJsonOptions, RootWriteOptions, WritableOpenMode, } from "./root-options.js";
3
+ export type { DenyMutationPolicy } from "./deny-mutations.js";
4
+ export type { RenameIdentityPolicy } from "./pinned-write-types.js";
5
+ export type { MutationSymlinkPolicy, SymlinkPolicy, } from "./root-symlink-policy.js";
6
+ export type { ReadResult } from "./read-opened-file.js";
7
+ export type { RootCopyPublicationReceipt } from "./copy-publication.js";
8
+ export type { CopyCloneMode } from "./copy-policy.js";
9
+ export type { RootEntriesOptions } from "./root-entries.js";
10
+ export type { ContainmentGuarantee } from "./containment.js";
11
+ export type { RootWalkDataEntry, RootWalkDataEntryKind, RootWalkDirectoryErrorBehavior, RootWalkEntry, RootWalkEntryFilter, RootWalkEntryFilterResult, RootWalkEntryKind, RootWalkLimitBehavior, RootWalkOptions, RootWalkSymlinkPolicy, } from "./root-walk.js";
@@ -2,12 +2,10 @@ import fsSync from "node:fs";
2
2
  import { inspectDirectoryIdentitySync } from "./directory-guard.js";
3
3
  import { FsSafeError } from "./errors.js";
4
4
  import { realpathSync } from "./realpath.js";
5
- import { directoryComponentNotDirectoryError } from "./root-errors.js";
5
+ import { directoryComponentNotDirectoryError, errorCauseOptions } from "./root-errors.js";
6
6
  const MAX_SAFE_DIRECTORY_IDENTITY = BigInt(Number.MAX_SAFE_INTEGER);
7
7
  function identityMismatch(cause) {
8
- return new FsSafeError("path-mismatch", "removal ancestor identity changed or could not be verified", {
9
- cause: cause instanceof Error ? cause : undefined,
10
- });
8
+ return new FsSafeError("path-mismatch", "removal ancestor identity changed or could not be verified", errorCauseOptions(cause));
11
9
  }
12
10
  function safeIdentityNumber(value) {
13
11
  if (value < 0n || value > MAX_SAFE_DIRECTORY_IDENTITY)
@@ -8,7 +8,7 @@ import { sameFileIdentityForCleanup } from "./file-identity.js";
8
8
  import { MutationAuthorityError } from "./mutation-authority.js";
9
9
  import { isNotFoundPathError, isPathInside } from "./path.js";
10
10
  import { assertRootIdentityCurrent } from "./root-context.js";
11
- import { normalizeRemoveGuardError, normalizeRemovePathError, rootPathChangedError } from "./root-errors.js";
11
+ import { errorCauseOptions, normalizeRemoveGuardError, normalizeRemovePathError, rootPathChangedError } from "./root-errors.js";
12
12
  import { assertRemovalDirectoryCurrent, createRemovalDirectoryAssertion, } from "./root-remove-identity.js";
13
13
  import { assertFinalSymlinkRejected } from "./root-symlink-policy.js";
14
14
  import { inspectFileIdentitySync } from "./strict-file-identity.js";
@@ -44,9 +44,7 @@ function assertNotAborted(signal) {
44
44
  }
45
45
  }
46
46
  function removalAncestorChanged(error) {
47
- return new FsSafeError("path-mismatch", "removal ancestor changed during operation", {
48
- cause: error instanceof Error ? error : undefined,
49
- });
47
+ return new FsSafeError("path-mismatch", "removal ancestor changed during operation", errorCauseOptions(error));
50
48
  }
51
49
  function sameCanonicalDirectory(left, right) {
52
50
  return left === right || (isPathInside(left, right) && isPathInside(right, left));
@@ -1,7 +1,7 @@
1
1
  import type { BigIntStats } from "node:fs";
2
2
  import { type DenyMutationPolicy } from "./deny-mutations.js";
3
3
  import { type AnyAsyncDirectoryGuard } from "./directory-guard.js";
4
- import type { PinnedWriteMutationAdmission } from "./pinned-write.js";
4
+ import type { PinnedWriteMutationAdmission } from "./pinned-write-types.js";
5
5
  import type { RootContext } from "./root-context.js";
6
6
  import { resolvePathInRoot } from "./root-context.js";
7
7
  import { type MutationSymlinkPolicy } from "./root-symlink-policy.js";
@@ -8,7 +8,7 @@ import { assertNoPathAliasEscape } from "./path-policy.js";
8
8
  import { preparePinnedWriteMutationAdmission, snapshotPinnedMutationPolicy, } from "./pinned-mutation-admission.js";
9
9
  import { admitPathInsideRoot, sameNormalizedPathSpelling } from "./root-boundary.js";
10
10
  import { resolvePathInRoot } from "./root-context.js";
11
- import { hardlinkedPathNotAllowedError, outsideWorkspaceError } from "./root-errors.js";
11
+ import { errorCauseOptions, hardlinkedPathNotAllowedError, outsideWorkspaceError } from "./root-errors.js";
12
12
  import { inheritWriteTargetMode } from "./root-write-mode.js";
13
13
  import { mutationSymlinkResolution, } from "./root-symlink-policy.js";
14
14
  import { inspectFileIdentitySync } from "./strict-file-identity.js";
@@ -23,9 +23,7 @@ export function createRootWriteSelectionForFd(selection, fd) {
23
23
  });
24
24
  }
25
25
  function writeSelectionChanged(cause) {
26
- return new FsSafeError("path-mismatch", "write target changed during operation", {
27
- cause: cause instanceof Error ? cause : undefined,
28
- });
26
+ return new FsSafeError("path-mismatch", "write target changed during operation", errorCauseOptions(cause));
29
27
  }
30
28
  function inspectRegularSelectionPath(pathname, expected, follow) {
31
29
  let observed;
@@ -186,9 +184,7 @@ export async function resolveGuardedWritePathInRoot(root, params) {
186
184
  });
187
185
  }
188
186
  catch (error) {
189
- throw new FsSafeError("path-alias", "path alias escape blocked", {
190
- cause: error instanceof Error ? error : undefined,
191
- });
187
+ throw new FsSafeError("path-alias", "path alias escape blocked", errorCauseOptions(error));
192
188
  }
193
189
  }
194
190
  return resolvedPath;
@@ -8,13 +8,12 @@ import { realpathSync } from "./realpath.js";
8
8
  import { admitPathInsideRoot, sameNormalizedPathSpelling } from "./root-boundary.js";
9
9
  import { ordinaryWindowsSegments } from "./pinned-mutation-shared-route.js";
10
10
  import { prepareRootWriteTarget } from "./root-directory-creation.js";
11
+ import { errorCauseOptions } from "./root-errors.js";
11
12
  import { canReuseParentWithMutationAssertion } from "./root-write-lock-binding.js";
12
13
  import { inspectFileIdentitySync } from "./strict-file-identity.js";
13
14
  import { getFsSafeTestHooks } from "./test-hooks.js";
14
15
  function writeSelectionChanged(cause) {
15
- return new FsSafeError("path-mismatch", "write target changed during operation", {
16
- cause: cause instanceof Error ? cause : undefined,
17
- });
16
+ return new FsSafeError("path-mismatch", "write target changed during operation", errorCauseOptions(cause));
18
17
  }
19
18
  function ordinarySharedWriteRoute(root, relativePath, operationTargetPath) {
20
19
  if (process.versions.bun || relativePath === "" || relativePath.startsWith("~") ||
@@ -1,5 +1,5 @@
1
1
  import { type AnyAsyncDirectoryGuard } from "./directory-guard.js";
2
- import type { PublishedWriteIdentity } from "./pinned-write.js";
2
+ import type { PublishedWriteIdentity } from "./pinned-write-types.js";
3
3
  import { type RootContext } from "./root-context.js";
4
4
  export declare function verifyAtomicWriteResult(params: {
5
5
  root: RootContext;
package/dist/root.d.ts CHANGED
@@ -1,6 +1,2 @@
1
- export { DEFAULT_ROOT_MAX_BYTES, openLocalFileSafely, readLocalFileSafely, resolveOpenedFileRealPathForHandle, root, type DenyMutationPolicy, type HardlinkPolicy, type MutationSymlinkPolicy, type RenameIdentityPolicy, type OpenResult, type ReadResult, type Root, type RootAppendOptions, type RootCopyOptions, type RootCopySource, type RootCreateJsonOptions, type RootCreateOptions, type RootCreateStreamOptions, type RootDefaults, type RootMkdirOptions, type RootMoveOptions, type RootOpenOptions, type RootOpenWritableOptions, type RootOptions, type RootReadOptions, type RootRemoveOptions, type RootWriteJsonOptions, type RootWriteOptions, type SymlinkPolicy, type WritableOpenMode, type WritableOpenResult, } from "./root-impl.js";
2
- export type { RootCopyPublicationReceipt } from "./copy-publication.js";
3
- export type { CopyCloneMode } from "./copy-policy.js";
4
- export type { RootEntriesOptions } from "./root-entries.js";
5
- export type { ContainmentGuarantee } from "./containment.js";
6
- export type { RootWalkDataEntry, RootWalkDataEntryKind, RootWalkDirectoryErrorBehavior, RootWalkEntry, RootWalkEntryFilter, RootWalkEntryFilterResult, RootWalkEntryKind, RootWalkLimitBehavior, RootWalkOptions, RootWalkSymlinkPolicy, } from "./root-walk.js";
1
+ export { DEFAULT_ROOT_MAX_BYTES, openLocalFileSafely, readLocalFileSafely, resolveOpenedFileRealPathForHandle, root, type Root, } from "./root-impl.js";
2
+ export type * from "./root-public-types.js";
@@ -8,7 +8,6 @@ import { assertAsyncDirectoryGuard, createAsyncDirectoryGuard, inspectDirectoryI
8
8
  import { pinNodeDirectoryForMode } from "./directory-mode-node.js";
9
9
  import { assertOwnedDirectory } from "./directory-mode-owner.js";
10
10
  import { FsSafeError } from "./errors.js";
11
- import { resolveHomeRelativePath } from "./home-dir.js";
12
11
  import { openPinnedFileSync } from "./pinned-open.js";
13
12
  import { runPinnedWriteHelper } from "./pinned-write.js";
14
13
  import { ensureTrailingSep } from "./root-context.js";
@@ -14,9 +14,13 @@ export function captureSecureTempRepairAdapter(supplied, hasLegacyFsHooks) {
14
14
  }
15
15
  return { lstatSync, fstatSync, openSync, fchmodSync, closeSync, flags: O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_NONBLOCK };
16
16
  }
17
+ // Node exposes stat identity through BigInt64Array; a high OS bit can be negative.
18
+ // Preserve raw values and existing positive adapter receipts, never normalize them.
19
+ const MIN_NODE_STAT_IDENTITY = -(1n << 63n);
17
20
  export function secureTempDirectoryReceipt(stat, uid) {
18
21
  const { dev, ino, uid: owner, mode } = stat;
19
- if (typeof dev !== "bigint" || dev < 0n || typeof ino !== "bigint" || ino <= 0n ||
22
+ if (typeof dev !== "bigint" || dev < MIN_NODE_STAT_IDENTITY ||
23
+ typeof ino !== "bigint" || ino < MIN_NODE_STAT_IDENTITY || ino === 0n ||
20
24
  typeof owner !== "bigint" || owner !== BigInt(uid) || typeof mode !== "bigint" ||
21
25
  mode < 0n || mode > 0xffffffffn || (mode & 61440n) !== 16384n ||
22
26
  stat.isDirectory() !== true || stat.isSymbolicLink() !== false) {
@@ -69,7 +69,7 @@ export async function acquireSidecarLock(options, context) {
69
69
  if (activeDescendant)
70
70
  throw sidecarLockTimeout(lockPath, normalizedTargetPath);
71
71
  const admission = createSidecarAdmissionController(admissionAncestry, context.admissions, normalizedTargetPath);
72
- const startedAt = Date.now();
72
+ const startedAt = performance.now();
73
73
  const reclaimGuardPath = `${lockPath}.reclaim`;
74
74
  let reclaimGuard;
75
75
  const releaseReclaimGuard = async () => {
@@ -90,7 +90,7 @@ export async function acquireSidecarLock(options, context) {
90
90
  const withinDenialBudget = () => ++transientDenials <= maxTransientLockDenials;
91
91
  const waitForRetry = async () => {
92
92
  admission.release();
93
- const delay = sidecarLockRetryDelay(retry, timeoutMs === Number.POSITIVE_INFINITY ? undefined : timeoutMs, Date.now() - startedAt, attempt);
93
+ const delay = sidecarLockRetryDelay(retry, timeoutMs === Number.POSITIVE_INFINITY ? undefined : timeoutMs, performance.now() - startedAt, attempt);
94
94
  if (delay === undefined)
95
95
  throw sidecarLockTimeout(lockPath, normalizedTargetPath);
96
96
  attempt += 1;
@@ -357,8 +357,9 @@ export async function acquireSidecarLock(options, context) {
357
357
  try {
358
358
  if (createdHeld)
359
359
  stopSidecarLockMonitoring(createdHeld);
360
+ let failedSnapshot = createdSnapshot;
360
361
  if (handle) {
361
- const failedSnapshot = createdSnapshot ?? { payload: null };
362
+ failedSnapshot ??= { payload: null };
362
363
  try {
363
364
  failedSnapshot.stat = fsSync.fstatSync(handle.fd);
364
365
  }
@@ -370,14 +371,10 @@ export async function acquireSidecarLock(options, context) {
370
371
  context.held.delete(normalizedTargetPath);
371
372
  }
372
373
  await handle.close().catch(() => undefined);
373
- // Root records use the creator receipt; partial raw writes use fd identity.
374
- await removeSidecarLockIfUnchanged(lockPath, failedSnapshot, {
375
- lockRoot,
376
- parsePayload: conditionalSidecarLockParser(parserState, admission, () => admission.hasToken() && !context.held.has(normalizedTargetPath)),
377
- });
378
374
  }
379
- else if (createdSnapshot) {
380
- await removeSidecarLockIfUnchanged(lockPath, createdSnapshot, {
375
+ // Root records use the creator receipt; partial raw writes use fd identity.
376
+ if (failedSnapshot) {
377
+ await removeSidecarLockIfUnchanged(lockPath, failedSnapshot, {
381
378
  lockRoot,
382
379
  parsePayload: conditionalSidecarLockParser(parserState, admission, () => admission.hasToken() && !context.held.has(normalizedTargetPath)),
383
380
  });
@@ -5,6 +5,7 @@ export declare function validateSidecarLockStaleMs(staleMs: number | undefined):
5
5
  export declare function validateSidecarLockCompromiseCheckIntervalMs(intervalMs: number | undefined): void;
6
6
  export declare function computeSidecarLockDelayMs(retry: SidecarLockRetryOptions, attempt: number): number;
7
7
  export declare function sidecarLockTimeout(lockPath: string, normalizedTargetPath: string): Error;
8
+ export declare function sidecarLockStale(lockPath: string, normalizedTargetPath: string): Error;
8
9
  /** Undefined means the deadline or retry count is exhausted. */
9
10
  export declare function sidecarLockRetryDelay(retry: SidecarLockRetryOptions, timeoutMs: number | undefined, elapsed: number, attempt: number): number | undefined;
10
11
  export declare const maxTransientLockDenials = 8;
@@ -62,6 +62,13 @@ export function sidecarLockTimeout(lockPath, normalizedTargetPath) {
62
62
  normalizedTargetPath,
63
63
  });
64
64
  }
65
+ export function sidecarLockStale(lockPath, normalizedTargetPath) {
66
+ return Object.assign(new Error(`file lock stale for ${normalizedTargetPath}`), {
67
+ code: "file_lock_stale",
68
+ lockPath,
69
+ normalizedTargetPath,
70
+ });
71
+ }
65
72
  /** Undefined means the deadline or retry count is exhausted. */
66
73
  export function sidecarLockRetryDelay(retry, timeoutMs, elapsed, attempt) {
67
74
  if ((timeoutMs !== undefined && elapsed >= timeoutMs) ||
@@ -1,4 +1,4 @@
1
- import { defaultSidecarLockShouldReclaim, isTransientLockFileDenial } from "./sidecar-lock-policy.js";
1
+ import { defaultSidecarLockShouldReclaim, isTransientLockFileDenial, sidecarLockStale } from "./sidecar-lock-policy.js";
2
2
  import { readSidecarLockRawSnapshot, removeStaleSidecarLockIfAllowed, sidecarLockSnapshotStillPresent, tryAcquireSidecarReclaimGuard, } from "./sidecar-lock-reclaim.js";
3
3
  import { observeSidecarLockParser, parseSidecarLockSnapshotUnderAdmission, scopedSidecarLockParser, } from "./sidecar-lock-admission-parser.js";
4
4
  /** Handle one historical EEXIST attempt while its canonical admission is held. */
@@ -224,9 +224,5 @@ export async function handleStaleSidecarAdmission(params) {
224
224
  }
225
225
  await params.releaseReclaimGuard();
226
226
  }
227
- throw Object.assign(new Error(`file lock stale for ${normalizedTargetPath}`), {
228
- code: "file_lock_stale",
229
- lockPath,
230
- normalizedTargetPath,
231
- });
227
+ throw sidecarLockStale(lockPath, normalizedTargetPath);
232
228
  }
@@ -12,27 +12,35 @@ export type SidecarLockCompromisedInfo = {
12
12
  lockPath: string;
13
13
  normalizedTargetPath: string;
14
14
  };
15
- export type SidecarLockAcquireOptions<TPayload extends Record<string, unknown>> = {
16
- targetPath: string;
15
+ export type SidecarLockOptionFields<T> = {
16
+ [K in keyof T]: T[K];
17
+ };
18
+ export type SidecarLockCommonAcquireOptions = {
17
19
  lockPath?: string;
18
- staleMs: number;
19
20
  timeoutMs?: number;
20
21
  retry?: SidecarLockRetryOptions;
21
22
  staleRecovery?: SidecarLockStaleRecovery;
22
23
  reentrantOwner?: string;
24
+ parsePayload?: (raw: string) => unknown;
25
+ lockRoot?: Root;
26
+ onCompromised?: (info: SidecarLockCompromisedInfo) => void;
27
+ compromiseCheckIntervalMs?: number;
28
+ };
29
+ export type SidecarLockReclaimParams<Held extends boolean = boolean> = {
30
+ lockPath: string;
31
+ normalizedTargetPath: string;
32
+ payload: unknown;
33
+ staleMs: number;
34
+ nowMs: number;
35
+ heldByThisProcess: Held;
36
+ };
37
+ export type SidecarLockAcquireOptions<TPayload extends Record<string, unknown>> = SidecarLockOptionFields<SidecarLockCommonAcquireOptions & {
38
+ targetPath: string;
39
+ staleMs: number;
23
40
  payload: () => TPayload | Promise<TPayload>;
24
- shouldReclaim?: (params: {
25
- lockPath: string;
26
- normalizedTargetPath: string;
27
- payload: unknown;
28
- staleMs: number;
29
- nowMs: number;
30
- heldByThisProcess: boolean;
31
- }) => boolean | Promise<boolean>;
41
+ shouldReclaim?: (params: SidecarLockReclaimParams) => boolean | Promise<boolean>;
32
42
  shouldRemoveStaleLock?: (snapshot: SidecarLockStaleSnapshot) => boolean | Promise<boolean>;
33
43
  metadata?: Record<string, unknown>;
34
- parsePayload?: (raw: string) => unknown;
35
- lockRoot?: Root;
36
44
  /**
37
45
  * Keep the lock file when the process exits naturally. Default `false`:
38
46
  * process-exit handlers release held locks. Set only for deliberately
@@ -40,9 +48,7 @@ export type SidecarLockAcquireOptions<TPayload extends Record<string, unknown>>
40
48
  * liveness is governed by the caller's own stale policy.
41
49
  */
42
50
  retainOnExit?: boolean;
43
- onCompromised?: (info: SidecarLockCompromisedInfo) => void;
44
- compromiseCheckIntervalMs?: number;
45
- };
51
+ }>;
46
52
  export type SidecarLockHandle = {
47
53
  lockPath: string;
48
54
  normalizedTargetPath: string;
@@ -2,14 +2,12 @@ import fsSync, {} from "node:fs";
2
2
  import fs from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { inspectDirectoryIdentitySync, observeDirectoryIdentitySync, } from "./directory-guard.js";
5
- import { admitTempWorkspaceChild, admitTempWorkspaceChildSync, } from "./temp-workspace-child-admission.js";
5
+ import { admitTempWorkspaceChild, admitTempWorkspaceChildSync, assertTrustedTempWorkspaceDirectory, inspectTempWorkspaceDescriptorIdentitySync, projectTempWorkspaceNumericIdentity, TEMP_WORKSPACE_NUMERIC_IDENTITY_REPLAY, } from "./temp-workspace-child-admission.js";
6
6
  import { FsSafeError } from "./errors.js";
7
7
  import { recordFileObservationFailure } from "./file-observation.js";
8
8
  import { realpathSync } from "./realpath.js";
9
9
  import { assertNoWindowsPathAlias, pathForWindowsFilesystem, resolvePathPreservingWindowsRoot, } from "./windows-path-alias.js";
10
10
  import { inspectFileIdentitySync } from "./strict-file-identity.js";
11
- import { inspectTempWorkspaceDescriptorIdentitySync, projectTempWorkspaceNumericIdentity, TEMP_WORKSPACE_NUMERIC_IDENTITY_REPLAY, } from "./temp-workspace-identity.js";
12
- import { assertTrustedTempWorkspaceDirectory } from "./temp-workspace-permissions.js";
13
11
  const WINDOWS = process.platform === "win32";
14
12
  function effectiveOwner() {
15
13
  // Windows mode/uid fields do not describe ACL authority. The supplied root's
@@ -1,6 +1,20 @@
1
- import type { BigIntStats, Stats } from "node:fs";
1
+ import { type BigIntStats, type Stats } from "node:fs";
2
2
  import type { TempWorkspaceRootAdmission } from "./temp-workspace-admission.js";
3
- import { type TempWorkspaceIdentityStat } from "./temp-workspace-identity.js";
3
+ export type TempWorkspaceIdentity = Readonly<{
4
+ dev: bigint;
5
+ ino: bigint;
6
+ }>;
7
+ export type TempWorkspaceNumericIdentity = Readonly<{
8
+ dev: number;
9
+ ino: number;
10
+ }>;
11
+ export type TempWorkspaceIdentityStat = BigIntStats | Stats;
12
+ export declare const TEMP_WORKSPACE_NUMERIC_IDENTITY_REPLAY: boolean;
13
+ export declare function projectTempWorkspaceNumericIdentity(identity: TempWorkspaceIdentity): TempWorkspaceNumericIdentity | undefined;
14
+ export declare function inspectTempWorkspaceDescriptorIdentitySync(fd: number, expected: TempWorkspaceIdentity, numeric: TempWorkspaceNumericIdentity | undefined): TempWorkspaceIdentityStat;
15
+ export declare function inspectTempWorkspaceDirectoryIdentitySync(dir: string, expected: TempWorkspaceIdentity, numeric: TempWorkspaceNumericIdentity | undefined): TempWorkspaceIdentityStat;
16
+ export declare function validateTempWorkspaceDirMode(mode: number): void;
17
+ export declare function assertTrustedTempWorkspaceDirectory(stat: Pick<BigIntStats, "uid" | "mode"> | Pick<Stats, "uid" | "mode">, uid: number | undefined, child?: boolean): void;
4
18
  export declare function assertTempWorkspaceChildState(stat: BigIntStats | Stats, ownerUid: number | undefined): void;
5
19
  export declare function validateInitialTempWorkspaceChild(stat: BigIntStats, ownerUid: number | undefined, mode: number): boolean;
6
20
  export declare function childHasRequestedMode(stat: BigIntStats | Stats, mode: number): boolean;