atomic-lockfile 0.0.1-security → 1.4.2
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.
Potentially problematic release.
This version of atomic-lockfile might be problematic. Click here for more details.
- package/CHANGELOG.md +35 -0
- package/LICENSE +21 -0
- package/README.md +207 -3
- package/dist/esm/adapters/atomic.js +42 -0
- package/dist/esm/adapters/atomic.js.map +1 -0
- package/dist/esm/adapters/fs.js +29 -0
- package/dist/esm/adapters/fs.js.map +1 -0
- package/dist/esm/adapters/index.js +27 -0
- package/dist/esm/adapters/index.js.map +1 -0
- package/dist/esm/adapters/mkdir.js +31 -0
- package/dist/esm/adapters/mkdir.js.map +1 -0
- package/dist/esm/adapters/symlink.js +29 -0
- package/dist/esm/adapters/symlink.js.map +1 -0
- package/dist/esm/async/check.js +11 -0
- package/dist/esm/async/check.js.map +1 -0
- package/dist/esm/async/index.js +4 -0
- package/dist/esm/async/index.js.map +1 -0
- package/dist/esm/async/lock.js +13 -0
- package/dist/esm/async/lock.js.map +1 -0
- package/dist/esm/async/unlock.js +8 -0
- package/dist/esm/async/unlock.js.map +1 -0
- package/dist/esm/cli/commands/cleanup.js +28 -0
- package/dist/esm/cli/commands/cleanup.js.map +1 -0
- package/dist/esm/cli/commands/list.js +26 -0
- package/dist/esm/cli/commands/list.js.map +1 -0
- package/dist/esm/cli/commands/lock.js +26 -0
- package/dist/esm/cli/commands/lock.js.map +1 -0
- package/dist/esm/cli/commands/status.js +27 -0
- package/dist/esm/cli/commands/status.js.map +1 -0
- package/dist/esm/cli/commands/unlock.js +20 -0
- package/dist/esm/cli/commands/unlock.js.map +1 -0
- package/dist/esm/cli/formatters/index.js +14 -0
- package/dist/esm/cli/formatters/index.js.map +1 -0
- package/dist/esm/cli/formatters/json.js +15 -0
- package/dist/esm/cli/formatters/json.js.map +1 -0
- package/dist/esm/cli/formatters/table.js +18 -0
- package/dist/esm/cli/formatters/table.js.map +1 -0
- package/dist/esm/cli/formatters/text.js +20 -0
- package/dist/esm/cli/formatters/text.js.map +1 -0
- package/dist/esm/cli/index.js +56 -0
- package/dist/esm/cli/index.js.map +1 -0
- package/dist/esm/compat/cjs.js +11 -0
- package/dist/esm/compat/cjs.js.map +1 -0
- package/dist/esm/compat/esm.js +11 -0
- package/dist/esm/compat/esm.js.map +1 -0
- package/dist/esm/compat/index.js +4 -0
- package/dist/esm/compat/index.js.map +1 -0
- package/dist/esm/compat/v1.js +23 -0
- package/dist/esm/compat/v1.js.map +1 -0
- package/dist/esm/config/defaults.js +12 -0
- package/dist/esm/config/defaults.js.map +1 -0
- package/dist/esm/config/index.js +17 -0
- package/dist/esm/config/index.js.map +1 -0
- package/dist/esm/config/schema.js +55 -0
- package/dist/esm/config/schema.js.map +1 -0
- package/dist/esm/constants/defaults.js +15 -0
- package/dist/esm/constants/defaults.js.map +1 -0
- package/dist/esm/constants/errors.js +37 -0
- package/dist/esm/constants/errors.js.map +1 -0
- package/dist/esm/constants/index.js +14 -0
- package/dist/esm/constants/index.js.map +1 -0
- package/dist/esm/constants/signals.js +21 -0
- package/dist/esm/constants/signals.js.map +1 -0
- package/dist/esm/constants/timeouts.js +16 -0
- package/dist/esm/constants/timeouts.js.map +1 -0
- package/dist/esm/core/acquire.js +51 -0
- package/dist/esm/core/acquire.js.map +1 -0
- package/dist/esm/core/buildLockData.js +23 -0
- package/dist/esm/core/buildLockData.js.map +1 -0
- package/dist/esm/core/check.js +62 -0
- package/dist/esm/core/check.js.map +1 -0
- package/dist/esm/core/cleanup.js +45 -0
- package/dist/esm/core/cleanup.js.map +1 -0
- package/dist/esm/core/handle.js +43 -0
- package/dist/esm/core/handle.js.map +1 -0
- package/dist/esm/core/index.js +8 -0
- package/dist/esm/core/index.js.map +1 -0
- package/dist/esm/core/list.js +38 -0
- package/dist/esm/core/list.js.map +1 -0
- package/dist/esm/core/release.js +21 -0
- package/dist/esm/core/release.js.map +1 -0
- package/dist/esm/errors/AbortError.js +18 -0
- package/dist/esm/errors/AbortError.js.map +1 -0
- package/dist/esm/errors/ConflictError.js +20 -0
- package/dist/esm/errors/ConflictError.js.map +1 -0
- package/dist/esm/errors/IOError.js +24 -0
- package/dist/esm/errors/IOError.js.map +1 -0
- package/dist/esm/errors/LockError.js +30 -0
- package/dist/esm/errors/LockError.js.map +1 -0
- package/dist/esm/errors/PermissionError.js +21 -0
- package/dist/esm/errors/PermissionError.js.map +1 -0
- package/dist/esm/errors/StaleError.js +27 -0
- package/dist/esm/errors/StaleError.js.map +1 -0
- package/dist/esm/errors/TimeoutError.js +21 -0
- package/dist/esm/errors/TimeoutError.js.map +1 -0
- package/dist/esm/errors/ValidationError.js +21 -0
- package/dist/esm/errors/ValidationError.js.map +1 -0
- package/dist/esm/errors/index.js +24 -0
- package/dist/esm/errors/index.js.map +1 -0
- package/dist/esm/events/emitter.js +41 -0
- package/dist/esm/events/emitter.js.map +1 -0
- package/dist/esm/events/index.js +3 -0
- package/dist/esm/events/index.js.map +1 -0
- package/dist/esm/events/types.js +15 -0
- package/dist/esm/events/types.js.map +1 -0
- package/dist/esm/hooks/afterLock.js +18 -0
- package/dist/esm/hooks/afterLock.js.map +1 -0
- package/dist/esm/hooks/afterUnlock.js +18 -0
- package/dist/esm/hooks/afterUnlock.js.map +1 -0
- package/dist/esm/hooks/beforeLock.js +18 -0
- package/dist/esm/hooks/beforeLock.js.map +1 -0
- package/dist/esm/hooks/beforeUnlock.js +18 -0
- package/dist/esm/hooks/beforeUnlock.js.map +1 -0
- package/dist/esm/hooks/index.js +24 -0
- package/dist/esm/hooks/index.js.map +1 -0
- package/dist/esm/hooks/onError.js +18 -0
- package/dist/esm/hooks/onError.js.map +1 -0
- package/dist/esm/hooks/onStale.js +18 -0
- package/dist/esm/hooks/onStale.js.map +1 -0
- package/dist/esm/hooks/onTimeout.js +18 -0
- package/dist/esm/hooks/onTimeout.js.map +1 -0
- package/dist/esm/index.js +21 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/logger/console.js +38 -0
- package/dist/esm/logger/console.js.map +1 -0
- package/dist/esm/logger/debug.js +26 -0
- package/dist/esm/logger/debug.js.map +1 -0
- package/dist/esm/logger/index.js +15 -0
- package/dist/esm/logger/index.js.map +1 -0
- package/dist/esm/logger/noop.js +12 -0
- package/dist/esm/logger/noop.js.map +1 -0
- package/dist/esm/meta/index.js +3 -0
- package/dist/esm/meta/index.js.map +1 -0
- package/dist/esm/meta/package.js +27 -0
- package/dist/esm/meta/package.js.map +1 -0
- package/dist/esm/meta/version.js +27 -0
- package/dist/esm/meta/version.js.map +1 -0
- package/dist/esm/middleware/index.js +11 -0
- package/dist/esm/middleware/index.js.map +1 -0
- package/dist/esm/middleware/logging.js +20 -0
- package/dist/esm/middleware/logging.js.map +1 -0
- package/dist/esm/middleware/metrics.js +32 -0
- package/dist/esm/middleware/metrics.js.map +1 -0
- package/dist/esm/middleware/retry.js +22 -0
- package/dist/esm/middleware/retry.js.map +1 -0
- package/dist/esm/middleware/timeout.js +28 -0
- package/dist/esm/middleware/timeout.js.map +1 -0
- package/dist/esm/platform/darwin.js +17 -0
- package/dist/esm/platform/darwin.js.map +1 -0
- package/dist/esm/platform/index.js +6 -0
- package/dist/esm/platform/index.js.map +1 -0
- package/dist/esm/platform/linux.js +31 -0
- package/dist/esm/platform/linux.js.map +1 -0
- package/dist/esm/platform/unix.js +34 -0
- package/dist/esm/platform/unix.js.map +1 -0
- package/dist/esm/platform/windows.js +22 -0
- package/dist/esm/platform/windows.js.map +1 -0
- package/dist/esm/plugins/cleanup.js +39 -0
- package/dist/esm/plugins/cleanup.js.map +1 -0
- package/dist/esm/plugins/heartbeat.js +31 -0
- package/dist/esm/plugins/heartbeat.js.map +1 -0
- package/dist/esm/plugins/index.js +6 -0
- package/dist/esm/plugins/index.js.map +1 -0
- package/dist/esm/plugins/pid.js +25 -0
- package/dist/esm/plugins/pid.js.map +1 -0
- package/dist/esm/plugins/stale.js +21 -0
- package/dist/esm/plugins/stale.js.map +1 -0
- package/dist/esm/plugins/ttl.js +28 -0
- package/dist/esm/plugins/ttl.js.map +1 -0
- package/dist/esm/promise/index.js +3 -0
- package/dist/esm/promise/index.js.map +1 -0
- package/dist/esm/promise/lock.js +13 -0
- package/dist/esm/promise/lock.js.map +1 -0
- package/dist/esm/promise/withLock.js +22 -0
- package/dist/esm/promise/withLock.js.map +1 -0
- package/dist/esm/registry/global.js +29 -0
- package/dist/esm/registry/global.js.map +1 -0
- package/dist/esm/registry/index.js +3 -0
- package/dist/esm/registry/index.js.map +1 -0
- package/dist/esm/registry/local.js +28 -0
- package/dist/esm/registry/local.js.map +1 -0
- package/dist/esm/strategies/advisory.js +19 -0
- package/dist/esm/strategies/advisory.js.map +1 -0
- package/dist/esm/strategies/exclusive.js +19 -0
- package/dist/esm/strategies/exclusive.js.map +1 -0
- package/dist/esm/strategies/index.js +27 -0
- package/dist/esm/strategies/index.js.map +1 -0
- package/dist/esm/strategies/optimistic.js +22 -0
- package/dist/esm/strategies/optimistic.js.map +1 -0
- package/dist/esm/strategies/shared.js +19 -0
- package/dist/esm/strategies/shared.js.map +1 -0
- package/dist/esm/sync/check.js +39 -0
- package/dist/esm/sync/check.js.map +1 -0
- package/dist/esm/sync/index.js +4 -0
- package/dist/esm/sync/index.js.map +1 -0
- package/dist/esm/sync/lock.js +39 -0
- package/dist/esm/sync/lock.js.map +1 -0
- package/dist/esm/sync/unlock.js +21 -0
- package/dist/esm/sync/unlock.js.map +1 -0
- package/dist/esm/types/adapter.js +2 -0
- package/dist/esm/types/adapter.js.map +1 -0
- package/dist/esm/types/events.js +2 -0
- package/dist/esm/types/events.js.map +1 -0
- package/dist/esm/types/index.js +2 -0
- package/dist/esm/types/index.js.map +1 -0
- package/dist/esm/types/lock.js +2 -0
- package/dist/esm/types/lock.js.map +1 -0
- package/dist/esm/types/logger.js +2 -0
- package/dist/esm/types/logger.js.map +1 -0
- package/dist/esm/types/options.js +2 -0
- package/dist/esm/types/options.js.map +1 -0
- package/dist/esm/types/state.js +2 -0
- package/dist/esm/types/state.js.map +1 -0
- package/dist/esm/types/strategy.js +2 -0
- package/dist/esm/types/strategy.js.map +1 -0
- package/dist/esm/utils/backoff.js +40 -0
- package/dist/esm/utils/backoff.js.map +1 -0
- package/dist/esm/utils/fs.js +88 -0
- package/dist/esm/utils/fs.js.map +1 -0
- package/dist/esm/utils/hash.js +20 -0
- package/dist/esm/utils/hash.js.map +1 -0
- package/dist/esm/utils/hostname.js +28 -0
- package/dist/esm/utils/hostname.js.map +1 -0
- package/dist/esm/utils/index.js +14 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/dist/esm/utils/parse.js +44 -0
- package/dist/esm/utils/parse.js.map +1 -0
- package/dist/esm/utils/path.js +35 -0
- package/dist/esm/utils/path.js.map +1 -0
- package/dist/esm/utils/pid.js +35 -0
- package/dist/esm/utils/pid.js.map +1 -0
- package/dist/esm/utils/platform.js +35 -0
- package/dist/esm/utils/platform.js.map +1 -0
- package/dist/esm/utils/random.js +26 -0
- package/dist/esm/utils/random.js.map +1 -0
- package/dist/esm/utils/retry.js +37 -0
- package/dist/esm/utils/retry.js.map +1 -0
- package/dist/esm/utils/serialize.js +27 -0
- package/dist/esm/utils/serialize.js.map +1 -0
- package/dist/esm/utils/time.js +44 -0
- package/dist/esm/utils/time.js.map +1 -0
- package/dist/esm/utils/validate.js +42 -0
- package/dist/esm/utils/validate.js.map +1 -0
- package/dist/types/adapters/atomic.d.ts +3 -0
- package/dist/types/adapters/atomic.d.ts.map +1 -0
- package/dist/types/adapters/fs.d.ts +3 -0
- package/dist/types/adapters/fs.d.ts.map +1 -0
- package/dist/types/adapters/index.d.ts +9 -0
- package/dist/types/adapters/index.d.ts.map +1 -0
- package/dist/types/adapters/mkdir.d.ts +3 -0
- package/dist/types/adapters/mkdir.d.ts.map +1 -0
- package/dist/types/adapters/symlink.d.ts +3 -0
- package/dist/types/adapters/symlink.d.ts.map +1 -0
- package/dist/types/async/check.d.ts +6 -0
- package/dist/types/async/check.d.ts.map +1 -0
- package/dist/types/async/index.d.ts +4 -0
- package/dist/types/async/index.d.ts.map +1 -0
- package/dist/types/async/lock.d.ts +5 -0
- package/dist/types/async/lock.d.ts.map +1 -0
- package/dist/types/async/unlock.d.ts +5 -0
- package/dist/types/async/unlock.d.ts.map +1 -0
- package/dist/types/cli/commands/cleanup.d.ts +2 -0
- package/dist/types/cli/commands/cleanup.d.ts.map +1 -0
- package/dist/types/cli/commands/list.d.ts +2 -0
- package/dist/types/cli/commands/list.d.ts.map +1 -0
- package/dist/types/cli/commands/lock.d.ts +2 -0
- package/dist/types/cli/commands/lock.d.ts.map +1 -0
- package/dist/types/cli/commands/status.d.ts +2 -0
- package/dist/types/cli/commands/status.d.ts.map +1 -0
- package/dist/types/cli/commands/unlock.d.ts +2 -0
- package/dist/types/cli/commands/unlock.d.ts.map +1 -0
- package/dist/types/cli/formatters/index.d.ts +7 -0
- package/dist/types/cli/formatters/index.d.ts.map +1 -0
- package/dist/types/cli/formatters/json.d.ts +5 -0
- package/dist/types/cli/formatters/json.d.ts.map +1 -0
- package/dist/types/cli/formatters/table.d.ts +3 -0
- package/dist/types/cli/formatters/table.d.ts.map +1 -0
- package/dist/types/cli/formatters/text.d.ts +6 -0
- package/dist/types/cli/formatters/text.d.ts.map +1 -0
- package/dist/types/cli/index.d.ts +3 -0
- package/dist/types/cli/index.d.ts.map +1 -0
- package/dist/types/compat/cjs.d.ts +11 -0
- package/dist/types/compat/cjs.d.ts.map +1 -0
- package/dist/types/compat/esm.d.ts +11 -0
- package/dist/types/compat/esm.d.ts.map +1 -0
- package/dist/types/compat/index.d.ts +4 -0
- package/dist/types/compat/index.d.ts.map +1 -0
- package/dist/types/compat/v1.d.ts +15 -0
- package/dist/types/compat/v1.d.ts.map +1 -0
- package/dist/types/config/defaults.d.ts +3 -0
- package/dist/types/config/defaults.d.ts.map +1 -0
- package/dist/types/config/index.d.ts +9 -0
- package/dist/types/config/index.d.ts.map +1 -0
- package/dist/types/config/schema.d.ts +12 -0
- package/dist/types/config/schema.d.ts.map +1 -0
- package/dist/types/constants/defaults.d.ts +15 -0
- package/dist/types/constants/defaults.d.ts.map +1 -0
- package/dist/types/constants/errors.d.ts +21 -0
- package/dist/types/constants/errors.d.ts.map +1 -0
- package/dist/types/constants/index.d.ts +14 -0
- package/dist/types/constants/index.d.ts.map +1 -0
- package/dist/types/constants/signals.d.ts +6 -0
- package/dist/types/constants/signals.d.ts.map +1 -0
- package/dist/types/constants/timeouts.d.ts +16 -0
- package/dist/types/constants/timeouts.d.ts.map +1 -0
- package/dist/types/core/acquire.d.ts +4 -0
- package/dist/types/core/acquire.d.ts.map +1 -0
- package/dist/types/core/buildLockData.d.ts +4 -0
- package/dist/types/core/buildLockData.d.ts.map +1 -0
- package/dist/types/core/check.d.ts +6 -0
- package/dist/types/core/check.d.ts.map +1 -0
- package/dist/types/core/cleanup.d.ts +14 -0
- package/dist/types/core/cleanup.d.ts.map +1 -0
- package/dist/types/core/handle.d.ts +4 -0
- package/dist/types/core/handle.d.ts.map +1 -0
- package/dist/types/core/index.d.ts +9 -0
- package/dist/types/core/index.d.ts.map +1 -0
- package/dist/types/core/list.d.ts +4 -0
- package/dist/types/core/list.d.ts.map +1 -0
- package/dist/types/core/release.d.ts +4 -0
- package/dist/types/core/release.d.ts.map +1 -0
- package/dist/types/errors/AbortError.d.ts +8 -0
- package/dist/types/errors/AbortError.d.ts.map +1 -0
- package/dist/types/errors/ConflictError.d.ts +9 -0
- package/dist/types/errors/ConflictError.d.ts.map +1 -0
- package/dist/types/errors/IOError.d.ts +10 -0
- package/dist/types/errors/IOError.d.ts.map +1 -0
- package/dist/types/errors/LockError.d.ts +12 -0
- package/dist/types/errors/LockError.d.ts.map +1 -0
- package/dist/types/errors/PermissionError.d.ts +9 -0
- package/dist/types/errors/PermissionError.d.ts.map +1 -0
- package/dist/types/errors/StaleError.d.ts +11 -0
- package/dist/types/errors/StaleError.d.ts.map +1 -0
- package/dist/types/errors/TimeoutError.d.ts +9 -0
- package/dist/types/errors/TimeoutError.d.ts.map +1 -0
- package/dist/types/errors/ValidationError.d.ts +9 -0
- package/dist/types/errors/ValidationError.d.ts.map +1 -0
- package/dist/types/errors/index.d.ts +14 -0
- package/dist/types/errors/index.d.ts.map +1 -0
- package/dist/types/events/emitter.d.ts +12 -0
- package/dist/types/events/emitter.d.ts.map +1 -0
- package/dist/types/events/index.d.ts +3 -0
- package/dist/types/events/index.d.ts.map +1 -0
- package/dist/types/events/types.d.ts +3 -0
- package/dist/types/events/types.d.ts.map +1 -0
- package/dist/types/hooks/afterLock.d.ts +7 -0
- package/dist/types/hooks/afterLock.d.ts.map +1 -0
- package/dist/types/hooks/afterUnlock.d.ts +7 -0
- package/dist/types/hooks/afterUnlock.d.ts.map +1 -0
- package/dist/types/hooks/beforeLock.d.ts +7 -0
- package/dist/types/hooks/beforeLock.d.ts.map +1 -0
- package/dist/types/hooks/beforeUnlock.d.ts +7 -0
- package/dist/types/hooks/beforeUnlock.d.ts.map +1 -0
- package/dist/types/hooks/index.d.ts +9 -0
- package/dist/types/hooks/index.d.ts.map +1 -0
- package/dist/types/hooks/onError.d.ts +6 -0
- package/dist/types/hooks/onError.d.ts.map +1 -0
- package/dist/types/hooks/onStale.d.ts +7 -0
- package/dist/types/hooks/onStale.d.ts.map +1 -0
- package/dist/types/hooks/onTimeout.d.ts +6 -0
- package/dist/types/hooks/onTimeout.d.ts.map +1 -0
- package/dist/types/index.d.ts +22 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/logger/console.d.ts +3 -0
- package/dist/types/logger/console.d.ts.map +1 -0
- package/dist/types/logger/debug.d.ts +3 -0
- package/dist/types/logger/debug.d.ts.map +1 -0
- package/dist/types/logger/index.d.ts +8 -0
- package/dist/types/logger/index.d.ts.map +1 -0
- package/dist/types/logger/noop.d.ts +3 -0
- package/dist/types/logger/noop.d.ts.map +1 -0
- package/dist/types/meta/index.d.ts +3 -0
- package/dist/types/meta/index.d.ts.map +1 -0
- package/dist/types/meta/package.d.ts +8 -0
- package/dist/types/meta/package.d.ts.map +1 -0
- package/dist/types/meta/version.d.ts +14 -0
- package/dist/types/meta/version.d.ts.map +1 -0
- package/dist/types/middleware/index.d.ts +10 -0
- package/dist/types/middleware/index.d.ts.map +1 -0
- package/dist/types/middleware/logging.d.ts +3 -0
- package/dist/types/middleware/logging.d.ts.map +1 -0
- package/dist/types/middleware/metrics.d.ts +13 -0
- package/dist/types/middleware/metrics.d.ts.map +1 -0
- package/dist/types/middleware/retry.d.ts +5 -0
- package/dist/types/middleware/retry.d.ts.map +1 -0
- package/dist/types/middleware/timeout.d.ts +7 -0
- package/dist/types/middleware/timeout.d.ts.map +1 -0
- package/dist/types/platform/darwin.d.ts +5 -0
- package/dist/types/platform/darwin.d.ts.map +1 -0
- package/dist/types/platform/index.d.ts +6 -0
- package/dist/types/platform/index.d.ts.map +1 -0
- package/dist/types/platform/linux.d.ts +6 -0
- package/dist/types/platform/linux.d.ts.map +1 -0
- package/dist/types/platform/unix.d.ts +8 -0
- package/dist/types/platform/unix.d.ts.map +1 -0
- package/dist/types/platform/windows.d.ts +7 -0
- package/dist/types/platform/windows.d.ts.map +1 -0
- package/dist/types/plugins/cleanup.d.ts +4 -0
- package/dist/types/plugins/cleanup.d.ts.map +1 -0
- package/dist/types/plugins/heartbeat.d.ts +7 -0
- package/dist/types/plugins/heartbeat.d.ts.map +1 -0
- package/dist/types/plugins/index.d.ts +8 -0
- package/dist/types/plugins/index.d.ts.map +1 -0
- package/dist/types/plugins/pid.d.ts +5 -0
- package/dist/types/plugins/pid.d.ts.map +1 -0
- package/dist/types/plugins/stale.d.ts +9 -0
- package/dist/types/plugins/stale.d.ts.map +1 -0
- package/dist/types/plugins/ttl.d.ts +7 -0
- package/dist/types/plugins/ttl.d.ts.map +1 -0
- package/dist/types/promise/index.d.ts +3 -0
- package/dist/types/promise/index.d.ts.map +1 -0
- package/dist/types/promise/lock.d.ts +6 -0
- package/dist/types/promise/lock.d.ts.map +1 -0
- package/dist/types/promise/withLock.d.ts +7 -0
- package/dist/types/promise/withLock.d.ts.map +1 -0
- package/dist/types/registry/global.d.ts +15 -0
- package/dist/types/registry/global.d.ts.map +1 -0
- package/dist/types/registry/index.d.ts +3 -0
- package/dist/types/registry/index.d.ts.map +1 -0
- package/dist/types/registry/local.d.ts +10 -0
- package/dist/types/registry/local.d.ts.map +1 -0
- package/dist/types/strategies/advisory.d.ts +4 -0
- package/dist/types/strategies/advisory.d.ts.map +1 -0
- package/dist/types/strategies/exclusive.d.ts +4 -0
- package/dist/types/strategies/exclusive.d.ts.map +1 -0
- package/dist/types/strategies/index.d.ts +9 -0
- package/dist/types/strategies/index.d.ts.map +1 -0
- package/dist/types/strategies/optimistic.d.ts +8 -0
- package/dist/types/strategies/optimistic.d.ts.map +1 -0
- package/dist/types/strategies/shared.d.ts +4 -0
- package/dist/types/strategies/shared.d.ts.map +1 -0
- package/dist/types/sync/check.d.ts +4 -0
- package/dist/types/sync/check.d.ts.map +1 -0
- package/dist/types/sync/index.d.ts +4 -0
- package/dist/types/sync/index.d.ts.map +1 -0
- package/dist/types/sync/lock.d.ts +7 -0
- package/dist/types/sync/lock.d.ts.map +1 -0
- package/dist/types/sync/unlock.d.ts +3 -0
- package/dist/types/sync/unlock.d.ts.map +1 -0
- package/dist/types/types/adapter.d.ts +21 -0
- package/dist/types/types/adapter.d.ts.map +1 -0
- package/dist/types/types/events.d.ts +37 -0
- package/dist/types/types/events.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +8 -0
- package/dist/types/types/index.d.ts.map +1 -0
- package/dist/types/types/lock.d.ts +38 -0
- package/dist/types/types/lock.d.ts.map +1 -0
- package/dist/types/types/logger.d.ts +21 -0
- package/dist/types/types/logger.d.ts.map +1 -0
- package/dist/types/types/options.d.ts +52 -0
- package/dist/types/types/options.d.ts.map +1 -0
- package/dist/types/types/state.d.ts +34 -0
- package/dist/types/types/state.d.ts.map +1 -0
- package/dist/types/types/strategy.d.ts +24 -0
- package/dist/types/types/strategy.d.ts.map +1 -0
- package/dist/types/utils/backoff.d.ts +6 -0
- package/dist/types/utils/backoff.d.ts.map +1 -0
- package/dist/types/utils/fs.d.ts +12 -0
- package/dist/types/utils/fs.d.ts.map +1 -0
- package/dist/types/utils/hash.d.ts +7 -0
- package/dist/types/utils/hash.d.ts.map +1 -0
- package/dist/types/utils/hostname.d.ts +9 -0
- package/dist/types/utils/hostname.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +14 -0
- package/dist/types/utils/index.d.ts.map +1 -0
- package/dist/types/utils/parse.d.ts +7 -0
- package/dist/types/utils/parse.d.ts.map +1 -0
- package/dist/types/utils/path.d.ts +10 -0
- package/dist/types/utils/path.d.ts.map +1 -0
- package/dist/types/utils/pid.d.ts +11 -0
- package/dist/types/utils/pid.d.ts.map +1 -0
- package/dist/types/utils/platform.d.ts +12 -0
- package/dist/types/utils/platform.d.ts.map +1 -0
- package/dist/types/utils/random.d.ts +7 -0
- package/dist/types/utils/random.d.ts.map +1 -0
- package/dist/types/utils/retry.d.ts +10 -0
- package/dist/types/utils/retry.d.ts.map +1 -0
- package/dist/types/utils/serialize.d.ts +7 -0
- package/dist/types/utils/serialize.d.ts.map +1 -0
- package/dist/types/utils/time.d.ts +12 -0
- package/dist/types/utils/time.d.ts.map +1 -0
- package/dist/types/utils/validate.d.ts +5 -0
- package/dist/types/utils/validate.d.ts.map +1 -0
- package/package.json +132 -3
- package/src/adapters/atomic.ts +39 -0
- package/src/adapters/fs.ts +30 -0
- package/src/adapters/index.ts +31 -0
- package/src/adapters/mkdir.ts +32 -0
- package/src/adapters/symlink.ts +30 -0
- package/src/async/check.ts +15 -0
- package/src/async/index.ts +3 -0
- package/src/async/lock.ts +15 -0
- package/src/async/unlock.ts +11 -0
- package/src/cli/commands/cleanup.ts +28 -0
- package/src/cli/commands/list.ts +27 -0
- package/src/cli/commands/lock.ts +27 -0
- package/src/cli/commands/status.ts +26 -0
- package/src/cli/commands/unlock.ts +20 -0
- package/src/cli/formatters/index.ts +18 -0
- package/src/cli/formatters/json.ts +18 -0
- package/src/cli/formatters/table.ts +26 -0
- package/src/cli/formatters/text.ts +22 -0
- package/src/cli/index.ts +61 -0
- package/src/compat/cjs.ts +11 -0
- package/src/compat/esm.ts +11 -0
- package/src/compat/index.ts +3 -0
- package/src/compat/v1.ts +35 -0
- package/src/config/defaults.ts +20 -0
- package/src/config/index.ts +24 -0
- package/src/config/schema.ts +66 -0
- package/src/constants/defaults.ts +14 -0
- package/src/constants/errors.ts +39 -0
- package/src/constants/index.ts +14 -0
- package/src/constants/signals.ts +26 -0
- package/src/constants/timeouts.ts +18 -0
- package/src/core/acquire.ts +54 -0
- package/src/core/buildLockData.ts +25 -0
- package/src/core/check.ts +66 -0
- package/src/core/cleanup.ts +53 -0
- package/src/core/handle.ts +62 -0
- package/src/core/index.ts +8 -0
- package/src/core/list.ts +38 -0
- package/src/core/release.ts +35 -0
- package/src/errors/AbortError.ts +25 -0
- package/src/errors/ConflictError.ts +28 -0
- package/src/errors/IOError.ts +39 -0
- package/src/errors/LockError.ts +39 -0
- package/src/errors/PermissionError.ts +35 -0
- package/src/errors/StaleError.ts +41 -0
- package/src/errors/TimeoutError.ts +28 -0
- package/src/errors/ValidationError.ts +28 -0
- package/src/errors/index.ts +28 -0
- package/src/events/emitter.ts +50 -0
- package/src/events/index.ts +2 -0
- package/src/events/types.ts +16 -0
- package/src/hooks/afterLock.ts +24 -0
- package/src/hooks/afterUnlock.ts +24 -0
- package/src/hooks/beforeLock.ts +28 -0
- package/src/hooks/beforeUnlock.ts +24 -0
- package/src/hooks/deps +0 -0
- package/src/hooks/index.ts +25 -0
- package/src/hooks/onError.ts +22 -0
- package/src/hooks/onStale.ts +24 -0
- package/src/hooks/onTimeout.ts +27 -0
- package/src/index.ts +25 -0
- package/src/logger/console.ts +39 -0
- package/src/logger/debug.ts +29 -0
- package/src/logger/index.ts +20 -0
- package/src/logger/noop.ts +13 -0
- package/src/meta/index.ts +2 -0
- package/src/meta/package.ts +29 -0
- package/src/meta/version.ts +26 -0
- package/src/middleware/index.ts +18 -0
- package/src/middleware/logging.ts +21 -0
- package/src/middleware/metrics.ts +44 -0
- package/src/middleware/retry.ts +25 -0
- package/src/middleware/timeout.ts +34 -0
- package/src/platform/darwin.ts +19 -0
- package/src/platform/index.ts +6 -0
- package/src/platform/linux.ts +32 -0
- package/src/platform/unix.ts +36 -0
- package/src/platform/windows.ts +26 -0
- package/src/plugins/cleanup.ts +45 -0
- package/src/plugins/heartbeat.ts +42 -0
- package/src/plugins/index.ts +7 -0
- package/src/plugins/pid.ts +26 -0
- package/src/plugins/stale.ts +33 -0
- package/src/plugins/ttl.ts +27 -0
- package/src/promise/index.ts +2 -0
- package/src/promise/lock.ts +23 -0
- package/src/promise/withLock.ts +30 -0
- package/src/registry/global.ts +39 -0
- package/src/registry/index.ts +11 -0
- package/src/registry/local.ts +37 -0
- package/src/strategies/advisory.ts +21 -0
- package/src/strategies/exclusive.ts +21 -0
- package/src/strategies/index.ts +31 -0
- package/src/strategies/optimistic.ts +29 -0
- package/src/strategies/shared.ts +23 -0
- package/src/sync/check.ts +43 -0
- package/src/sync/index.ts +3 -0
- package/src/sync/lock.ts +38 -0
- package/src/sync/unlock.ts +19 -0
- package/src/types/adapter.ts +23 -0
- package/src/types/events.ts +63 -0
- package/src/types/index.ts +24 -0
- package/src/types/lock.ts +40 -0
- package/src/types/logger.ts +23 -0
- package/src/types/options.ts +57 -0
- package/src/types/state.ts +36 -0
- package/src/types/strategy.ts +31 -0
- package/src/utils/backoff.ts +52 -0
- package/src/utils/fs.ts +93 -0
- package/src/utils/hash.ts +25 -0
- package/src/utils/hostname.ts +31 -0
- package/src/utils/index.ts +13 -0
- package/src/utils/parse.ts +43 -0
- package/src/utils/path.ts +43 -0
- package/src/utils/pid.ts +36 -0
- package/src/utils/platform.ts +45 -0
- package/src/utils/random.ts +31 -0
- package/src/utils/retry.ts +59 -0
- package/src/utils/serialize.ts +31 -0
- package/src/utils/time.ts +51 -0
- package/src/utils/validate.ts +45 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { acquireLock as lock } from '../core/acquire.js';
|
|
2
|
+
export { isLocked as check } from '../core/check.js';
|
|
3
|
+
export { withLock } from '../promise/withLock.js';
|
|
4
|
+
export { lockSync } from '../sync/lock.js';
|
|
5
|
+
export { unlockSync } from '../sync/unlock.js';
|
|
6
|
+
export { checkSync } from '../sync/check.js';
|
|
7
|
+
|
|
8
|
+
export { LockError } from '../errors/LockError.js';
|
|
9
|
+
export { ConflictError } from '../errors/ConflictError.js';
|
|
10
|
+
export { TimeoutError } from '../errors/TimeoutError.js';
|
|
11
|
+
export { StaleError } from '../errors/StaleError.js';
|
package/src/compat/v1.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { acquireLock } from '../core/acquire.js';
|
|
2
|
+
import { releaseLock } from '../core/release.js';
|
|
3
|
+
import { isLocked } from '../core/check.js';
|
|
4
|
+
import type { LockHandle } from '../types/lock.js';
|
|
5
|
+
|
|
6
|
+
export interface V1LockOptions {
|
|
7
|
+
wait?: number;
|
|
8
|
+
stale?: number;
|
|
9
|
+
retries?: number;
|
|
10
|
+
retryWait?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function lock(file: string, options: V1LockOptions = {}): Promise<() => Promise<void>> {
|
|
14
|
+
const handle: LockHandle = await acquireLock(file, {
|
|
15
|
+
...(options.wait !== undefined ? { timeout: options.wait } : {}),
|
|
16
|
+
...(options.stale !== undefined ? { staleAge: options.stale } : {}),
|
|
17
|
+
...(options.retries !== undefined ? { retries: options.retries } : {}),
|
|
18
|
+
...(options.retryWait !== undefined ? { retryDelay: options.retryWait } : {}),
|
|
19
|
+
removeStale: true,
|
|
20
|
+
});
|
|
21
|
+
return () => handle.release();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function unlock(file: string): Promise<void> {
|
|
25
|
+
const { unlinkSafe } = await import('../utils/fs.js');
|
|
26
|
+
await unlinkSafe(file + '.lock');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function check(file: string, options: V1LockOptions = {}): Promise<boolean> {
|
|
30
|
+
return isLocked(file, {
|
|
31
|
+
...(options.stale !== undefined ? { staleAge: options.stale } : {}),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const v1 = { lock, unlock, check };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { GlobalOptions } from '../types/options.js';
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_LOCK_EXTENSION,
|
|
4
|
+
DEFAULT_TTL,
|
|
5
|
+
DEFAULT_STALE_AGE,
|
|
6
|
+
DEFAULT_RETRIES,
|
|
7
|
+
DEFAULT_STRATEGY,
|
|
8
|
+
DEFAULT_ADAPTER,
|
|
9
|
+
} from '../constants/defaults.js';
|
|
10
|
+
|
|
11
|
+
export const DEFAULT_GLOBAL_OPTIONS: Required<GlobalOptions> = {
|
|
12
|
+
lockExtension: DEFAULT_LOCK_EXTENSION,
|
|
13
|
+
defaultTtl: DEFAULT_TTL,
|
|
14
|
+
defaultStaleAge: DEFAULT_STALE_AGE,
|
|
15
|
+
defaultRetries: DEFAULT_RETRIES,
|
|
16
|
+
defaultStrategy: DEFAULT_STRATEGY,
|
|
17
|
+
defaultAdapter: DEFAULT_ADAPTER,
|
|
18
|
+
logLevel: 'silent',
|
|
19
|
+
tmpDir: process.env['TMPDIR'] ?? '/tmp',
|
|
20
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export { DEFAULT_GLOBAL_OPTIONS } from './defaults.js';
|
|
2
|
+
export { CONFIG_SCHEMA } from './schema.js';
|
|
3
|
+
export type { ConfigSchema } from './schema.js';
|
|
4
|
+
|
|
5
|
+
import type { GlobalOptions } from '../types/options.js';
|
|
6
|
+
import { DEFAULT_GLOBAL_OPTIONS } from './defaults.js';
|
|
7
|
+
|
|
8
|
+
let globalConfig: Required<GlobalOptions> = { ...DEFAULT_GLOBAL_OPTIONS };
|
|
9
|
+
|
|
10
|
+
export function getConfig(): Required<GlobalOptions> {
|
|
11
|
+
return { ...globalConfig };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function setConfig(options: Partial<GlobalOptions>): void {
|
|
15
|
+
globalConfig = { ...globalConfig, ...options };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function resetConfig(): void {
|
|
19
|
+
globalConfig = { ...DEFAULT_GLOBAL_OPTIONS };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function getConfigValue<K extends keyof GlobalOptions>(key: K): Required<GlobalOptions>[K] {
|
|
23
|
+
return globalConfig[key];
|
|
24
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { GlobalOptions } from '../types/options.js';
|
|
2
|
+
|
|
3
|
+
export type ConfigSchema = {
|
|
4
|
+
[K in keyof GlobalOptions]: {
|
|
5
|
+
type: string;
|
|
6
|
+
required: boolean;
|
|
7
|
+
default?: GlobalOptions[K];
|
|
8
|
+
description: string;
|
|
9
|
+
validate?: (value: unknown) => boolean;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const CONFIG_SCHEMA: ConfigSchema = {
|
|
14
|
+
lockExtension: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
required: false,
|
|
17
|
+
default: '.lock',
|
|
18
|
+
description: 'File extension appended to the target path to form the lock path',
|
|
19
|
+
validate: (v) => typeof v === 'string' && v.startsWith('.'),
|
|
20
|
+
},
|
|
21
|
+
defaultTtl: {
|
|
22
|
+
type: 'number',
|
|
23
|
+
required: false,
|
|
24
|
+
default: 30_000,
|
|
25
|
+
description: 'Default TTL in milliseconds for all locks',
|
|
26
|
+
validate: (v) => typeof v === 'number' && v > 0,
|
|
27
|
+
},
|
|
28
|
+
defaultStaleAge: {
|
|
29
|
+
type: 'number',
|
|
30
|
+
required: false,
|
|
31
|
+
default: 30_000,
|
|
32
|
+
description: 'Default stale age threshold in milliseconds',
|
|
33
|
+
validate: (v) => typeof v === 'number' && v > 0,
|
|
34
|
+
},
|
|
35
|
+
defaultRetries: {
|
|
36
|
+
type: 'number',
|
|
37
|
+
required: false,
|
|
38
|
+
default: 5,
|
|
39
|
+
description: 'Default number of retries when acquiring a lock',
|
|
40
|
+
validate: (v) => typeof v === 'number' && v >= 0,
|
|
41
|
+
},
|
|
42
|
+
defaultStrategy: {
|
|
43
|
+
type: 'string',
|
|
44
|
+
required: false,
|
|
45
|
+
default: 'exclusive',
|
|
46
|
+
description: 'Default locking strategy',
|
|
47
|
+
},
|
|
48
|
+
defaultAdapter: {
|
|
49
|
+
type: 'string',
|
|
50
|
+
required: false,
|
|
51
|
+
default: 'atomic',
|
|
52
|
+
description: 'Default adapter to use for lock file operations',
|
|
53
|
+
},
|
|
54
|
+
logLevel: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
required: false,
|
|
57
|
+
default: 'silent',
|
|
58
|
+
description: 'Log level for internal logging',
|
|
59
|
+
},
|
|
60
|
+
tmpDir: {
|
|
61
|
+
type: 'string',
|
|
62
|
+
required: false,
|
|
63
|
+
description: 'Temporary directory for atomic write operations',
|
|
64
|
+
validate: (v) => typeof v === 'string' && v.length > 0,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const DEFAULT_LOCK_EXTENSION = '.lock';
|
|
2
|
+
export const DEFAULT_TTL = 30_000;
|
|
3
|
+
export const DEFAULT_STALE_AGE = 30_000;
|
|
4
|
+
export const DEFAULT_RETRIES = 5;
|
|
5
|
+
export const DEFAULT_RETRY_DELAY = 100;
|
|
6
|
+
export const DEFAULT_RETRY_MAX_DELAY = 5_000;
|
|
7
|
+
export const DEFAULT_HEARTBEAT_INTERVAL = 5_000;
|
|
8
|
+
export const DEFAULT_TIMEOUT = 60_000;
|
|
9
|
+
export const DEFAULT_STRATEGY = 'exclusive';
|
|
10
|
+
export const DEFAULT_ADAPTER = 'atomic';
|
|
11
|
+
export const DEFAULT_LOCK_VERSION = 1;
|
|
12
|
+
export const DEFAULT_NONCE_LENGTH = 16;
|
|
13
|
+
export const DEFAULT_CONCURRENCY = 1;
|
|
14
|
+
export const DEFAULT_META = {} as const;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export const ERROR_CODES = {
|
|
2
|
+
LOCK_CONFLICT: 'ELOCK_CONFLICT',
|
|
3
|
+
LOCK_TIMEOUT: 'ELOCK_TIMEOUT',
|
|
4
|
+
LOCK_STALE: 'ELOCK_STALE',
|
|
5
|
+
LOCK_EXPIRED: 'ELOCK_EXPIRED',
|
|
6
|
+
LOCK_NOT_OWNED: 'ELOCK_NOT_OWNED',
|
|
7
|
+
LOCK_NOT_FOUND: 'ELOCK_NOT_FOUND',
|
|
8
|
+
LOCK_INVALID: 'ELOCK_INVALID',
|
|
9
|
+
LOCK_CORRUPT: 'ELOCK_CORRUPT',
|
|
10
|
+
LOCK_PERMISSION: 'ELOCK_PERMISSION',
|
|
11
|
+
LOCK_IO: 'ELOCK_IO',
|
|
12
|
+
LOCK_VALIDATION: 'ELOCK_VALIDATION',
|
|
13
|
+
LOCK_ABORTED: 'ELOCK_ABORTED',
|
|
14
|
+
LOCK_NOT_ACQUIRED: 'ELOCK_NOT_ACQUIRED',
|
|
15
|
+
LOCK_ALREADY_ACQUIRED: 'ELOCK_ALREADY_ACQUIRED',
|
|
16
|
+
LOCK_REFRESH_FAILED: 'ELOCK_REFRESH_FAILED',
|
|
17
|
+
LOCK_RELEASE_FAILED: 'ELOCK_RELEASE_FAILED',
|
|
18
|
+
} as const;
|
|
19
|
+
|
|
20
|
+
export type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];
|
|
21
|
+
|
|
22
|
+
export const ERROR_MESSAGES: Record<ErrorCode, string> = {
|
|
23
|
+
ELOCK_CONFLICT: 'Lock is already held by another process',
|
|
24
|
+
ELOCK_TIMEOUT: 'Timed out waiting to acquire lock',
|
|
25
|
+
ELOCK_STALE: 'Lock file is stale',
|
|
26
|
+
ELOCK_EXPIRED: 'Lock file has expired',
|
|
27
|
+
ELOCK_NOT_OWNED: 'Lock is not owned by this process',
|
|
28
|
+
ELOCK_NOT_FOUND: 'Lock file not found',
|
|
29
|
+
ELOCK_INVALID: 'Lock file is invalid',
|
|
30
|
+
ELOCK_CORRUPT: 'Lock file is corrupt or unreadable',
|
|
31
|
+
ELOCK_PERMISSION: 'Insufficient permissions to acquire lock',
|
|
32
|
+
ELOCK_IO: 'I/O error while operating on lock',
|
|
33
|
+
ELOCK_VALIDATION: 'Lock path or options failed validation',
|
|
34
|
+
ELOCK_ABORTED: 'Lock acquisition was aborted',
|
|
35
|
+
ELOCK_NOT_ACQUIRED: 'No lock has been acquired',
|
|
36
|
+
ELOCK_ALREADY_ACQUIRED: 'Lock has already been acquired',
|
|
37
|
+
ELOCK_REFRESH_FAILED: 'Failed to refresh lock heartbeat',
|
|
38
|
+
ELOCK_RELEASE_FAILED: 'Failed to release lock',
|
|
39
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from './defaults.js';
|
|
2
|
+
export * from './errors.js';
|
|
3
|
+
export * from './timeouts.js';
|
|
4
|
+
export * from './signals.js';
|
|
5
|
+
|
|
6
|
+
export const LOCK_FILE_MAGIC = 'atomic-lockfile/v1';
|
|
7
|
+
export const LOCK_DATA_ENCODING = 'utf-8' as const;
|
|
8
|
+
export const LOCK_FILE_MODE = 0o644;
|
|
9
|
+
export const LOCK_DIR_MODE = 0o755;
|
|
10
|
+
export const LOCK_OPEN_FLAGS_EXCLUSIVE = 'wx';
|
|
11
|
+
export const LOCK_OPEN_FLAGS_READ = 'r';
|
|
12
|
+
export const LOCK_TMP_PREFIX = '.atomic-lockfile-tmp-';
|
|
13
|
+
export const LOCK_PID_FILE_SUFFIX = '.pid';
|
|
14
|
+
export const LOCK_BACKUP_SUFFIX = '.bak';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const CLEANUP_SIGNALS = [
|
|
2
|
+
'SIGINT',
|
|
3
|
+
'SIGTERM',
|
|
4
|
+
'SIGHUP',
|
|
5
|
+
'SIGQUIT',
|
|
6
|
+
'SIGABRT',
|
|
7
|
+
] as const;
|
|
8
|
+
|
|
9
|
+
export type CleanupSignal = (typeof CLEANUP_SIGNALS)[number];
|
|
10
|
+
|
|
11
|
+
export const PROCESS_EXIT_EVENTS = [
|
|
12
|
+
'exit',
|
|
13
|
+
'beforeExit',
|
|
14
|
+
'uncaughtException',
|
|
15
|
+
'unhandledRejection',
|
|
16
|
+
] as const;
|
|
17
|
+
|
|
18
|
+
export type ProcessExitEvent = (typeof PROCESS_EXIT_EVENTS)[number];
|
|
19
|
+
|
|
20
|
+
export const SIGNAL_DESCRIPTIONS: Record<CleanupSignal, string> = {
|
|
21
|
+
SIGINT: 'Interrupt from keyboard (Ctrl+C)',
|
|
22
|
+
SIGTERM: 'Termination signal',
|
|
23
|
+
SIGHUP: 'Hangup detected on controlling terminal',
|
|
24
|
+
SIGQUIT: 'Quit from keyboard',
|
|
25
|
+
SIGABRT: 'Abort signal from abort()',
|
|
26
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const TIMEOUT_ACQUIRE = 60_000;
|
|
2
|
+
export const TIMEOUT_RELEASE = 10_000;
|
|
3
|
+
export const TIMEOUT_REFRESH = 5_000;
|
|
4
|
+
export const TIMEOUT_CHECK = 2_000;
|
|
5
|
+
export const TIMEOUT_LIST = 5_000;
|
|
6
|
+
export const TIMEOUT_CLEANUP = 30_000;
|
|
7
|
+
|
|
8
|
+
export const INTERVAL_HEARTBEAT = 5_000;
|
|
9
|
+
export const INTERVAL_POLL = 50;
|
|
10
|
+
export const INTERVAL_STALE_CHECK = 10_000;
|
|
11
|
+
|
|
12
|
+
export const DELAY_INITIAL_RETRY = 100;
|
|
13
|
+
export const DELAY_MAX_RETRY = 5_000;
|
|
14
|
+
export const DELAY_BACKOFF_FACTOR = 2;
|
|
15
|
+
export const DELAY_JITTER_MAX = 50;
|
|
16
|
+
|
|
17
|
+
export const AGE_STALE_DEFAULT = 30_000;
|
|
18
|
+
export const AGE_EXPIRED_DEFAULT = 60_000;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { AcquireOptions } from '../types/options.js';
|
|
2
|
+
import type { LockHandle } from '../types/lock.js';
|
|
3
|
+
import { resolveLockPath } from '../utils/path.js';
|
|
4
|
+
import { getAdapter } from '../adapters/index.js';
|
|
5
|
+
import { serializeLockData } from '../utils/serialize.js';
|
|
6
|
+
import { withRetry } from '../utils/retry.js';
|
|
7
|
+
import { buildLockData } from './buildLockData.js';
|
|
8
|
+
import { checkStale } from '../plugins/stale.js';
|
|
9
|
+
import { unlinkSafe } from '../utils/fs.js';
|
|
10
|
+
import { readFileSafe, fileExists } from '../utils/fs.js';
|
|
11
|
+
import { safeDeserializeLockData } from '../utils/serialize.js';
|
|
12
|
+
import { createHandle } from './handle.js';
|
|
13
|
+
import { ConflictError } from '../errors/ConflictError.js';
|
|
14
|
+
import { DEFAULT_STALE_AGE, DEFAULT_ADAPTER, DEFAULT_LOCK_EXTENSION } from '../constants/defaults.js';
|
|
15
|
+
|
|
16
|
+
export async function acquireLock(filePath: string, options: AcquireOptions = {}): Promise<LockHandle> {
|
|
17
|
+
const lockPath = resolveLockPath(filePath, options.lockExtension ?? DEFAULT_LOCK_EXTENSION);
|
|
18
|
+
const adapter = getAdapter(options.adapter ?? DEFAULT_ADAPTER);
|
|
19
|
+
const staleAge = options.staleAge ?? DEFAULT_STALE_AGE;
|
|
20
|
+
|
|
21
|
+
const data = buildLockData(options);
|
|
22
|
+
const content = serializeLockData(data);
|
|
23
|
+
|
|
24
|
+
const tryAcquire = async (): Promise<void> => {
|
|
25
|
+
const exists = await fileExists(lockPath);
|
|
26
|
+
if (exists) {
|
|
27
|
+
if (options.removeStale) {
|
|
28
|
+
const raw = await readFileSafe(lockPath, filePath, lockPath).catch(() => null);
|
|
29
|
+
const existing = raw ? safeDeserializeLockData(raw) : null;
|
|
30
|
+
if (existing) {
|
|
31
|
+
const staleResult = checkStale(existing, staleAge);
|
|
32
|
+
if (staleResult.isStale) {
|
|
33
|
+
options.onStale?.(lockPath);
|
|
34
|
+
await unlinkSafe(lockPath);
|
|
35
|
+
} else {
|
|
36
|
+
throw new ConflictError(filePath, lockPath, existing);
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
await unlinkSafe(lockPath);
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
const raw = await readFileSafe(lockPath, filePath, lockPath).catch(() => null);
|
|
43
|
+
const existing = raw ? safeDeserializeLockData(raw) : null;
|
|
44
|
+
throw new ConflictError(filePath, lockPath, existing);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
await adapter.acquire(lockPath, content);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
await withRetry(tryAcquire, options);
|
|
51
|
+
options.onAcquired?.(lockPath);
|
|
52
|
+
|
|
53
|
+
return createHandle(filePath, lockPath, data, options);
|
|
54
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { LockData } from '../types/lock.js';
|
|
2
|
+
import type { AcquireOptions } from '../types/options.js';
|
|
3
|
+
import { getUid, getGid } from '../utils/platform.js';
|
|
4
|
+
import { getHostname } from '../utils/hostname.js';
|
|
5
|
+
import { generateNonce } from '../utils/random.js';
|
|
6
|
+
import { DEFAULT_LOCK_VERSION } from '../constants/defaults.js';
|
|
7
|
+
|
|
8
|
+
export function buildLockData(options: AcquireOptions): LockData {
|
|
9
|
+
const now = Date.now();
|
|
10
|
+
const ttl = options.ttl ?? null;
|
|
11
|
+
return {
|
|
12
|
+
pid: process.pid,
|
|
13
|
+
hostname: getHostname(),
|
|
14
|
+
uid: getUid(),
|
|
15
|
+
gid: getGid(),
|
|
16
|
+
created: now,
|
|
17
|
+
updated: now,
|
|
18
|
+
expires: ttl !== null ? now + ttl : null,
|
|
19
|
+
ttl,
|
|
20
|
+
nonce: generateNonce(),
|
|
21
|
+
version: DEFAULT_LOCK_VERSION,
|
|
22
|
+
strategy: options.strategy ?? 'exclusive',
|
|
23
|
+
meta: options.meta ?? {},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { CheckOptions } from '../types/options.js';
|
|
2
|
+
import type { LockFile, LockState } from '../types/lock.js';
|
|
3
|
+
import { resolveLockPath } from '../utils/path.js';
|
|
4
|
+
import { fileExists, getFileMtimeMs } from '../utils/fs.js';
|
|
5
|
+
import { readFileSafe } from '../utils/fs.js';
|
|
6
|
+
import { safeDeserializeLockData } from '../utils/serialize.js';
|
|
7
|
+
import { checkStale } from '../plugins/stale.js';
|
|
8
|
+
import { DEFAULT_LOCK_EXTENSION, DEFAULT_STALE_AGE } from '../constants/defaults.js';
|
|
9
|
+
|
|
10
|
+
export async function checkLock(filePath: string, options: CheckOptions = {}): Promise<LockFile> {
|
|
11
|
+
const lockPath = resolveLockPath(filePath, options.staleAge !== undefined ? DEFAULT_LOCK_EXTENSION : DEFAULT_LOCK_EXTENSION);
|
|
12
|
+
const exists = await fileExists(lockPath);
|
|
13
|
+
|
|
14
|
+
if (!exists) {
|
|
15
|
+
return {
|
|
16
|
+
path: filePath,
|
|
17
|
+
lockPath,
|
|
18
|
+
data: null,
|
|
19
|
+
exists: false,
|
|
20
|
+
readable: false,
|
|
21
|
+
writable: false,
|
|
22
|
+
stale: false,
|
|
23
|
+
expired: false,
|
|
24
|
+
ageMs: 0,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const raw = await readFileSafe(lockPath, filePath, lockPath).catch(() => null);
|
|
29
|
+
const data = raw ? safeDeserializeLockData(raw) : null;
|
|
30
|
+
const mtimeMs = await getFileMtimeMs(lockPath);
|
|
31
|
+
const ageMs = mtimeMs !== null ? Date.now() - mtimeMs : 0;
|
|
32
|
+
|
|
33
|
+
let stale = false;
|
|
34
|
+
let expired = false;
|
|
35
|
+
if (data) {
|
|
36
|
+
const staleResult = checkStale(data, options.staleAge ?? DEFAULT_STALE_AGE);
|
|
37
|
+
stale = staleResult.isStale && staleResult.reason === 'age';
|
|
38
|
+
expired = staleResult.isStale && staleResult.reason === 'expired';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
path: filePath,
|
|
43
|
+
lockPath,
|
|
44
|
+
data,
|
|
45
|
+
exists: true,
|
|
46
|
+
readable: raw !== null,
|
|
47
|
+
writable: true,
|
|
48
|
+
stale,
|
|
49
|
+
expired,
|
|
50
|
+
ageMs,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function isLocked(filePath: string, options: CheckOptions = {}): Promise<boolean> {
|
|
55
|
+
const result = await checkLock(filePath, options);
|
|
56
|
+
return result.exists && !result.stale && !result.expired;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function getLockState(filePath: string, options: CheckOptions = {}): Promise<LockState> {
|
|
60
|
+
const result = await checkLock(filePath, options);
|
|
61
|
+
if (!result.exists) return 'unlocked';
|
|
62
|
+
if (result.expired) return 'expired';
|
|
63
|
+
if (result.stale) return 'stale';
|
|
64
|
+
if (!result.readable) return 'unknown';
|
|
65
|
+
return 'locked';
|
|
66
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { promises as fsp } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { checkStale } from '../plugins/stale.js';
|
|
4
|
+
import { safeDeserializeLockData } from '../utils/serialize.js';
|
|
5
|
+
import { DEFAULT_LOCK_EXTENSION, DEFAULT_STALE_AGE } from '../constants/defaults.js';
|
|
6
|
+
|
|
7
|
+
export interface CleanupResult {
|
|
8
|
+
removed: string[];
|
|
9
|
+
errors: Array<{ path: string; error: Error }>;
|
|
10
|
+
scanned: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function cleanupLocks(
|
|
14
|
+
directory: string,
|
|
15
|
+
options: { extension?: string; staleAge?: number; dryRun?: boolean } = {},
|
|
16
|
+
): Promise<CleanupResult> {
|
|
17
|
+
const ext = options.extension ?? DEFAULT_LOCK_EXTENSION;
|
|
18
|
+
const staleAge = options.staleAge ?? DEFAULT_STALE_AGE;
|
|
19
|
+
const result: CleanupResult = { removed: [], errors: [], scanned: 0 };
|
|
20
|
+
|
|
21
|
+
let entries;
|
|
22
|
+
try {
|
|
23
|
+
entries = await fsp.readdir(directory, { withFileTypes: true, encoding: 'utf-8' });
|
|
24
|
+
} catch (err) {
|
|
25
|
+
result.errors.push({ path: directory, error: err as Error });
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
if (!entry.isFile() || !entry.name.endsWith(ext)) continue;
|
|
31
|
+
const lockPath = join(directory, entry.name);
|
|
32
|
+
result.scanned++;
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const raw = await fsp.readFile(lockPath, 'utf-8');
|
|
36
|
+
const data = safeDeserializeLockData(raw);
|
|
37
|
+
if (!data) {
|
|
38
|
+
if (!options.dryRun) await fsp.unlink(lockPath);
|
|
39
|
+
result.removed.push(lockPath);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const staleResult = checkStale(data, staleAge);
|
|
43
|
+
if (staleResult.isStale) {
|
|
44
|
+
if (!options.dryRun) await fsp.unlink(lockPath);
|
|
45
|
+
result.removed.push(lockPath);
|
|
46
|
+
}
|
|
47
|
+
} catch (err) {
|
|
48
|
+
result.errors.push({ path: lockPath, error: err as Error });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { LockHandle, LockData } from '../types/lock.js';
|
|
2
|
+
import type { AcquireOptions } from '../types/options.js';
|
|
3
|
+
import { releaseLock } from './release.js';
|
|
4
|
+
import { startHeartbeat } from '../plugins/heartbeat.js';
|
|
5
|
+
import type { HeartbeatHandle } from '../plugins/heartbeat.js';
|
|
6
|
+
import { checkStale } from '../plugins/stale.js';
|
|
7
|
+
import { isLockExpiredByTtl } from '../plugins/ttl.js';
|
|
8
|
+
import { DEFAULT_HEARTBEAT_INTERVAL, DEFAULT_STALE_AGE } from '../constants/defaults.js';
|
|
9
|
+
import { promises as fsp } from 'node:fs';
|
|
10
|
+
import { serializeLockData } from '../utils/serialize.js';
|
|
11
|
+
|
|
12
|
+
export function createHandle(
|
|
13
|
+
filePath: string,
|
|
14
|
+
lockPath: string,
|
|
15
|
+
data: LockData,
|
|
16
|
+
options: AcquireOptions,
|
|
17
|
+
): LockHandle {
|
|
18
|
+
let acquired = true;
|
|
19
|
+
let heartbeat: HeartbeatHandle | null = null;
|
|
20
|
+
let currentData = { ...data };
|
|
21
|
+
|
|
22
|
+
if (options.heartbeatInterval !== undefined || options.ttl !== undefined) {
|
|
23
|
+
heartbeat = startHeartbeat(
|
|
24
|
+
lockPath,
|
|
25
|
+
() => currentData,
|
|
26
|
+
options.heartbeatInterval ?? DEFAULT_HEARTBEAT_INTERVAL,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const handle: LockHandle = {
|
|
31
|
+
get path() { return filePath; },
|
|
32
|
+
get lockPath() { return lockPath; },
|
|
33
|
+
get data() { return { ...currentData }; },
|
|
34
|
+
get acquired() { return acquired; },
|
|
35
|
+
|
|
36
|
+
async release() {
|
|
37
|
+
if (!acquired) return;
|
|
38
|
+
heartbeat?.stop();
|
|
39
|
+
await releaseLock(filePath, lockPath, currentData, {});
|
|
40
|
+
acquired = false;
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
async refresh() {
|
|
44
|
+
currentData = { ...currentData, updated: Date.now() };
|
|
45
|
+
await fsp.writeFile(lockPath, serializeLockData(currentData), 'utf-8');
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
isStale() {
|
|
49
|
+
return checkStale(currentData, options.staleAge ?? DEFAULT_STALE_AGE).isStale;
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
isExpired() {
|
|
53
|
+
return isLockExpiredByTtl(currentData);
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
toJSON() {
|
|
57
|
+
return { ...currentData };
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return handle;
|
|
62
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { acquireLock } from './acquire.js';
|
|
2
|
+
export { releaseLock } from './release.js';
|
|
3
|
+
export { checkLock, isLocked, getLockState } from './check.js';
|
|
4
|
+
export { createHandle } from './handle.js';
|
|
5
|
+
export { listLocks } from './list.js';
|
|
6
|
+
export { cleanupLocks } from './cleanup.js';
|
|
7
|
+
export type { CleanupResult } from './cleanup.js';
|
|
8
|
+
export { buildLockData } from './buildLockData.js';
|
package/src/core/list.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { promises as fsp } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import type { ListOptions } from '../types/options.js';
|
|
4
|
+
import type { LockFile } from '../types/lock.js';
|
|
5
|
+
import { checkLock } from './check.js';
|
|
6
|
+
import { DEFAULT_LOCK_EXTENSION } from '../constants/defaults.js';
|
|
7
|
+
|
|
8
|
+
export async function listLocks(options: ListOptions = {}): Promise<LockFile[]> {
|
|
9
|
+
const dir = options.directory ?? process.cwd();
|
|
10
|
+
const ext = options.lockExtension ?? DEFAULT_LOCK_EXTENSION;
|
|
11
|
+
const lockFiles: LockFile[] = [];
|
|
12
|
+
|
|
13
|
+
const scanDir = async (directory: string): Promise<void> => {
|
|
14
|
+
let entries;
|
|
15
|
+
try {
|
|
16
|
+
entries = await fsp.readdir(directory, { withFileTypes: true, encoding: 'utf-8' });
|
|
17
|
+
} catch {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
for (const entry of entries) {
|
|
22
|
+
const fullPath = join(directory, entry.name);
|
|
23
|
+
if (entry.isDirectory() && options.recursive) {
|
|
24
|
+
await scanDir(fullPath);
|
|
25
|
+
} else if (entry.isFile() && entry.name.endsWith(ext)) {
|
|
26
|
+
const filePath = fullPath.slice(0, -ext.length);
|
|
27
|
+
const lockFile = await checkLock(filePath).catch(() => null);
|
|
28
|
+
if (!lockFile) continue;
|
|
29
|
+
if (!options.includeStale && lockFile.stale) continue;
|
|
30
|
+
if (!options.includeExpired && lockFile.expired) continue;
|
|
31
|
+
lockFiles.push(lockFile);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
await scanDir(dir);
|
|
37
|
+
return lockFiles;
|
|
38
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ReleaseOptions } from '../types/options.js';
|
|
2
|
+
import type { LockData } from '../types/lock.js';
|
|
3
|
+
import { getAdapter } from '../adapters/index.js';
|
|
4
|
+
import { fileExists, readFileSafe } from '../utils/fs.js';
|
|
5
|
+
import { safeDeserializeLockData } from '../utils/serialize.js';
|
|
6
|
+
import { LockError } from '../errors/LockError.js';
|
|
7
|
+
import { ERROR_CODES } from '../constants/errors.js';
|
|
8
|
+
import { DEFAULT_ADAPTER, DEFAULT_LOCK_EXTENSION } from '../constants/defaults.js';
|
|
9
|
+
|
|
10
|
+
export async function releaseLock(
|
|
11
|
+
filePath: string,
|
|
12
|
+
lockPath: string,
|
|
13
|
+
ownData: LockData,
|
|
14
|
+
options: ReleaseOptions = {},
|
|
15
|
+
): Promise<void> {
|
|
16
|
+
const adapter = getAdapter(DEFAULT_ADAPTER);
|
|
17
|
+
|
|
18
|
+
const exists = await fileExists(lockPath);
|
|
19
|
+
if (!exists) return;
|
|
20
|
+
|
|
21
|
+
if (!options.force) {
|
|
22
|
+
const raw = await readFileSafe(lockPath, filePath, lockPath).catch(() => null);
|
|
23
|
+
const current = raw ? safeDeserializeLockData(raw) : null;
|
|
24
|
+
if (current && current.nonce !== ownData.nonce) {
|
|
25
|
+
throw new LockError(
|
|
26
|
+
ERROR_CODES.LOCK_NOT_OWNED,
|
|
27
|
+
filePath,
|
|
28
|
+
lockPath,
|
|
29
|
+
`Cannot release lock owned by nonce ${current.nonce} (ours: ${ownData.nonce})`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
await adapter.release(lockPath);
|
|
35
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { LockError } from './LockError.js';
|
|
2
|
+
import { ERROR_CODES } from '../constants/errors.js';
|
|
3
|
+
|
|
4
|
+
export class AbortError extends LockError {
|
|
5
|
+
public override name = 'AbortError';
|
|
6
|
+
public readonly attempt: number;
|
|
7
|
+
|
|
8
|
+
constructor(path: string, lockPath: string, attempt: number) {
|
|
9
|
+
super(
|
|
10
|
+
ERROR_CODES.LOCK_ABORTED,
|
|
11
|
+
path,
|
|
12
|
+
lockPath,
|
|
13
|
+
`Lock acquisition on "${path}" was aborted after ${attempt} attempt(s)`,
|
|
14
|
+
);
|
|
15
|
+
this.attempt = attempt;
|
|
16
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override toJSON(): Record<string, unknown> {
|
|
20
|
+
return {
|
|
21
|
+
...super.toJSON(),
|
|
22
|
+
attempt: this.attempt,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|