@neottia/repository-store 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +8 -5
  2. package/binding.gyp +12 -2
  3. package/dist/files.d.ts.map +1 -1
  4. package/dist/files.js +2 -2
  5. package/dist/files.js.map +1 -1
  6. package/dist/internal/filesystem.d.ts +3 -1
  7. package/dist/internal/filesystem.d.ts.map +1 -1
  8. package/dist/internal/filesystem.js +95 -13
  9. package/dist/internal/filesystem.js.map +1 -1
  10. package/dist/internal/model.d.ts +1 -0
  11. package/dist/internal/model.d.ts.map +1 -1
  12. package/dist/internal/model.js.map +1 -1
  13. package/dist/internal/platform-backend.d.ts +24 -0
  14. package/dist/internal/platform-backend.d.ts.map +1 -0
  15. package/dist/internal/platform-backend.js +120 -0
  16. package/dist/internal/platform-backend.js.map +1 -0
  17. package/dist/internal/publication.d.ts.map +1 -1
  18. package/dist/internal/publication.js +28 -16
  19. package/dist/internal/publication.js.map +1 -1
  20. package/dist/lease.d.ts +3 -0
  21. package/dist/lease.d.ts.map +1 -1
  22. package/dist/lease.js +241 -52
  23. package/dist/lease.js.map +1 -1
  24. package/dist/paths.d.ts.map +1 -1
  25. package/dist/paths.js +4 -1
  26. package/dist/paths.js.map +1 -1
  27. package/dist/sqlite/adapter.d.ts +1 -0
  28. package/dist/sqlite/adapter.d.ts.map +1 -1
  29. package/dist/sqlite/adapter.js +9 -0
  30. package/dist/sqlite/adapter.js.map +1 -1
  31. package/dist/sqlite/cache-publication.d.ts.map +1 -1
  32. package/dist/sqlite/cache-publication.js +2 -2
  33. package/dist/sqlite/cache-publication.js.map +1 -1
  34. package/dist/sqlite/cache.d.ts.map +1 -1
  35. package/dist/sqlite/cache.js +1 -2
  36. package/dist/sqlite/cache.js.map +1 -1
  37. package/dist/transaction/apply.js +2 -2
  38. package/dist/transaction/apply.js.map +1 -1
  39. package/dist/transaction/journal.js +2 -2
  40. package/dist/transaction/journal.js.map +1 -1
  41. package/dist/transaction/recovery.js +2 -2
  42. package/dist/transaction/recovery.js.map +1 -1
  43. package/native/{rename_noreplace.cc → backend.cc} +47 -49
  44. package/native/freebsd_backend.cc +83 -0
  45. package/native/linux_backend.cc +45 -0
  46. package/native/macos_backend.cc +84 -0
  47. package/native/platform_backend.h +17 -0
  48. package/native/unsupported_backend.cc +28 -0
  49. package/native/windows_backend.cc +179 -0
  50. package/package.json +5 -5
  51. package/scripts/install-native.mjs +2 -2
  52. package/dist/internal/native-publication.d.ts +0 -9
  53. package/dist/internal/native-publication.d.ts.map +0 -1
  54. package/dist/internal/native-publication.js +0 -65
  55. package/dist/internal/native-publication.js.map +0 -1
@@ -1,19 +1,19 @@
1
- import { closeSync, constants as fsConstants, fstatSync, linkSync, lstatSync, openSync, rmSync, writeFileSync, } from 'node:fs';
1
+ import { closeSync, constants as fsConstants, linkSync, openSync, rmSync, writeFileSync } from 'node:fs';
2
2
  import { basename, dirname, join } from 'node:path';
3
3
  import { PathSafetyError, RecoveryError, UnsupportedRuntimeError } from '../errors.js';
4
4
  import { computeByteRevision } from '../revision.js';
5
5
  import { emitFilesystemFault } from './fault-injection.js';
