Skip to content

Commit 9203a71

Browse files
committed
refactor(dlx): split main.ts into focused modules
Split dlx/main.ts into smaller, focused modules for better organization and maintainability. Changes: - Create dlx/cache.ts for cache key generation (generateCacheKey) - Create dlx/paths.ts for path utilities (getDlxPackageDir, getDlxInstalledPackageDir, getDlxPackageJsonPath, getDlxPackageNodeModulesDir, isInSocketDlx) - Create dlx/dir.ts for directory management (clearDlx, clearDlxSync, dlxDirExists, dlxDirExistsAsync, ensureDlxDir, ensureDlxDirSync) - Create dlx/packages.ts for package management (isDlxPackageInstalled, isDlxPackageInstalledAsync, listDlxPackages, listDlxPackagesAsync, removeDlxPackage, removeDlxPackageSync) - Remove old dlx/main.ts file - Update imports in dlx/binary.ts and dlx/package.ts to use dlx/cache - Update package.json exports: - Remove ./dlx/main - Add ./dlx/cache, ./dlx/dir, ./dlx/packages, ./dlx/paths - Update test imports in test/unit/dlx/main.test.ts to use split modules - All tests passing (182 tests, 179 passed, 3 skipped)
1 parent 3b4b8c6 commit 9203a71

File tree

9 files changed

+352
-303
lines changed

9 files changed

+352
-303
lines changed

