@outfitter/file-ops 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,348 +1,8 @@
1
- import { ConflictError, InternalError, NotFoundError, Result, ValidationError } from "@outfitter/contracts";
2
- /**
3
- * Options for workspace root detection.
4
- *
5
- * Configure which marker files trigger workspace detection and where to stop searching.
6
- */
7
- interface FindWorkspaceRootOptions {
8
- /**
9
- * Marker files/directories to search for.
10
- * Search stops when any marker is found at a directory level.
11
- * @defaultValue [".git", "package.json"]
12
- */
13
- markers?: string[];
14
- /**
15
- * Stop searching at this directory boundary.
16
- * The search will not continue above this path.
17
- * @defaultValue filesystem root
18
- */
19
- stopAt?: string;
20
- }
21
- /**
22
- * Options for glob operations.
23
- *
24
- * Configure base directory, exclusion patterns, and file matching behavior.
25
- */
26
- interface GlobOptions {
27
- /**
28
- * Base directory for glob matching.
29
- * All returned paths will be absolute paths within this directory.
30
- * @defaultValue process.cwd()
31
- */
32
- cwd?: string;
33
- /**
34
- * Include files and directories starting with a dot in results.
35
- * @defaultValue false
36
- */
37
- dot?: boolean;
38
- /**
39
- * Follow symbolic links when scanning directories.
40
- * @defaultValue false
41
- */
42
- followSymlinks?: boolean;
43
- /**
44
- * Patterns to exclude from results.
45
- * Supports negation with "!" prefix to re-include previously excluded files.
46
- */
47
- ignore?: string[];
48
- }
49
- /**
50
- * Options for atomic write operations.
51
- *
52
- * Configure directory creation, permission handling, and file modes.
53
- */
54
- interface AtomicWriteOptions {
55
- /**
56
- * Create parent directories if they do not exist.
57
- * Uses recursive mkdir when enabled.
58
- * @defaultValue true
59
- */
60
- createParentDirs?: boolean;
61
- /**
62
- * Unix file mode for newly created files.
63
- * @defaultValue 0o644
64
- */
65
- mode?: number;
66
- /**
67
- * Preserve file permissions from existing file.
68
- * If the target file does not exist, falls back to the mode option.
69
- * @defaultValue false
70
- */
71
- preservePermissions?: boolean;
72
- }
73
- /**
74
- * Represents an acquired file lock.
75
- *
76
- * Contains metadata about the lock including the owning process ID and
77
- * acquisition timestamp. Used with acquireLock and releaseLock functions.
78
- */
79
- interface FileLock {
80
- /** Path to the .lock file that indicates the lock */
81
- lockPath: string;
82
- /** Absolute path to the locked file */
83
- path: string;
84
- /** Process ID of the lock holder */
85
- pid: number;
86
- /** Unix timestamp (milliseconds) when the lock was acquired */
87
- timestamp: number;
88
- }
89
- /**
90
- * Represents an acquired shared (reader) file lock.
91
- *
92
- * Extends FileLock with a lock type discriminator. Multiple processes can
93
- * hold shared locks simultaneously, but shared locks block exclusive locks.
94
- */
95
- interface SharedFileLock extends FileLock {
96
- /** Discriminator indicating this is a shared/reader lock */
97
- lockType: "shared";
98
- /** Unique identifier for this reader (allows multiple readers from same PID) */
99
- readerId: string;
100
- }
101
- /**
102
- * Options for lock acquisition.
103
- */
104
- interface LockOptions {
105
- /**
106
- * Interval in milliseconds between retry attempts when waiting.
107
- * @defaultValue 50
108
- */
109
- retryInterval?: number;
110
- /**
111
- * Maximum time in milliseconds to wait for lock acquisition.
112
- * If not specified, fails immediately if lock cannot be acquired.
113
- */
114
- timeout?: number;
115
- }
116
- /**
117
- * Finds the workspace root by searching upward for marker files/directories.
118
- *
119
- * Searches from startPath up to the filesystem root (or stopAt if specified),
120
- * returning the first directory containing any of the marker files.
121
- * Default markers are ".git" and "package.json".
122
- *
123
- * @param startPath - Path to start searching from (can be file or directory)
124
- * @param options - Search options including custom markers and stop boundary
125
- * @returns Result containing absolute workspace root path, or NotFoundError if no markers found
126
- */
127
- declare function findWorkspaceRoot(startPath: string, options?: FindWorkspaceRootOptions): Promise<Result<string, InstanceType<typeof NotFoundError>>>;
128
- /**
129
- * Gets the path relative to the workspace root.
130
- *
131
- * Finds the workspace root from the file's directory and returns the
132
- * path relative to that root. Uses forward slashes for cross-platform consistency.
133
- *
134
- * @param absolutePath - Absolute path to convert to workspace-relative
135
- * @returns Result containing relative path with forward slashes, or NotFoundError if no workspace found
136
- */
137
- declare function getRelativePath(absolutePath: string): Promise<Result<string, InstanceType<typeof NotFoundError>>>;
138
- /**
139
- * Checks if a path is inside a workspace directory.
140
- *
141
- * Resolves both paths to absolute form and checks if path is equal to
142
- * or a descendant of workspaceRoot. Does not follow symlinks.
143
- *
144
- * @param path - Path to check (can be relative or absolute)
145
- * @param workspaceRoot - Workspace root directory to check against
146
- * @returns True if path is inside or equal to workspace root, false otherwise
147
- */
148
- declare function isInsideWorkspace(path: string, workspaceRoot: string): boolean;
149
- /**
150
- * Validates and secures a user-provided path, preventing path traversal attacks.
151
- *
152
- * Security checks performed:
153
- * - Null bytes are rejected immediately
154
- * - Path traversal sequences (..) are rejected
155
- * - Absolute paths are rejected
156
- * - Final resolved path is verified to remain within basePath (defense in depth)
157
- *
158
- * Always use this function when handling user-provided paths instead of
159
- * directly using path.join with untrusted input.
160
- *
161
- * @param path - User-provided path to validate (must be relative)
162
- * @param basePath - Base directory to resolve against
163
- * @returns Result containing resolved absolute safe path, or ValidationError if path is unsafe
164
- */
165
- declare function securePath(path: string, basePath: string): Result<string, InstanceType<typeof ValidationError>>;
166
- /**
167
- * Checks if a path is safe (no traversal, valid characters).
168
- *
169
- * Convenience wrapper around securePath that returns a boolean.
170
- * Use this for quick validation; use securePath when you need the resolved path.
171
- *
172
- * @param path - Path to check (should be relative)
173
- * @param basePath - Base directory to resolve against
174
- * @returns True if path passes all security checks, false otherwise
175
- */
176
- declare function isPathSafe(path: string, basePath: string): boolean;
177
- /**
178
- * Safely resolves path segments into an absolute path.
179
- *
180
- * Validates each segment for security issues before joining. Use this
181
- * instead of path.join when any segment may come from user input.
182
- *
183
- * Security checks per segment:
184
- * - Null bytes are rejected
185
- * - Path traversal (..) is rejected
186
- * - Absolute path segments are rejected
187
- *
188
- * @param basePath - Base directory (must be absolute)
189
- * @param segments - Path segments to join (each validated individually)
190
- * @returns Result containing resolved absolute path, or ValidationError if any segment is unsafe
191
- */
192
- declare function resolveSafePath(basePath: string, ...segments: string[]): Result<string, InstanceType<typeof ValidationError>>;
193
- /**
194
- * Finds files matching a glob pattern.
195
- *
196
- * Uses Bun.Glob internally for fast pattern matching. Returns absolute paths.
197
- * Supports standard glob syntax including recursive matching, alternation, and character classes.
198
- *
199
- * Pattern syntax:
200
- * - Single asterisk matches any characters except path separator
201
- * - Double asterisk matches any characters including path separator (recursive)
202
- * - Curly braces for alternation
203
- * - Square brackets for character classes
204
- *
205
- * @param pattern - Glob pattern to match
206
- * @param options - Glob options including cwd, ignore patterns, and file type filters
207
- * @returns Result containing array of absolute file paths, or InternalError on failure
208
- */
209
- declare function glob(pattern: string, options?: GlobOptions): Promise<Result<string[], InstanceType<typeof InternalError>>>;
210
- /**
211
- * Synchronous version of glob.
212
- *
213
- * Use the async glob function when possible. This synchronous version
214
- * blocks the event loop and should only be used in initialization code
215
- * or synchronous contexts.
216
- *
217
- * @param pattern - Glob pattern to match
218
- * @param options - Glob options including cwd, ignore patterns, and file type filters
219
- * @returns Result containing array of absolute file paths, or InternalError on failure
220
- */
221
- declare function globSync(pattern: string, options?: GlobOptions): Result<string[], InstanceType<typeof InternalError>>;
222
- /**
223
- * Acquires an exclusive advisory lock on a file.
224
- *
225
- * Creates a .lock file next to the target file with lock metadata (PID, timestamp).
226
- * Uses atomic file creation (wx flag) to prevent race conditions.
227
- *
228
- * Exclusive locks block and are blocked by both shared and exclusive locks.
229
- * Use shared locks (acquireSharedLock) for read-only operations.
230
- *
231
- * Important: This is advisory locking. All processes must cooperate by using
232
- * these locking APIs. The filesystem does not enforce the lock.
233
- *
234
- * Prefer using withLock for automatic lock release.
235
- *
236
- * @param path - Absolute path to the file to lock
237
- * @param options - Lock options including timeout and retry interval
238
- * @returns Result containing FileLock on success, or ConflictError if already locked
239
- */
240
- declare function acquireLock(path: string, options?: LockOptions): Promise<Result<FileLock, InstanceType<typeof ConflictError>>>;
241
- /**
242
- * Releases a file lock by removing the .lock file.
243
- *
244
- * Should only be called with a lock obtained from acquireLock.
245
- * Prefer using withLock for automatic lock management.
246
- *
247
- * @param lock - Lock object returned from acquireLock
248
- * @returns Result indicating success, or InternalError if lock file cannot be removed
249
- */
250
- declare function releaseLock(lock: FileLock): Promise<Result<void, InstanceType<typeof InternalError>>>;
251
- /**
252
- * Executes a callback while holding an exclusive lock on a file.
253
- *
254
- * Lock is automatically released after callback completes, whether it
255
- * succeeds or throws an error. This is the recommended way to use file locking.
256
- *
257
- * Uses advisory file locking via .lock files. The lock is NOT enforced
258
- * by the filesystem - all processes must cooperate by using this API.
259
- *
260
- * @typeParam T - Return type of the callback
261
- * @param path - Absolute path to the file to lock
262
- * @param callback - Async callback to execute while holding lock
263
- * @returns Result containing callback return value, ConflictError if locked, or InternalError on failure
264
- */
265
- declare function withLock<T>(path: string, callback: () => Promise<T>): Promise<Result<T, InstanceType<typeof ConflictError> | InstanceType<typeof InternalError>>>;
266
- /**
267
- * Checks if a file is currently locked.
268
- *
269
- * Checks for the existence of a .lock file. Does not verify if the
270
- * process holding the lock is still running (no stale lock detection).
271
- *
272
- * @param path - Absolute path to check
273
- * @returns True if a lock file exists, false otherwise
274
- */
275
- declare function isLocked(path: string): Promise<boolean>;
276
- /**
277
- * Writes content to a file atomically using temp-file-then-rename strategy.
278
- *
279
- * How it works:
280
- * 1. Creates a unique temp file in the same directory
281
- * 2. Writes content to temp file
282
- * 3. Renames temp file to target (atomic on most filesystems)
283
- * 4. Cleans up temp file on failure
284
- *
285
- * This prevents partial writes and file corruption. The file either
286
- * contains the old content or the new content, never a partial state.
287
- *
288
- * @param path - Absolute path to target file
289
- * @param content - String content to write
290
- * @param options - Write options including directory creation and permission handling
291
- * @returns Result indicating success, or InternalError on failure
292
- */
293
- declare function atomicWrite(path: string, content: string, options?: AtomicWriteOptions): Promise<Result<void, InstanceType<typeof InternalError>>>;
294
- /**
295
- * Writes JSON data to a file atomically.
296
- *
297
- * Serializes data to JSON and writes using atomicWrite.
298
- * Returns ValidationError if serialization fails.
299
- *
300
- * @typeParam T - Type of data to serialize
301
- * @param path - Absolute path to target file
302
- * @param data - Data to serialize and write (must be JSON-serializable)
303
- * @param options - Write options including directory creation and permission handling
304
- * @returns Result indicating success, ValidationError if serialization fails, or InternalError on write failure
305
- */
306
- declare function atomicWriteJson<T>(path: string, data: T, options?: AtomicWriteOptions): Promise<Result<void, InstanceType<typeof InternalError> | InstanceType<typeof ValidationError>>>;
307
- /**
308
- * Acquires a shared (reader) lock on a file.
309
- *
310
- * Multiple readers can hold shared locks simultaneously. Shared locks are
311
- * blocked by exclusive locks. Uses the same .lock file as exclusive locks
312
- * with a JSON format that distinguishes lock types.
313
- *
314
- * Important: This is advisory locking. All processes must cooperate by using
315
- * these locking APIs. The filesystem does not enforce the lock.
316
- *
317
- * @param path - Absolute path to the file to lock
318
- * @param options - Lock options including timeout and retry interval
319
- * @returns Result containing SharedFileLock on success, or ConflictError if blocked by exclusive lock
320
- */
321
- declare function acquireSharedLock(path: string, options?: LockOptions): Promise<Result<SharedFileLock, InstanceType<typeof ConflictError>>>;
322
- /**
323
- * Releases a shared (reader) lock.
324
- *
325
- * Removes this process from the list of readers in the lock file.
326
- * If this is the last reader, the lock file is deleted.
327
- *
328
- * @param lock - Shared lock object returned from acquireSharedLock
329
- * @returns Result indicating success, or InternalError if lock file cannot be modified
330
- */
331
- declare function releaseSharedLock(lock: SharedFileLock): Promise<Result<void, InstanceType<typeof InternalError>>>;
332
- /**
333
- * Executes a callback while holding a shared (reader) lock on a file.
334
- *
335
- * Lock is automatically released after callback completes, whether it
336
- * succeeds or throws an error. This is the recommended way to use shared locks.
337
- *
338
- * Multiple readers can hold shared locks simultaneously. Use this for
339
- * read-only operations that should not block other readers.
340
- *
341
- * @typeParam T - Return type of the callback
342
- * @param path - Absolute path to the file to lock
343
- * @param callback - Async callback to execute while holding lock
344
- * @param options - Lock options including timeout and retry interval
345
- * @returns Result containing callback return value, ConflictError if blocked, or InternalError on failure
346
- */
347
- declare function withSharedLock<T>(path: string, callback: () => Promise<T>, options?: LockOptions): Promise<Result<T, InstanceType<typeof ConflictError> | InstanceType<typeof InternalError>>>;
1
+ import { glob, globSync } from "./shared/@outfitter/file-ops-3kzghhjm.js";
2
+ import { findWorkspaceRoot, getRelativePath, isInsideWorkspace } from "./shared/@outfitter/file-ops-b3v6xcnw.js";
3
+ import { acquireSharedLock, releaseSharedLock, withSharedLock } from "./shared/@outfitter/file-ops-cpvpwwsr.js";
4
+ import { isPathSafe, resolveSafePath, securePath } from "./shared/@outfitter/file-ops-ss4da105.js";
5
+ import { acquireLock, isLocked, releaseLock, withLock } from "./shared/@outfitter/file-ops-9xg8rjay.js";
6
+ import { atomicWrite, atomicWriteJson } from "./shared/@outfitter/file-ops-cp4q6s4n.js";
7
+ import { AtomicWriteOptions, FileLock, FindWorkspaceRootOptions, GlobOptions, LockOptions, SharedFileLock } from "./shared/@outfitter/file-ops-f0bv7qk0.js";
348
8
  export { withSharedLock, withLock, securePath, resolveSafePath, releaseSharedLock, releaseLock, isPathSafe, isLocked, isInsideWorkspace, globSync, glob, getRelativePath, findWorkspaceRoot, atomicWriteJson, atomicWrite, acquireSharedLock, acquireLock, SharedFileLock, LockOptions, GlobOptions, FindWorkspaceRootOptions, FileLock, AtomicWriteOptions };