6
- import { assertSafeRegular, captureDirectories, ensurePrivateDirectory, hasCode, noFollowFlag, readRegularFile, revalidateDirectories, sameIdentity, syncDirectory, syncFileDescriptor, } from './filesystem.js';
7
- import { assertNativePublicationPath, nativeRenameNoReplace, requireNativePublicationBackend, } from './native-publication.js';
6
+ import { assertSafeRegular, captureDirectories, ensurePrivateDirectory, fstatSync, hasCode, lstatSync, noFollowFlag, readRegularFile, revalidateDirectories, sameIdentity, syncDirectory, syncFileDescriptor, } from './filesystem.js';
7
+ import { assertPlatformFilesystem, platformRenameNoReplace, requireRepositoryPlatformBackend, } from './platform-backend.js';
8
8
  export function publishExactRegularFile(path, bytes, expected, token) {
9
9
  const parent = dirname(path);
10
10
  ensurePrivateDirectory(parent);
11
11
  const parents = captureDirectories(parent);
12
12
  const temporary = join(parent, `.${basename(path)}.${token}.repository-store.tmp`);
13
13
  const evacuated = join(parent, `.${basename(path)}.${token}.repository-store.evacuated`);
14
- const nativeBackend = expected === undefined ? undefined : requireNativePublicationBackend();
15
- if (nativeBackend !== undefined)
16
- assertNativePublicationPath(nativeBackend, parent);
14
+ const platformBackend = expected === undefined ? undefined : requireRepositoryPlatformBackend();
15
+ if (platformBackend !== undefined)
16
+ assertPlatformFilesystem(platformBackend, parent);
17
17
  let descriptor;
18
18
  let temporaryIdentity;
19
19
  let evacuatedIdentity;
@@ -35,17 +35,22 @@ export function publishExactRegularFile(path, bytes, expected, token) {
35
35
  if (expected !== undefined) {
36
36
  emitFilesystemFault(bytes === null ? 'before-exact-removal' : 'before-exact-publication', path);
37
37
  emitFilesystemFault('before-exact-evacuation', evacuated);
38
- moveNoReplace(nativeBackend, path, evacuated, 'evacuate destination');
38
+ moveNoReplace(platformBackend, path, evacuated, 'evacuate destination');
39
39
  emitFilesystemFault('destination-evacuated', path);
40
- evacuatedIdentity = lstatSync(evacuated);
41
- assertSafeRegular(evacuatedIdentity, evacuated);
40
+ const observedIdentity = lstatSync(evacuated);
41
+ evacuatedIdentity = observedIdentity;
42
+ assertSafeRegular(observedIdentity, evacuated);
42
43
  const evacuatedBytes = readRegularFile(evacuated, expected.maxBytes);
43
- if (!sameIdentity(expected.identity, evacuatedIdentity) ||
44
- computeByteRevision(evacuatedBytes) !== expected.revision) {
45
- restoreEvacuated(nativeBackend, evacuated, path, parent);
44
+ const evacuatedRevision = computeByteRevision(evacuatedBytes);
45
+ if (!sameIdentity(expected.identity, observedIdentity) || evacuatedRevision !== expected.revision) {
46
+ restoreEvacuated(platformBackend, evacuated, path, parent);
46
47
  evacuatedIdentity = undefined;
47
48
  throw new PathSafetyError(`Destination changed during publication: ${path}`, 'IDENTITY_CHANGED', {
48
49
  path,
50
+ expectedIdentity: identityEvidence(expected.identity),
51
+ observedIdentity: identityEvidence(observedIdentity),
52
+ expectedRevision: expected.revision,
53
+ observedRevision: evacuatedRevision,
49
54
  });
50
55
  }
51
56
  revalidateDirectories(parents);
@@ -61,7 +66,7 @@ export function publishExactRegularFile(path, bytes, expected, token) {
61
66
  catch (error) {
62
67
  if (hasCode(error, 'EEXIST')) {
63
68
  if (evacuatedIdentity !== undefined)
64
- restoreEvacuated(nativeBackend, evacuated, path, parent);
69
+ restoreEvacuated(platformBackend, evacuated, path, parent);
65
70
  evacuatedIdentity = undefined;
66
71
  throw new PathSafetyError(`Destination appeared during publication: ${path}`, 'IDENTITY_CHANGED');
67
72
  }
@@ -125,7 +130,7 @@ export function recoverExactPublication(path, token, allowedRevisions, maxBytes)
125
130
  throw error;
126
131
  }
127
132
  if (current === undefined) {
128
- restoreEvacuated(requireNativePublicationBackend(), evacuated, path, parent);
133
+ restoreEvacuated(requireRepositoryPlatformBackend(), evacuated, path, parent);
129
134
  return;
130
135
  }
131
136
  if (sameIdentity(evidence, current)) {
@@ -175,7 +180,7 @@ function recoverTemporaryPublication(path, temporary, token, allowedRevisions, m
175
180
  }
176
181
  function restoreEvacuated(backend, evacuated, path, parent) {
177
182
  try {
178
- nativeRenameNoReplace(backend, evacuated, path);
183
+ platformRenameNoReplace(backend, evacuated, path);
179
184
  }
180
185
  catch (error) {
181
186
  if (hasCode(error, 'EEXIST'))
@@ -186,7 +191,7 @@ function restoreEvacuated(backend, evacuated, path, parent) {
186
191
  }
187
192
  function moveNoReplace(backend, source, destination, operation) {
188
193
  try {
189
- nativeRenameNoReplace(backend, source, destination);
194
+ platformRenameNoReplace(backend, source, destination);
190
195
  }
191
196
  catch (error) {
192
197
  if (hasCode(error, 'EEXIST'))
@@ -209,6 +214,13 @@ function unsupportedLink(error, path) {
209
214
  return new UnsupportedRuntimeError(`Filesystem does not support exclusive regular-file publication: ${path}`);
210
215
  return error;
211
216
  }
217
+ function identityEvidence(identity) {
218
+ return {
219
+ birthtimeMs: identity.birthtimeMs,
220
+ dev: identity.dev,
221
+ ino: identity.ino,
222
+ };
223
+ }
212
224
  function artifactExists(path) {
213
225
  try {
214
226
  lstatSync(path);
@@ -1 +1 @@
1
- {"version":3,"file":"publication.js","sourceRoot":"","sources":["../../src/internal/publication.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"publication.js","sourceRoot":"","sources":["../../src/internal/publication.ts"],"names":[],"mappings":"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"}
package/dist/lease.d.ts CHANGED
@@ -13,6 +13,9 @@ export declare function withRepositoryLease<T>(root: ManagedRoot, operation: (le
13
13
  export declare function assertLiveLease(root: ManagedRoot, lease: RepositoryLease): void;
14
14
  export declare function trackLeaseOperation<T>(lease: RepositoryLease, operation: Promise<T>): Promise<T>;
15
15
  export declare function checkControl(control: OperationControl): void;
16
+ export declare function interruptedClaimPeer(path: string, observed?: Stats, allowReleasePeer?: boolean): {
17
+ readonly token: string;
18
+ } | undefined;
16
19
  export interface ReleaseExpectation {
17
20
  readonly kind: 'file' | 'directory';
18
21
  readonly identity: Stats;
@@ -1 +1 @@
1
- {"version":3,"file":"lease.d.ts","sourceRoot":"","sources":["../src/lease.ts"],"names":[],"mappings":"AAEA,OAAO,EAaL,KAAK,KAAK,EACX,MAAM,SAAS,CAAC;AAiBjB,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,qBAAqB,CAAC;AAQ7B,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAE9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAGD,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AA0BD,wBAAsB,mBAAmB,CAAC,CAAC,EACzC,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,CAAC,CAAC,EACjD,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,CAAC,CAAC,CAqHZ;AAGD,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAY/E;AAGD,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAUhG;AAGD,wBAAgB,YAAY,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAI5D;AAmeD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC;CAChC;AAGD,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,kBAAkB,EAC5B,aAAa,CAAC,EAAE,kBAAkB,GACjC,IAAI,CA6CN;AAuRD,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"lease.d.ts","sourceRoot":"","sources":["../src/lease.ts"],"names":[],"mappings":"AAEA,OAAO,EAWL,KAAK,KAAK,EACX,MAAM,SAAS,CAAC;AAmBjB,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,qBAAqB,CAAC;AAQ7B,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAE9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAGD,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AA0BD,wBAAsB,mBAAmB,CAAC,CAAC,EACzC,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,CAAC,CAAC,EACjD,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,CAAC,CAAC,CAyIZ;AAGD,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAkB/E;AAGD,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAUhG;AAGD,wBAAgB,YAAY,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAI5D;AA4fD,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,KAAK,EAChB,gBAAgB,UAAQ,GACvB;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CA4BxC;AA4HD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC;CAChC;AAGD,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,kBAAkB,EAC5B,aAAa,CAAC,EAAE,kBAAkB,GACjC,IAAI,CA6CN;AAgSD,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/lease.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { AsyncLocalStorage } from 'node:async_hooks';
2
2
  import { randomBytes } from 'node:crypto';
3
- import { closeSync, constants as fsConstants, fstatSync, linkSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, rmSync, rmdirSync, writeFileSync, } from 'node:fs';
3
+ import { closeSync, constants as fsConstants, linkSync, mkdirSync, openSync, readFileSync, readdirSync, rmSync, rmdirSync, writeFileSync, } from 'node:fs';
4
4
  import { hostname } from 'node:os';
5
5
  import { basename, dirname, join } from 'node:path';
6
6
  import { LeaseContentionError, PathSafetyError, RepositoryStoreConfigError, ResourceLimitError } from './errors.js';
7
7
  import { emitFilesystemFault, emitLeaseFault } from './internal/fault-injection.js';
8
- import { assertSafeRegular, captureDirectories, ensurePrivateDirectory, hasCode, readRegularFile, readRegularFileWithIdentity, revalidateDirectories, sameIdentity, syncDirectory, syncFileDescriptor, } from './internal/filesystem.js';
8
+ import { assertSafeRegular, captureDirectories, ensurePrivateDirectory, fstatSync, hasCode, lstatSync, readRegularFile, readRegularFileWithIdentity, revalidateDirectories, sameIdentity, syncDirectory, syncFileDescriptor, } from './internal/filesystem.js';
9
9
  import { createRepositoryLease, getLeaseState, getRootState, } from './internal/model.js';
10
- import { assertNativePublicationPath, nativeRenameNoReplace, requireNativePublicationBackend, } from './internal/native-publication.js';
10
+ import { assertPlatformFilesystem, platformRenameNoReplace, requireRepositoryPlatformBackend, } from './internal/platform-backend.js';
11
11
  const authorityContext = new AsyncLocalStorage();
12
12
  const authorityQueueTails = new Map();
13
13
  const DEFAULT_STALE_MS = 60_000;
@@ -40,18 +40,38 @@ export async function withRepositoryLease(root, operation, options = {}) {
40
40
  let ownerIdentity;
41
41
  let leaseState;
42
42
  let lockPath = '';
43
+ let lockKind = 'directory';
43
44
  let token = '';
44
45
  try {
45
46
  checkAcquisitionControl(deadline, explicitDeadline !== undefined, options.signal);
46
47
  ensurePrivateDirectory(controlRoot);
47
- const cleanupBackend = requireNativePublicationBackend();
48
- assertNativePublicationPath(cleanupBackend, controlRoot);
48
+ const cleanupBackend = requireRepositoryPlatformBackend();
49
+ assertPlatformFilesystem(cleanupBackend, controlRoot);
50
+ lockKind = cleanupBackend.leaseArtifact;
49
51
  const hostId = ensureHostId(controlRoot);
50
52
  lockPath = join(controlRoot, 'authority.lease');
51
53
  const claimPath = join(controlRoot, 'authority.claim');
52
54
  token = randomBytes(32).toString('hex');
53
55
  while (!acquired) {
54
56
  checkAcquisitionControl(deadline, explicitDeadline !== undefined, options.signal);
57
+ if (lockKind === 'file') {
58
+ if (!acquireClaim(lockPath, controlRoot, token, hostId)) {
59
+ if (tryReclaimFileLease(lockPath, controlRoot, hostId, staleMs))
60
+ continue;
61
+ await waitForLeasePoll(pollMs, deadline, explicitDeadline !== undefined, options.signal);
62
+ continue;
63
+ }
64
+ emitLeaseFault('lease-directory-created');
65
+ const owner = readOwner(lockPath);
66
+ if (owner.metadata.token !== token)
67
+ throw new LeaseContentionError('Repository file lease ownership changed.', 'LEASE_OWNER_UNKNOWN');
68
+ lockIdentity = owner.identity;
69
+ ownerIdentity = owner.identity;
70
+ emitLeaseFault('lease-owner-written');
71
+ emitLeaseFault('lease-claim-removed');
72
+ acquired = true;
73
+ continue;
74
+ }
55
75
  if (!acquireClaim(claimPath, controlRoot, token, hostId)) {
56
76
  if (tryReclaimClaim(claimPath, lockPath, controlRoot, hostId, staleMs))
57
77
  continue;
@@ -87,7 +107,7 @@ export async function withRepositoryLease(root, operation, options = {}) {
87
107
  syncDirectory(controlRoot);
88
108
  if (!removeOwnedClaim(claimPath, token)) {
89
109
  claimOwnershipUncertain = true;
90
- releaseOwnedLease(lockPath, controlRoot, token, lockIdentity, ownerIdentity);
110
+ releaseOwnedLease(lockPath, controlRoot, token, lockIdentity, ownerIdentity, lockKind);
91
111
  throw new LeaseContentionError('Repository initialization claim ownership changed.', 'LEASE_OWNER_UNKNOWN');
92
112
  }
93
113
  emitLeaseFault('lease-claim-removed');
@@ -109,6 +129,7 @@ export async function withRepositoryLease(root, operation, options = {}) {
109
129
  authorityId: rootState.authorityId,
110
130
  token,
111
131
  lockPath,
132
+ lockKind,
112
133
  lockIdentity,
113
134
  ownerIdentity,
114
135
  pendingOperations: new Set(),
@@ -131,7 +152,7 @@ export async function withRepositoryLease(root, operation, options = {}) {
131
152
  leaseState.active = false;
132
153
  }
133
154
  if (acquired && lockIdentity !== undefined && ownerIdentity !== undefined)
134
- releaseOwnedLease(lockPath, controlRoot, token, lockIdentity, ownerIdentity);
155
+ releaseOwnedLease(lockPath, controlRoot, token, lockIdentity, ownerIdentity, lockKind);
135
156
  turn.release();
136
157
  }
137
158
  }
@@ -142,7 +163,7 @@ export function assertLiveLease(root, lease) {
142
163
  throw new RepositoryStoreConfigError('Lease and managed root have different authorities.', 'AUTHORITY_MISMATCH');
143
164
  if (!leaseState.active)
144
165
  throw new LeaseContentionError('Repository lease is no longer active.', 'LEASE_BUSY');
145
- if (!ownedLeaseIdentityMatches(leaseState.lockPath, leaseState.token, leaseState.lockIdentity, leaseState.ownerIdentity)) {
166
+ if (!ownedLeaseIdentityMatches(leaseState.lockPath, leaseState.token, leaseState.lockIdentity, leaseState.ownerIdentity, leaseState.lockKind)) {
146
167
  leaseState.active = false;
147
168
  throw new LeaseContentionError('Repository lease ownership changed.', 'LEASE_OWNER_UNKNOWN');
148
169
  }
@@ -196,25 +217,22 @@ function ownerMetadata(token, hostId) {
196
217
  function ensureHostId(controlRoot) {
197
218
  const path = join(controlRoot, 'host-id');
198
219
  try {
199
- const value = new TextDecoder().decode(readRegularFile(path, MAX_LEASE_METADATA_BYTES)).trim();
200
- if (!/^[0-9a-f]{64}$/u.test(value))
201
- throw new PathSafetyError('Repository host-id is malformed.');
202
- return value;
220
+ return readHostId(path, controlRoot);
203
221
  }
204
222
  catch (error) {
205
223
  if (!hasCode(error, 'ENOENT'))
206
224
  throw error;
207
225
  }
208
226
  const value = randomBytes(32).toString('hex');
227
+ const candidate = join(controlRoot, `.host-id-${randomBytes(16).toString('hex')}.tmp`);
228
+ let descriptor;
209
229
  try {
210
- const descriptor = openSync(path, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL, 0o600);
211
- try {
212
- writeFileSync(descriptor, `${value}\n`);
213
- syncFileDescriptor(descriptor, path);
214
- }
215
- finally {
216
- closeSync(descriptor);
217
- }
230
+ descriptor = openSync(candidate, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL, 0o600);
231
+ writeFileSync(descriptor, `${value}\n`);
232
+ syncFileDescriptor(descriptor, candidate);
233
+ closeSync(descriptor);
234
+ descriptor = undefined;
235
+ platformRenameNoReplace(requireRepositoryPlatformBackend(), candidate, path);
218
236
  syncDirectory(controlRoot);
219
237
  return value;
220
238
  }
@@ -223,6 +241,98 @@ function ensureHostId(controlRoot) {
223
241
  throw error;
224
242
  return ensureHostId(controlRoot);
225
243
  }
244
+ finally {
245
+ if (descriptor !== undefined)
246
+ closeSync(descriptor);
247
+ rmSync(candidate, { force: true });
248
+ }
249
+ }
250
+ function readHostId(path, controlRoot) {
251
+ const identity = lstatSync(path);
252
+ if (identity.isSymbolicLink() || !identity.isFile())
253
+ throw new PathSafetyError('Repository host-id has an unsafe identity.', 'UNSAFE_LINK');
254
+ if (identity.nlink !== 1 && identity.nlink !== 2)
255
+ throw new PathSafetyError('Repository host-id has an unsafe hard-link count.', 'UNSAFE_HARD_LINK');
256
+ if (identity.nlink === 2) {
257
+ const prefix = '.host-id-';
258
+ const peers = readdirSync(controlRoot).filter((name) => {
259
+ if (!name.startsWith(prefix) || !name.endsWith('.tmp'))
260
+ return false;
261
+ const token = name.slice(prefix.length, -'.tmp'.length);
262
+ if (!/^[0-9a-f]{32}$/u.test(token))
263
+ return false;
264
+ try {
265
+ const peer = lstatSync(join(controlRoot, name));
266
+ return peer.isFile() && !peer.isSymbolicLink() && sameIdentity(identity, peer);
267
+ }
268
+ catch (error) {
269
+ if (hasCode(error, 'ENOENT'))
270
+ return false;
271
+ throw error;
272
+ }
273
+ });
274
+ if (peers.length === 1) {
275
+ rmSync(join(controlRoot, peers[0]));
276
+ syncDirectory(controlRoot);
277
+ }
278
+ else {
279
+ const stabilized = lstatSync(path);
280
+ if (stabilized.nlink !== 1 || !sameIdentity(identity, stabilized))
281
+ throw new PathSafetyError('Repository host-id hard link is not package-owned.', 'UNSAFE_HARD_LINK');
282
+ }
283
+ }
284
+ const value = new TextDecoder().decode(readRegularFile(path, MAX_LEASE_METADATA_BYTES)).trim();
285
+ if (!/^[0-9a-f]{64}$/u.test(value))
286
+ throw new PathSafetyError('Repository host-id is malformed.');
287
+ return value;
288
+ }
289
+ function tryReclaimFileLease(lockPath, controlRoot, hostId, staleMs) {
290
+ const controlDirectories = captureDirectories(controlRoot);
291
+ try {
292
+ const preliminary = lstatSync(lockPath);
293
+ if (preliminary.isSymbolicLink() || !preliminary.isFile() || (preliminary.nlink !== 1 && preliminary.nlink !== 2))
294
+ throw new PathSafetyError('Unsafe repository file lease.', 'UNSAFE_HARD_LINK');
295
+ const verifiedOwner = readOwner(lockPath, true, true);
296
+ if (!sameIdentity(preliminary, verifiedOwner.identity))
297
+ throw new LeaseContentionError('File lease identity changed before owner verification.', 'LEASE_OWNER_UNKNOWN');
298
+ if (Date.now() - verifiedOwner.identity.mtimeMs < staleMs)
299
+ return false;
300
+ if (!conclusivelyDead(verifiedOwner.metadata, hostId))
301
+ return false;
302
+ normalizeInterruptedClaimLink(lockPath, controlRoot, true, verifiedOwner.metadata.token);
303
+ const normalizedOwner = readOwner(lockPath);
304
+ if (!sameIdentity(preliminary, normalizedOwner.identity) ||
305
+ normalizedOwner.metadata.token !== verifiedOwner.metadata.token)
306
+ throw new LeaseContentionError('File lease owner changed during reclamation.', 'LEASE_OWNER_UNKNOWN');
307
+ const quarantine = `${lockPath}.release-${normalizedOwner.metadata.token}`;
308
+ const expected = {
309
+ kind: 'file',
310
+ identity: normalizedOwner.identity,
311
+ token: normalizedOwner.metadata.token,
312
+ };
313
+ if (!quarantineNoReplace(lockPath, quarantine))
314
+ return false;
315
+ const moved = readOwner(quarantine);
316
+ if (!sameIdentity(normalizedOwner.identity, moved.identity) ||
317
+ moved.metadata.token !== normalizedOwner.metadata.token) {
318
+ restoreQuarantinedLease(quarantine, lockPath, expected, {
319
+ kind: 'file',
320
+ identity: moved.identity,
321
+ token: moved.metadata.token,
322
+ });
323
+ return false;
324
+ }
325
+ rmSync(quarantine);
326
+ syncDirectory(controlRoot);
327
+ return true;
328
+ }
329
+ catch (error) {
330
+ if (hasCode(error, 'ENOENT') || (error instanceof PathSafetyError && error.code === 'IDENTITY_CHANGED'))
331
+ return exactPathWasReleased(lockPath, controlDirectories, error, false);
332
+ if (error instanceof PathSafetyError || error instanceof ResourceLimitError)
333
+ throw error;
334
+ return false;
335
+ }
226
336
  }
227
337
  function tryReclaimLockedLease(lockPath, controlRoot, hostId, staleMs) {
228
338
  const controlDirectories = captureDirectories(controlRoot);
@@ -454,17 +564,22 @@ function cleanupOwnedInitialization(lockPath, controlRoot, token, expectedLock)
454
564
  restoreQuarantinedLease(quarantine, lockPath, releaseExpectation);
455
565
  }
456
566
  }
457
- function normalizeInterruptedClaimLink(claimPath, controlRoot) {
567
+ function normalizeInterruptedClaimLink(claimPath, controlRoot, allowReleasePeer = false, expectedToken) {
458
568
  const claim = lstatSync(claimPath);
459
569
  if (!claim.isFile() || claim.isSymbolicLink() || claim.nlink === 1)
460
570
  return;
461
571
  if (claim.nlink !== 2)
462
572
  throw new PathSafetyError('Unsafe repository claim hard-link count.', 'UNSAFE_HARD_LINK');
463
- const prefix = `${basename(claimPath)}.prepare-`;
464
- const candidates = readdirSync(dirname(claimPath)).filter((name) => name.startsWith(prefix));
465
- const matching = candidates.filter((name) => {
466
- const suffix = name.slice(prefix.length);
467
- if (!/^[0-9a-f-]{32,64}$/u.test(suffix))
573
+ const base = basename(claimPath);
574
+ const prefixes = [`${base}.prepare-`, ...(allowReleasePeer ? [`${base}.release-`] : [])];
575
+ const candidates = readdirSync(dirname(claimPath)).flatMap((name) => {
576
+ const prefix = prefixes.find((candidate) => name.startsWith(candidate));
577
+ if (prefix === undefined)
578
+ return [];
579
+ return [{ name, token: name.slice(prefix.length) }];
580
+ });
581
+ const matching = candidates.filter(({ name, token }) => {
582
+ if (!/^[0-9a-f-]{32,64}$/u.test(token) || (expectedToken !== undefined && token !== expectedToken))
468
583
  return false;
469
584
  const stat = lstatSync(join(dirname(claimPath), name));
470
585
  return stat.isFile() && !stat.isSymbolicLink() && sameIdentity(claim, stat);
@@ -475,7 +590,7 @@ function normalizeInterruptedClaimLink(claimPath, controlRoot) {
475
590
  return;
476
591
  throw new PathSafetyError('Repository claim hard link is not package-owned.');
477
592
  }
478
- rmSync(join(dirname(claimPath), matching[0]));
593
+ rmSync(join(dirname(claimPath), matching[0].name));
479
594
  syncDirectory(controlRoot);
480
595
  }
481
596
  function conclusivelyDead(owner, hostId) {
@@ -503,9 +618,11 @@ function readProcessStart(pid) {
503
618
  return undefined;
504
619
  }
505
620
  }
506
- function readOwner(path, allowInterruptedClaimLink = false) {
621
+ function readOwner(path, allowInterruptedClaimLink = false, allowInterruptedReleaseLink = false) {
507
622
  const initialIdentity = allowInterruptedClaimLink ? lstatSync(path) : undefined;
508
- const stagingPeer = allowInterruptedClaimLink ? interruptedClaimPeer(path, initialIdentity) : undefined;
623
+ const stagingPeer = allowInterruptedClaimLink
624
+ ? interruptedClaimPeer(path, initialIdentity, allowInterruptedReleaseLink)
625
+ : undefined;
509
626
  let file;
510
627
  try {
511
628
  file = readRegularFileWithIdentity(path, MAX_LEASE_METADATA_BYTES, {
@@ -516,7 +633,15 @@ function readOwner(path, allowInterruptedClaimLink = false) {
516
633
  const recoverableReadRace = error instanceof PathSafetyError && (error.code === 'IDENTITY_CHANGED' || error.code === 'UNSAFE_HARD_LINK');
517
634
  if (initialIdentity === undefined || !recoverableReadRace)
518
635
  throw error;
519
- const stabilized = lstatSync(path);
636
+ let stabilized;
637
+ try {
638
+ stabilized = lstatSync(path);
639
+ }
640
+ catch (stabilizationError) {
641
+ if (hasCode(stabilizationError, 'ENOENT'))
642
+ throw new PathSafetyError('Interrupted claim was released during owner verification.', 'IDENTITY_CHANGED');
643
+ throw stabilizationError;
644
+ }
520
645
  if (stabilized.isSymbolicLink() || !stabilized.isFile())
521
646
  throw error;
522
647
  if (!sameIdentity(initialIdentity, stabilized))
@@ -538,27 +663,56 @@ function readOwner(path, allowInterruptedClaimLink = false) {
538
663
  const finalIdentity = allowInterruptedClaimLink ? lstatSync(path) : undefined;
539
664
  if (finalIdentity !== undefined && !sameIdentity(file.identity, finalIdentity))
540
665
  throw new PathSafetyError('Interrupted claim identity changed after owner verification.', 'IDENTITY_CHANGED');
541
- const finalStagingPeer = allowInterruptedClaimLink && finalIdentity !== undefined ? interruptedClaimPeer(path, finalIdentity) : undefined;
666
+ const finalStagingPeer = allowInterruptedClaimLink && finalIdentity !== undefined
667
+ ? interruptedClaimPeer(path, finalIdentity, allowInterruptedReleaseLink)
668
+ : undefined;
542
669
  if ([stagingPeer, finalStagingPeer].some((peer) => peer !== undefined && owner.token !== peer.token))
543
670
  throw new PathSafetyError('Interrupted claim token does not match its package-owned staging link.');
544
671
  return { metadata: owner, identity: file.identity };
545
672
  }
546
- function interruptedClaimPeer(path, observed) {
673
+ export function interruptedClaimPeer(path, observed, allowReleasePeer = false) {
547
674
  const stat = observed ?? lstatSync(path);
548
675
  if (stat.isSymbolicLink() || !stat.isFile() || (stat.nlink !== 1 && stat.nlink !== 2))
549
676
  throw new PathSafetyError('Unsafe interrupted repository claim.', 'UNSAFE_HARD_LINK');
550
677
  if (stat.nlink === 1)
551
678
  return undefined;
552
- const prefix = `${basename(path)}.prepare-`;
553
- const peers = readdirSync(dirname(path)).flatMap((name) => {
554
- if (!name.startsWith(prefix))
679
+ for (let attempt = 0; attempt < 4; attempt += 1) {
680
+ const peers = matchingInterruptedClaimPeers(path, stat, allowReleasePeer);
681
+ if (peers.length === 1)
682
+ return peers[0];
683
+ let stabilized;
684
+ try {
685
+ stabilized = lstatSync(path);
686
+ }
687
+ catch (stabilizationError) {
688
+ if (hasCode(stabilizationError, 'ENOENT'))
689
+ throw new PathSafetyError('Interrupted claim was released during peer verification.', 'IDENTITY_CHANGED');
690
+ throw stabilizationError;
691
+ }
692
+ if (stabilized.isSymbolicLink() || !stabilized.isFile())
693
+ throw new PathSafetyError('Interrupted claim path became unsafe during peer verification.', 'UNSAFE_HARD_LINK');
694
+ if (!sameIdentity(stat, stabilized))
695
+ throw new PathSafetyError('Interrupted claim identity changed during peer verification.', 'IDENTITY_CHANGED');
696
+ if (stabilized.nlink === 1)
697
+ return undefined;
698
+ if (stabilized.nlink !== 2)
699
+ break;
700
+ }
701
+ throw new PathSafetyError('Interrupted claim hard link is not package-owned.', 'UNSAFE_HARD_LINK');
702
+ }
703
+ function matchingInterruptedClaimPeers(path, identity, allowReleasePeer) {
704
+ const base = basename(path);
705
+ const prefixes = [`${base}.prepare-`, ...(allowReleasePeer ? [`${base}.release-`] : [])];
706
+ return readdirSync(dirname(path)).flatMap((name) => {
707
+ const prefix = prefixes.find((candidate) => name.startsWith(candidate));
708
+ if (prefix === undefined)
555
709
  return [];
556
710
  const token = name.slice(prefix.length);
557
711
  if (!/^[0-9a-f-]{32,64}$/u.test(token))
558
712
  return [];
559
713
  try {
560
714
  const peer = lstatSync(join(dirname(path), name));
561
- return peer.isFile() && !peer.isSymbolicLink() && sameIdentity(stat, peer) ? [{ token }] : [];
715
+ return peer.isFile() && !peer.isSymbolicLink() && sameIdentity(identity, peer) ? [{ token }] : [];
562
716
  }
563
717
  catch (error) {
564
718
  if (hasCode(error, 'ENOENT'))
@@ -566,14 +720,12 @@ function interruptedClaimPeer(path, observed) {
566
720
  throw error;
567
721
  }
568
722
  });
569
- if (peers.length === 1)
570
- return peers[0];
571
- const stabilized = lstatSync(path);
572
- if (!stabilized.isSymbolicLink() && stabilized.isFile() && stabilized.nlink === 1 && sameIdentity(stat, stabilized))
573
- return undefined;
574
- throw new PathSafetyError('Interrupted claim hard link is not package-owned.', 'UNSAFE_HARD_LINK');
575
723
  }
576
- function releaseOwnedLease(lockPath, controlRoot, token, lockIdentity, ownerIdentity) {
724
+ function releaseOwnedLease(lockPath, controlRoot, token, lockIdentity, ownerIdentity, lockKind) {
725
+ if (lockKind === 'file') {
726
+ releaseOwnedFileLease(lockPath, controlRoot, token, lockIdentity, ownerIdentity);
727
+ return;
728
+ }
577
729
  const releasePath = `${lockPath}.release-${token}`;
578
730
  const releaseExpectation = {
579
731
  kind: 'directory',
@@ -621,13 +773,44 @@ function releaseOwnedLease(lockPath, controlRoot, token, lockIdentity, ownerIden
621
773
  restoreQuarantinedLease(releasePath, lockPath, releaseExpectation);
622
774
  }
623
775
  }
776
+ function releaseOwnedFileLease(lockPath, controlRoot, token, lockIdentity, ownerIdentity) {
777
+ const releasePath = `${lockPath}.release-${token}`;
778
+ const expected = { kind: 'file', identity: lockIdentity, token };
779
+ let restorationSafe = false;
780
+ try {
781
+ const current = readOwner(lockPath);
782
+ if (current.metadata.token !== token ||
783
+ !sameIdentity(current.identity, lockIdentity) ||
784
+ !sameIdentity(current.identity, ownerIdentity))
785
+ return;
786
+ if (!quarantineNoReplace(lockPath, releasePath))
787
+ return;
788
+ restorationSafe = true;
789
+ const moved = readOwner(releasePath);
790
+ if (moved.metadata.token !== token || !sameIdentity(moved.identity, lockIdentity)) {
791
+ restoreQuarantinedLease(releasePath, lockPath, expected, {
792
+ kind: 'file',
793
+ identity: moved.identity,
794
+ token: moved.metadata.token,
795
+ });
796
+ return;
797
+ }
798
+ rmSync(releasePath);
799
+ restorationSafe = false;
800
+ syncDirectory(controlRoot);
801
+ }
802
+ catch {
803
+ if (restorationSafe)
804
+ restoreQuarantinedLease(releasePath, lockPath, expected);
805
+ }
806
+ }
624
807
  export function restoreQuarantinedLease(quarantine, lockPath, expected, movedFromLock) {
625
808
  const verification = `${quarantine}.restore-${randomBytes(16).toString('hex')}`;
626
809
  let staged = false;
627
810
  let preserveUnverified = false;
628
811
  let restorationExpectation;
629
812
  try {
630
- nativeRenameNoReplace(requireNativePublicationBackend(), quarantine, verification);
813
+ platformRenameNoReplace(requireRepositoryPlatformBackend(), quarantine, verification);
631
814
  staged = true;
632
815
  restorationExpectation = releaseArtifactMatches(verification, expected)
633
816
  ? expected
@@ -639,7 +822,7 @@ export function restoreQuarantinedLease(quarantine, lockPath, expected, movedFro
639
822
  return;
640
823
  }
641
824
  try {
642
- nativeRenameNoReplace(requireNativePublicationBackend(), verification, lockPath);
825
+ platformRenameNoReplace(requireRepositoryPlatformBackend(), verification, lockPath);
643
826
  staged = false;
644
827
  }
645
828
  catch (error) {
@@ -660,7 +843,7 @@ export function restoreQuarantinedLease(quarantine, lockPath, expected, movedFro
660
843
  if (preserveUnverified ||
661
844
  releaseArtifactMatches(verification, expected) ||
662
845
  (movedFromLock !== undefined && releaseArtifactMatches(verification, movedFromLock)))
663
- nativeRenameNoReplace(requireNativePublicationBackend(), verification, quarantine);
846
+ platformRenameNoReplace(requireRepositoryPlatformBackend(), verification, quarantine);
664
847
  }
665
848
  catch {
666
849
  }
@@ -705,7 +888,7 @@ function cleanupVerifiedReleaseArtifact(path, expected, releasePath = path) {
705
888
  const match = /\.release-([0-9a-f-]{32,64})$/u.exec(basename(releasePath));
706
889
  if (match?.[1] !== expected.token)
707
890
  return;
708
- nativeRenameNoReplace(requireNativePublicationBackend(), path, cleanup);
891
+ platformRenameNoReplace(requireRepositoryPlatformBackend(), path, cleanup);
709
892
  moved = true;
710
893
  const identity = lstatSync(cleanup);
711
894
  if (!sameIdentity(identity, expected.identity) || identity.isSymbolicLink())
@@ -748,7 +931,7 @@ function cleanupVerifiedReleaseArtifact(path, expected, releasePath = path) {
748
931
  finally {
749
932
  if (moved && !removed) {
750
933
  try {
751
- nativeRenameNoReplace(requireNativePublicationBackend(), cleanup, path);
934
+ platformRenameNoReplace(requireRepositoryPlatformBackend(), cleanup, path);
752
935
  }
753
936
  catch {
754
937
  }
@@ -780,8 +963,14 @@ function removeOwnedClaim(path, token) {
780
963
  return false;
781
964
  }
782
965
  }
783
- function ownedLeaseIdentityMatches(lockPath, token, lockIdentity, ownerIdentity) {
966
+ function ownedLeaseIdentityMatches(lockPath, token, lockIdentity, ownerIdentity, lockKind) {
784
967
  try {
968
+ if (lockKind === 'file') {
969
+ const currentOwner = readOwner(lockPath);
970
+ return (currentOwner.metadata.token === token &&
971
+ sameIdentity(lockIdentity, currentOwner.identity) &&
972
+ sameIdentity(ownerIdentity, currentOwner.identity));
973
+ }
785
974
  const currentLock = lstatSync(lockPath);
786
975
  const currentOwner = readOwner(join(lockPath, 'owner.json'));
787
976
  return (currentLock.isDirectory() &&
@@ -908,9 +1097,9 @@ function acquisitionTimeout(hasExplicitDeadline) {
908
1097
  function quarantineNoReplace(source, destination) {
909
1098
  emitFilesystemFault('before-lease-artifact-quarantine', source);
910
1099
  try {
911
- const backend = requireNativePublicationBackend();
912
- assertNativePublicationPath(backend, dirname(source));
913
- nativeRenameNoReplace(backend, source, destination);
1100
+ const backend = requireRepositoryPlatformBackend();
1101
+ assertPlatformFilesystem(backend, dirname(source));
1102
+ platformRenameNoReplace(backend, source, destination);
914
1103
  return true;
915
1104
  }
916
1105
  catch (error) {