package.json

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,13 @@
223223
"types": "./dist/dlx/binary.d.ts",
224224
"default": "./dist/dlx/binary.js"
225225
},
226-
"./dlx/main": {
227-
"types": "./dist/dlx/main.d.ts",
228-
"default": "./dist/dlx/main.js"
226+
"./dlx/cache": {
227+
"types": "./dist/dlx/cache.d.ts",
228+
"default": "./dist/dlx/cache.js"
229+
},
230+
"./dlx/dir": {
231+
"types": "./dist/dlx/dir.d.ts",
232+
"default": "./dist/dlx/dir.js"
229233
},
230234
"./dlx/manifest": {
231235
"types": "./dist/dlx/manifest.d.ts",
@@ -235,6 +239,14 @@
235239
"types": "./dist/dlx/package.d.ts",
236240
"default": "./dist/dlx/package.js"
237241
},
242+
"./dlx/packages": {
243+
"types": "./dist/dlx/packages.d.ts",
244+
"default": "./dist/dlx/packages.js"
245+
},
246+
"./dlx/paths": {
247+
"types": "./dist/dlx/paths.d.ts",
248+
"default": "./dist/dlx/paths.js"
249+
},
238250
"./effects/pulse-frames": {
239251
"types": "./dist/effects/pulse-frames.d.ts",
240252
"default": "./dist/effects/pulse-frames.js"

src/dlx/binary.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import path from 'path'
99
import { WIN32 } from '../constants/platform'
1010
import { DLX_BINARY_CACHE_TTL } from '../constants/time'
1111

12-
import { generateCacheKey } from './main'
12+
import { generateCacheKey } from './cache'
1313
import { dlxManifest } from './manifest'
1414
import { httpDownload } from '../http-request'
1515
import { isDir, readJson, safeDelete, safeMkdir } from '../fs'

src/dlx/cache.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/** @fileoverview Cache key generation utilities for DLX package installations. */
2+
3+
import { createHash } from 'node:crypto'
4+
5+
/**
6+
* Generate a cache directory name using npm/npx approach.
7+
* Uses first 16 characters of SHA-512 hash (like npm/npx).
8+
*
9+
* Rationale for SHA-512 truncated (vs full SHA-256):
10+
* - Matches npm/npx ecosystem behavior
11+
* - Shorter paths for Windows MAX_PATH compatibility (260 chars)
12+
* - 16 hex chars = 64 bits = acceptable collision risk for local cache
13+
* - Collision probability ~1 in 18 quintillion with 1000 entries
14+
*
15+
* Input strategy (aligned with npx):
16+
* - npx uses package spec strings (e.g., '@scope/pkg@1.0.0', 'prettier@3.0.0')
17+
* - Caller provides complete spec string with version for accurate cache keying
18+
* - For package installs: Use PURL-style spec with version
19+
* Examples: 'npm:prettier@3.0.0', 'pypi:requests@2.31.0', 'gem:rails@7.0.0'
20+
* Note: Socket uses shorthand format without 'pkg:' prefix
21+
* (handled by @socketregistry/packageurl-js)
22+
* - For binary downloads: Use URL:name for uniqueness
23+
*
24+
* Reference: npm/cli v11.6.2 libnpmexec/lib/index.js#L233-L244
25+
* https://github.com/npm/cli/blob/v11.6.2/workspaces/libnpmexec/lib/index.js#L233-L244
26+
* Implementation: packages.map().sort().join('\n') → SHA-512 → slice(0,16)
27+
* npx hashes the package spec (name@version), not just name
28+
*/
29+
export function generateCacheKey(spec: string): string {
30+
return createHash('sha512').update(spec).digest('hex').substring(0, 16)
31+
}

src/dlx/dir.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/** @fileoverview Directory management utilities for DLX installations. */
2+
3+
import { safeMkdir, safeMkdirSync } from '../fs'
4+
import { getSocketDlxDir } from '../paths/socket'
5+
import { pEach } from '../promises'
6+
import {
7+
listDlxPackages,
8+
listDlxPackagesAsync,
9+
removeDlxPackage,
10+
removeDlxPackageSync,
11+
} from './packages'
12+
13+
let _fs: typeof import('fs') | undefined
14+
/**
15+
* Lazily load the fs module to avoid Webpack errors.
16+
* Uses non-'node:' prefixed require to prevent Webpack bundling issues.
17+
*
18+
* @returns The Node.js fs module
19+
* @private
20+
*/
21+
/*@__NO_SIDE_EFFECTS__*/
22+
function getFs() {
23+
if (_fs === undefined) {
24+
// Use non-'node:' prefixed require to avoid Webpack errors.
25+
26+
_fs = /*@__PURE__*/ require('node:fs')
27+
}
28+
return _fs as typeof import('fs')
29+
}
30+
31+
/**
32+
* Clear all DLX package installations.
33+
*/
34+
export async function clearDlx(): Promise<void> {
35+
const packages = await listDlxPackagesAsync()
36+
await pEach(packages, pkg => removeDlxPackage(pkg))
37+
}
38+
39+
/**
40+
* Clear all DLX package installations synchronously.
41+
*/
42+
export function clearDlxSync(): void {
43+
const packages = listDlxPackages()
44+
for (const pkg of packages) {
45+
removeDlxPackageSync(pkg)
46+
}
47+
}
48+
49+
/**
50+
* Check if the DLX directory exists.
51+
*/
52+
export function dlxDirExists(): boolean {
53+
const fs = getFs()
54+
return fs.existsSync(getSocketDlxDir())
55+
}
56+
57+
/**
58+
* Check if the DLX directory exists asynchronously.
59+
*/
60+
export async function dlxDirExistsAsync(): Promise<boolean> {
61+
const fs = getFs()
62+
try {
63+
await fs.promises.access(getSocketDlxDir())
64+
return true
65+
} catch {
66+
return false
67+
}
68+
}
69+
70+
/**
71+
* Ensure the DLX directory exists, creating it if necessary.
72+
*/
73+
export async function ensureDlxDir(): Promise<void> {
74+
await safeMkdir(getSocketDlxDir())
75+
}
76+
77+
/**
78+
* Ensure the DLX directory exists synchronously, creating it if necessary.
79+
*/
80+
export function ensureDlxDirSync(): void {
81+
safeMkdirSync(getSocketDlxDir())
82+
}

0 commit comments

Comments
 (0)