@edxeth/fff-node 0.7.2-edxeth.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.
@@ -0,0 +1,423 @@
1
+ /**
2
+ * FileFinder - High-level API for the fff file finder
3
+ *
4
+ * This class provides a type-safe, ergonomic API for file finding operations.
5
+ * Each instance owns an independent native file picker that can be created
6
+ * and destroyed independently. Multiple instances can coexist.
7
+ *
8
+ * All methods return Result types for explicit error handling.
9
+ */
10
+ import { ensureLoaded, ffiCreate, ffiDestroy, ffiGetBasePath, ffiGetHistoricalQuery, ffiGetScanProgress, ffiHealthCheck, ffiIsScanning, ffiLiveGrep, ffiMultiGrep, ffiRefreshGitStatus, ffiRestartIndex, ffiScanFiles, ffiSearch, ffiSearchDirectories, ffiSearchMixed, ffiTrackQuery, isAvailable, } from "./ffi.js";
11
+ import { err } from "./types.js";
12
+ /**
13
+ * FileFinder - Fast file finder with fuzzy search
14
+ *
15
+ * Each instance is backed by an independent native file picker. Create as many
16
+ * as you need and destroy them when done.
17
+ *
18
+ * @example
19
+ *
20
+ * ```ts
21
+ * import { FileFinder } from "@ff-labs/fff-node";
22
+ *
23
+ * // Create an instance
24
+ * const finder = FileFinder.create({ basePath: "/path/to/project" });
25
+ * if (!finder.ok) {
26
+ * console.error(finder.error);
27
+ * process.exit(1);
28
+ * }
29
+ *
30
+ * // Wait for initial scan
31
+ * finder.value.waitForScan(5000);
32
+ *
33
+ * // Search for files
34
+ * const search = finder.value.search("main.ts");
35
+ * if (search.ok) {
36
+ * for (const item of search.value.items) {
37
+ * console.log(item.relativePath);
38
+ * }
39
+ * }
40
+ *
41
+ * // Cleanup
42
+ * finder.value.destroy();
43
+ * ```
44
+ */
45
+ export class FileFinder {
46
+ handle;
47
+ constructor(handle) {
48
+ this.handle = handle;
49
+ }
50
+ /**
51
+ * Create a new file finder instance.
52
+ *
53
+ * @param options - Initialization options
54
+ * @returns Result containing the new FileFinder instance or an error
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * // Basic initialization
59
+ * const finder = FileFinder.create({ basePath: "/path/to/project" });
60
+ *
61
+ * // With custom database paths
62
+ * const finder = FileFinder.create({
63
+ * basePath: "/path/to/project",
64
+ * frecencyDbPath: "/custom/frecency.mdb",
65
+ * historyDbPath: "/custom/history.mdb",
66
+ * });
67
+ * ```
68
+ */
69
+ static create(options) {
70
+ const result = ffiCreate(options.basePath, options.frecencyDbPath ?? "", options.historyDbPath ?? "", options.useUnsafeNoLock ?? false, !(options.disableMmapCache ?? false), !(options.disableContentIndexing ?? options.disableMmapCache ?? false), !(options.disableWatch ?? false), options.aiMode ?? false, options.logFilePath ?? "", options.logLevel ?? "", options.cacheBudgetMaxFiles ?? 0, options.cacheBudgetMaxBytes ?? 0, options.cacheBudgetMaxFileSize ?? 0);
71
+ if (!result.ok) {
72
+ return result;
73
+ }
74
+ return { ok: true, value: new FileFinder(result.value) };
75
+ }
76
+ /**
77
+ * Destroy and clean up all resources.
78
+ *
79
+ * Call this when you're done using the file finder to free memory
80
+ * and stop background file watching. After calling this, the instance
81
+ * must not be used again.
82
+ */
83
+ destroy() {
84
+ if (this.handle !== null) {
85
+ ffiDestroy(this.handle);
86
+ this.handle = null;
87
+ }
88
+ }
89
+ /**
90
+ * Check if this instance has been destroyed.
91
+ */
92
+ get isDestroyed() {
93
+ return this.handle === null;
94
+ }
95
+ /**
96
+ * Guard that returns an error if the instance has been destroyed.
97
+ */
98
+ ensureAlive() {
99
+ if (this.handle === null) {
100
+ return err("FileFinder instance has been destroyed.");
101
+ }
102
+ return { ok: true, value: this.handle };
103
+ }
104
+ /**
105
+ * Search for files matching the query.
106
+ *
107
+ * The query supports fuzzy matching and special syntax:
108
+ * - `foo bar` - Match files containing "foo" and "bar"
109
+ * - `src/` - Match files in src directory
110
+ * - `file.ts:42` - Match file.ts with line 42
111
+ * - `file.ts:42:10` - Match file.ts with line 42, column 10
112
+ *
113
+ * @param query - Search query string
114
+ * @param options - Search options
115
+ * @returns Search results with matched files and scores
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * const result = finder.search("main.ts", { pageSize: 10 });
120
+ * if (result.ok) {
121
+ * console.log(`Found ${result.value.totalMatched} files`);
122
+ * for (const item of result.value.items) {
123
+ * console.log(item.relativePath);
124
+ * }
125
+ * }
126
+ * ```
127
+ */
128
+ fileSearch(query, options) {
129
+ const guard = this.ensureAlive();
130
+ if (!guard.ok)
131
+ return guard;
132
+ return ffiSearch(guard.value, query, options?.currentFile ?? "", options?.maxThreads ?? 0, options?.pageIndex ?? 0, options?.pageSize ?? 0, options?.comboBoostMultiplier ?? 0, options?.minComboCount ?? 0);
133
+ }
134
+ /**
135
+ * Search for directories matching the query.
136
+ *
137
+ * @param query - Search query string
138
+ * @param options - Directory search options
139
+ * @returns Search results with matched directories and scores
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * const result = finder.directorySearch("src/comp", { pageSize: 10 });
144
+ * if (result.ok) {
145
+ * console.log(`Found ${result.value.totalMatched} directories`);
146
+ * for (const item of result.value.items) {
147
+ * console.log(item.relativePath);
148
+ * }
149
+ * }
150
+ * ```
151
+ */
152
+ directorySearch(query, options) {
153
+ const guard = this.ensureAlive();
154
+ if (!guard.ok)
155
+ return guard;
156
+ return ffiSearchDirectories(guard.value, query, options?.currentFile ?? null, options?.maxThreads ?? 0, options?.pageIndex ?? 0, options?.pageSize ?? 0);
157
+ }
158
+ /**
159
+ * Search for files and directories matching the query (mixed results).
160
+ *
161
+ * Results are interleaved by total score in descending order, mixing
162
+ * both file and directory items.
163
+ *
164
+ * @param query - Search query string
165
+ * @param options - Search options
166
+ * @returns Mixed search results with files and directories interleaved by score
167
+ *
168
+ * @example
169
+ * ```typescript
170
+ * const result = finder.mixedSearch("main", { pageSize: 20 });
171
+ * if (result.ok) {
172
+ * for (const entry of result.value.items) {
173
+ * if (entry.type === "file") {
174
+ * console.log(`File: ${entry.item.relativePath}`);
175
+ * } else {
176
+ * console.log(`Dir: ${entry.item.relativePath}`);
177
+ * }
178
+ * }
179
+ * }
180
+ * ```
181
+ */
182
+ mixedSearch(query, options) {
183
+ const guard = this.ensureAlive();
184
+ if (!guard.ok)
185
+ return guard;
186
+ return ffiSearchMixed(guard.value, query, options?.currentFile ?? "", options?.maxThreads ?? 0, options?.pageIndex ?? 0, options?.pageSize ?? 0, options?.comboBoostMultiplier ?? 0, options?.minComboCount ?? 0);
187
+ }
188
+ /**
189
+ * Search file contents (live grep).
190
+ *
191
+ * Searches through the contents of indexed files using the specified mode:
192
+ * - `"plain"` (default): SIMD-accelerated literal text matching
193
+ * - `"regex"`: Regular expression matching
194
+ * - `"fuzzy"`: Smith-Waterman fuzzy matching per line
195
+ *
196
+ * Supports pagination for large result sets. The result includes a `nextCursor`
197
+ * that can be passed back to fetch the next page.
198
+ *
199
+ * The query also supports constraint syntax:
200
+ * - `*.ts pattern` - Only search in TypeScript files
201
+ * - `src/ pattern` - Only search in the src directory
202
+ *
203
+ * @param query - Search query string
204
+ * @param options - Grep options (mode, pagination, limits)
205
+ * @returns Grep results with matched lines and file metadata
206
+ *
207
+ * @example
208
+ * ```typescript
209
+ * // First page
210
+ * const result = finder.grep("TODO", { mode: "plain" });
211
+ * if (result.ok) {
212
+ * for (const match of result.value.items) {
213
+ * console.log(`${match.relativePath}:${match.lineNumber}: ${match.lineContent}`);
214
+ * }
215
+ * // Fetch next page
216
+ * if (result.value.nextCursor) {
217
+ * const page2 = finder.grep("TODO", {
218
+ * cursor: result.value.nextCursor,
219
+ * });
220
+ * }
221
+ * }
222
+ * ```
223
+ */
224
+ grep(query, options) {
225
+ const guard = this.ensureAlive();
226
+ if (!guard.ok)
227
+ return guard;
228
+ return ffiLiveGrep(guard.value, query, options?.mode ?? "plain", options?.maxFileSize ?? 0, options?.maxMatchesPerFile ?? 0, options?.smartCase ?? true, options?.cursor?._offset ?? 0, 0, // page_limit (0 = default 50)
229
+ options?.timeBudgetMs ?? 0, options?.beforeContext ?? 0, options?.afterContext ?? 0, options?.classifyDefinitions ?? false);
230
+ }
231
+ /**
232
+ * Multi-pattern OR search using Aho-Corasick.
233
+ *
234
+ * Searches for lines matching ANY of the provided patterns using
235
+ * SIMD-accelerated multi-needle matching. Faster than regex alternation
236
+ * for literal text searches.
237
+ *
238
+ * Supports pagination. The result includes a `nextCursor` that can be
239
+ * passed back to fetch the next page.
240
+ *
241
+ * @param options - Multi-grep options including patterns and optional constraints
242
+ * @returns Grep results with matched lines and file metadata
243
+ *
244
+ * @example
245
+ * ```typescript
246
+ * const result = finder.multiGrep({
247
+ * patterns: ["VideoFrame", "video_frame", "PreloadedImage"],
248
+ * });
249
+ * if (result.ok) {
250
+ * for (const match of result.value.items) {
251
+ * console.log(`${match.relativePath}:${match.lineNumber}: ${match.lineContent}`);
252
+ * }
253
+ * }
254
+ * ```
255
+ */
256
+ multiGrep(options) {
257
+ const guard = this.ensureAlive();
258
+ if (!guard.ok)
259
+ return guard;
260
+ if (!options.patterns || options.patterns.length === 0) {
261
+ return err("patterns array must have at least 1 element");
262
+ }
263
+ return ffiMultiGrep(guard.value, options.patterns.join("\n"), options.constraints ?? "", options.maxFileSize ?? 0, options.maxMatchesPerFile ?? 0, options.smartCase ?? true, options.cursor?._offset ?? 0, 0, // page_limit (0 = default 50)
264
+ options.timeBudgetMs ?? 0, options.beforeContext ?? 0, options.afterContext ?? 0, options.classifyDefinitions ?? false);
265
+ }
266
+ /**
267
+ * Trigger a rescan of the indexed directory.
268
+ *
269
+ * This is useful after major file system changes that the
270
+ * background watcher might have missed.
271
+ */
272
+ scanFiles() {
273
+ const guard = this.ensureAlive();
274
+ if (!guard.ok)
275
+ return guard;
276
+ return ffiScanFiles(guard.value);
277
+ }
278
+ /**
279
+ * Check if a scan is currently in progress.
280
+ */
281
+ isScanning() {
282
+ if (this.handle === null)
283
+ return false;
284
+ return ffiIsScanning(this.handle);
285
+ }
286
+ /**
287
+ * Get the base path of the file picker (the root directory being indexed).
288
+ */
289
+ getBasePath() {
290
+ const guard = this.ensureAlive();
291
+ if (!guard.ok)
292
+ return guard;
293
+ return ffiGetBasePath(guard.value);
294
+ }
295
+ /**
296
+ * Get the current scan progress.
297
+ */
298
+ getScanProgress() {
299
+ const guard = this.ensureAlive();
300
+ if (!guard.ok)
301
+ return guard;
302
+ return ffiGetScanProgress(guard.value);
303
+ }
304
+ /**
305
+ * Wait for the initial file scan to complete.
306
+ *
307
+ * Non-blocking — polls `isScanning` and yields to the event loop between checks.
308
+ *
309
+ * @param timeoutMs - Maximum time to wait in milliseconds (default: 5000)
310
+ * @returns true if scan completed, false if timed out
311
+ *
312
+ * @example
313
+ * ```typescript
314
+ * const finder = FileFinder.create({ basePath: "/path/to/project" });
315
+ * if (finder.ok) {
316
+ * const completed = await finder.value.waitForScan(10000);
317
+ * if (!completed.ok || !completed.value) {
318
+ * console.warn("Scan did not complete in time");
319
+ * }
320
+ * }
321
+ * ```
322
+ */
323
+ async waitForScan(timeoutMs = 5000) {
324
+ const guard = this.ensureAlive();
325
+ if (!guard.ok)
326
+ return guard;
327
+ const deadline = Date.now() + timeoutMs;
328
+ while (this.isScanning()) {
329
+ if (Date.now() >= deadline) {
330
+ return { ok: true, value: false };
331
+ }
332
+ await new Promise((resolve) => setTimeout(resolve, 50));
333
+ }
334
+ return { ok: true, value: true };
335
+ }
336
+ /**
337
+ * Change the indexed directory to a new path.
338
+ *
339
+ * This stops the current file watcher and starts indexing the new directory.
340
+ *
341
+ * @param newPath - New directory path to index
342
+ */
343
+ reindex(newPath) {
344
+ const guard = this.ensureAlive();
345
+ if (!guard.ok)
346
+ return guard;
347
+ return ffiRestartIndex(guard.value, newPath);
348
+ }
349
+ /**
350
+ * Refresh the git status cache.
351
+ *
352
+ * @returns Number of files with updated git status
353
+ */
354
+ refreshGitStatus() {
355
+ const guard = this.ensureAlive();
356
+ if (!guard.ok)
357
+ return guard;
358
+ return ffiRefreshGitStatus(guard.value);
359
+ }
360
+ /**
361
+ * Track query completion for smart suggestions.
362
+ *
363
+ * Call this when a user selects a file from search results.
364
+ * This helps improve future search rankings for similar queries.
365
+ *
366
+ * @param query - The search query that was used
367
+ * @param selectedFilePath - The file path that was selected
368
+ */
369
+ trackQuery(query, selectedFilePath) {
370
+ const guard = this.ensureAlive();
371
+ if (!guard.ok)
372
+ return guard;
373
+ return ffiTrackQuery(guard.value, query, selectedFilePath);
374
+ }
375
+ /**
376
+ * Get a historical query by offset.
377
+ *
378
+ * @param offset - Offset from most recent (0 = most recent)
379
+ * @returns The historical query string, or null if not found
380
+ */
381
+ getHistoricalQuery(offset) {
382
+ const guard = this.ensureAlive();
383
+ if (!guard.ok)
384
+ return guard;
385
+ return ffiGetHistoricalQuery(guard.value, offset);
386
+ }
387
+ /**
388
+ * Get health check information.
389
+ *
390
+ * Useful for debugging and verifying the file finder is working correctly.
391
+ *
392
+ * @param testPath - Optional path to test git repository detection
393
+ */
394
+ healthCheck(testPath) {
395
+ return ffiHealthCheck(this.handle, testPath || "");
396
+ }
397
+ /**
398
+ * Check if the native library is available.
399
+ */
400
+ static isAvailable() {
401
+ return isAvailable();
402
+ }
403
+ /**
404
+ * Ensure the native library is loaded.
405
+ *
406
+ * Loads the native library from the platform-specific npm package
407
+ * or a local dev build. Throws if the binary is not found.
408
+ */
409
+ static ensureLoaded() {
410
+ ensureLoaded();
411
+ }
412
+ /**
413
+ * Get a health check without requiring an instance.
414
+ *
415
+ * Returns limited info (version + git only, no picker/frecency/query data).
416
+ *
417
+ * @param testPath - Optional path to test git repository detection
418
+ */
419
+ static healthCheckStatic(testPath) {
420
+ return ffiHealthCheck(null, testPath || "");
421
+ }
422
+ }
423
+ //# sourceMappingURL=finder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finder.js","sourceRoot":"","sources":["../../src/finder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * fff - Fast File Finder
3
+ *
4
+ * High-performance fuzzy file finder for Node.js, powered by Rust.
5
+ * Perfect for LLM agent tools that need to search through codebases.
6
+ *
7
+ * Each `FileFinder` instance is backed by an independent native file picker.
8
+ * Create as many as you need and destroy them when done.
9
+ *
10
+ * Uses ffi-rs to load the same native libfff_c binary used by @ff-labs/fff-bun.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { FileFinder } from "@ff-labs/fff-node";
15
+ *
16
+ * // Create a file finder instance
17
+ * const result = FileFinder.create({ basePath: "/path/to/project" });
18
+ * if (!result.ok) {
19
+ * console.error(result.error);
20
+ * process.exit(1);
21
+ * }
22
+ * const finder = result.value;
23
+ *
24
+ * // Wait for initial scan
25
+ * finder.waitForScan(5000);
26
+ *
27
+ * // Search for files
28
+ * const search = finder.fileSearch("main.ts");
29
+ * if (search.ok) {
30
+ * for (const item of search.value.items) {
31
+ * console.log(item.relativePath);
32
+ * }
33
+ * }
34
+ *
35
+ * // Cleanup when done
36
+ * finder.destroy();
37
+ * ```
38
+ *
39
+ * @packageDocumentation
40
+ */
41
+ export { binaryExists, findBinary, } from "./binary.js";
42
+ export { closeLibrary } from "./ffi.js";
43
+ export { FileFinder } from "./finder.js";
44
+ export { getLibExtension, getLibFilename, getNpmPackageName, getTriple, } from "./platform.js";
45
+ export type { DbHealth, DirItem, DirSearchOptions, DirSearchResult, FileItem, GrepCursor, GrepMatch, GrepMode, GrepOptions, GrepResult, HealthCheck, InitOptions, Location, MixedItem, MixedSearchResult, MultiGrepOptions, Result, ScanProgress, Score, SearchOptions, SearchResult, } from "./types.js";
46
+ export { err, ok } from "./types.js";
47
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EACL,YAAY,EACZ,UAAU,GACX,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,SAAS,GACV,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,QAAQ,EACR,OAAO,EACP,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACR,UAAU,EACV,SAAS,EACT,QAAQ,EACR,WAAW,EACX,UAAU,EACV,WAAW,EACX,WAAW,EACX,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,gBAAgB,EAChB,MAAM,EACN,YAAY,EACZ,KAAK,EACL,aAAa,EACb,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * fff - Fast File Finder
3
+ *
4
+ * High-performance fuzzy file finder for Node.js, powered by Rust.
5
+ * Perfect for LLM agent tools that need to search through codebases.
6
+ *
7
+ * Each `FileFinder` instance is backed by an independent native file picker.
8
+ * Create as many as you need and destroy them when done.
9
+ *
10
+ * Uses ffi-rs to load the same native libfff_c binary used by @ff-labs/fff-bun.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { FileFinder } from "@ff-labs/fff-node";
15
+ *
16
+ * // Create a file finder instance
17
+ * const result = FileFinder.create({ basePath: "/path/to/project" });
18
+ * if (!result.ok) {
19
+ * console.error(result.error);
20
+ * process.exit(1);
21
+ * }
22
+ * const finder = result.value;
23
+ *
24
+ * // Wait for initial scan
25
+ * finder.waitForScan(5000);
26
+ *
27
+ * // Search for files
28
+ * const search = finder.fileSearch("main.ts");
29
+ * if (search.ok) {
30
+ * for (const item of search.value.items) {
31
+ * console.log(item.relativePath);
32
+ * }
33
+ * }
34
+ *
35
+ * // Cleanup when done
36
+ * finder.destroy();
37
+ * ```
38
+ *
39
+ * @packageDocumentation
40
+ */
41
+ export { binaryExists, findBinary, } from "./binary.js";
42
+ export { closeLibrary } from "./ffi.js";
43
+ export { FileFinder } from "./finder.js";
44
+ export { getLibExtension, getLibFilename, getNpmPackageName, getTriple, } from "./platform.js";
45
+ // Result helpers
46
+ export { err, ok } from "./types.js";
47
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EACL,YAAY,EACZ,UAAU,GACX,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,SAAS,GACV,MAAM,eAAe,CAAC;AAyBvB,iBAAiB;AACjB,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Platform detection utilities for downloading the correct binary
3
+ */
4
+ /**
5
+ * Get the platform triple (e.g., "x86_64-unknown-linux-gnu")
6
+ */
7
+ export declare function getTriple(): string;
8
+ /**
9
+ * Get the library file extension for the current platform
10
+ */
11
+ export declare function getLibExtension(): "dylib" | "so" | "dll";
12
+ /**
13
+ * Get the library filename prefix (empty on Windows)
14
+ */
15
+ export declare function getLibPrefix(): string;
16
+ /**
17
+ * Get the full library filename for the current platform
18
+ */
19
+ export declare function getLibFilename(): string;
20
+ /**
21
+ * Get the npm package name for the current platform's native binary.
22
+ *
23
+ * @returns Package name like "@edxeth/fff-bin-darwin-arm64"
24
+ * @throws If the current platform is not supported
25
+ */
26
+ export declare function getNpmPackageName(): string;
27
+ //# sourceMappingURL=platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/platform.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAiBlC;AAqCD;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,GAAG,IAAI,GAAG,KAAK,CASxD;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAIvC;AAkBD;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAO1C"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Platform detection utilities for downloading the correct binary
3
+ */
4
+ import { execSync } from "node:child_process";
5
+ /**
6
+ * Get the platform triple (e.g., "x86_64-unknown-linux-gnu")
7
+ */
8
+ export function getTriple() {
9
+ const platform = process.platform;
10
+ const arch = process.arch;
11
+ let osName;
12
+ if (platform === "darwin") {
13
+ osName = "apple-darwin";
14
+ }
15
+ else if (platform === "linux") {
16
+ osName = detectLinuxLibc();
17
+ }
18
+ else if (platform === "win32") {
19
+ osName = "pc-windows-msvc";
20
+ }
21
+ else {
22
+ throw new Error(`Unsupported platform: ${platform}`);
23
+ }
24
+ const archName = normalizeArch(arch);
25
+ return `${archName}-${osName}`;
26
+ }
27
+ /**
28
+ * Detect whether we're on musl or glibc Linux
29
+ */
30
+ function detectLinuxLibc() {
31
+ try {
32
+ const lddOutput = execSync("ldd --version 2>&1", {
33
+ encoding: "utf-8",
34
+ timeout: 5000,
35
+ });
36
+ if (lddOutput.toLowerCase().includes("musl")) {
37
+ return "unknown-linux-musl";
38
+ }
39
+ }
40
+ catch {
41
+ // ldd failed, assume glibc
42
+ }
43
+ return "unknown-linux-gnu";
44
+ }
45
+ /**
46
+ * Normalize architecture name to Rust target format
47
+ */
48
+ function normalizeArch(arch) {
49
+ switch (arch) {
50
+ case "x64":
51
+ case "amd64":
52
+ return "x86_64";
53
+ case "arm64":
54
+ return "aarch64";
55
+ case "arm":
56
+ return "arm";
57
+ default:
58
+ throw new Error(`Unsupported architecture: ${arch}`);
59
+ }
60
+ }
61
+ /**
62
+ * Get the library file extension for the current platform
63
+ */
64
+ export function getLibExtension() {
65
+ switch (process.platform) {
66
+ case "darwin":
67
+ return "dylib";
68
+ case "win32":
69
+ return "dll";
70
+ default:
71
+ return "so";
72
+ }
73
+ }
74
+ /**
75
+ * Get the library filename prefix (empty on Windows)
76
+ */
77
+ export function getLibPrefix() {
78
+ return process.platform === "win32" ? "" : "lib";
79
+ }
80
+ /**
81
+ * Get the full library filename for the current platform
82
+ */
83
+ export function getLibFilename() {
84
+ const prefix = getLibPrefix();
85
+ const ext = getLibExtension();
86
+ return `${prefix}fff_c.${ext}`;
87
+ }
88
+ /**
89
+ * Map from Rust target triple to npm platform package name.
90
+ * The @ff-labs/fff-bin-* packages contain the pre-built libfff_c
91
+ * shared library and are runtime-agnostic (used by both Bun and Node).
92
+ */
93
+ const TRIPLE_TO_NPM_PACKAGE = {
94
+ "aarch64-apple-darwin": "@edxeth/fff-bin-darwin-arm64",
95
+ "x86_64-apple-darwin": "@edxeth/fff-bin-darwin-x64",
96
+ "x86_64-unknown-linux-gnu": "@edxeth/fff-bin-linux-x64-gnu",
97
+ "aarch64-unknown-linux-gnu": "@edxeth/fff-bin-linux-arm64-gnu",
98
+ "x86_64-unknown-linux-musl": "@edxeth/fff-bin-linux-x64-musl",
99
+ "aarch64-unknown-linux-musl": "@edxeth/fff-bin-linux-arm64-musl",
100
+ "x86_64-pc-windows-msvc": "@edxeth/fff-bin-win32-x64",
101
+ "aarch64-pc-windows-msvc": "@edxeth/fff-bin-win32-arm64",
102
+ };
103
+ /**
104
+ * Get the npm package name for the current platform's native binary.
105
+ *
106
+ * @returns Package name like "@edxeth/fff-bin-darwin-arm64"
107
+ * @throws If the current platform is not supported
108
+ */
109
+ export function getNpmPackageName() {
110
+ const triple = getTriple();
111
+ const packageName = TRIPLE_TO_NPM_PACKAGE[triple];
112
+ if (!packageName) {
113
+ throw new Error(`No npm package available for platform: ${triple}`);
114
+ }
115
+ return packageName;
116
+ }
117
+ //# sourceMappingURL=platform.js.map