Skip to content

Commit 595e1b5

Browse files
committed
refactor(dlx): extract generateCacheKey to shared dlx.ts module
- Move generateCacheKey from dlx-binary.ts to dlx.ts for reuse - Remove generatePackageCacheKey from dlx-package.ts - Update both dlx-binary and dlx-package to use shared function - Enables socket-cli to import and use generateCacheKey directly - All tests passing (4573 passed)
1 parent acfc634 commit 595e1b5

3 files changed

Lines changed: 33 additions & 39 deletions

File tree

src/dlx-binary.ts

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import path from 'node:path'
77

88
import { WIN32 } from '#constants/platform'
99

10+
import { generateCacheKey } from './dlx'
1011
import { downloadWithLock } from './download-lock'
1112
import { isDir, readJson, safeDelete } from './fs'
1213
import { isObjectObject } from './objects'
@@ -39,34 +40,6 @@ export interface DlxBinaryResult {
3940
spawnPromise: ReturnType<typeof spawn>
4041
}
4142

42-
/**
43-
* Generate a cache directory name using npm/npx approach.
44-
* Uses first 16 characters of SHA-512 hash (like npm/npx).
45-
*
46-
* Rationale for SHA-512 truncated (vs full SHA-256):
47-
* - Matches npm/npx ecosystem behavior
48-
* - Shorter paths for Windows MAX_PATH compatibility (260 chars)
49-
* - 16 hex chars = 64 bits = acceptable collision risk for local cache
50-
* - Collision probability ~1 in 18 quintillion with 1000 entries
51-
*
52-
* Input strategy (aligned with npx):
53-
* - npx uses package spec strings (e.g., '@scope/pkg@1.0.0', 'prettier@3.0.0')
54-
* - Caller provides complete spec string with version for accurate cache keying
55-
* - For package installs: Use PURL-style spec with version
56-
* Examples: 'npm:prettier@3.0.0', 'pypi:requests@2.31.0', 'gem:rails@7.0.0'
57-
* Note: Socket uses shorthand format without 'pkg:' prefix
58-
* (handled by @socketregistry/packageurl-js)
59-
* - For binary downloads: Use URL for uniqueness
60-
*
61-
* Reference: npm/cli v11.6.2 libnpmexec/lib/index.js#L233-L244
62-
* https://github.com/npm/cli/blob/v11.6.2/workspaces/libnpmexec/lib/index.js#L233-L244
63-
* Implementation: packages.map().sort().join('\n') → SHA-512 → slice(0,16)
64-
* npx hashes the package spec (name@version), not just name
65-
*/
66-
function generateCacheKey(spec: string): string {
67-
return createHash('sha512').update(spec).digest('hex').substring(0, 16)
68-
}
69-
7043
/**
7144
* Get metadata file path for a cached binary.
7245
*/

src/dlx-package.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@
3030
* - dlxPackage() combines both for convenience
3131
*/
3232

33-
import { createHash } from 'node:crypto'
3433
import { existsSync, promises as fs } from 'node:fs'
3534
import path from 'node:path'
3635

37-
import pacote from './external/pacote'
3836
import { WIN32 } from './constants/platform'
3937
import { getPacoteCachePath } from './constants/packages'
38+
import { generateCacheKey } from './dlx'
39+
import pacote from './external/pacote'
4040
import { readJsonSync } from './fs'
4141
import { normalizePath } from './path'
4242
import { getSocketDlxDir } from './paths'
@@ -85,14 +85,6 @@ export interface DlxPackageResult {
8585
spawnPromise: ReturnType<typeof spawn>
8686
}
8787

88-
/**
89-
* Generate a cache key from package spec, similar to npm's _npx.
90-
* Uses first 16 hex characters of SHA256 hash.
91-
*/
92-
function generatePackageCacheKey(packageSpec: string): string {
93-
return createHash('sha256').update(packageSpec).digest('hex').slice(0, 16)
94-
}
95-
9688
/**
9789
* Parse package spec into name and version.
9890
* Examples:
@@ -142,7 +134,7 @@ async function ensurePackageInstalled(
142134
packageName: string,
143135
force: boolean,
144136
): Promise<{ installed: boolean; packageDir: string }> {
145-
const cacheKey = generatePackageCacheKey(packageSpec)
137+
const cacheKey = generateCacheKey(packageSpec)
146138
const packageDir = normalizePath(path.join(getSocketDlxDir(), cacheKey))
147139
const installedDir = normalizePath(
148140
path.join(packageDir, 'node_modules', packageName),

src/dlx.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,41 @@
11
/** @fileoverview DLX (execute package) utilities for Socket ecosystem shared installations. */
22

3+
import { createHash } from 'node:crypto'
34
import { existsSync, promises as fs } from 'node:fs'
45

56
import { readDirNamesSync, safeDelete } from './fs'
67
import { normalizePath } from './path'
78
import { getSocketDlxDir } from './paths'
89
import { pEach } from './promises'
910

11+
/**
12+
* Generate a cache directory name using npm/npx approach.
13+
* Uses first 16 characters of SHA-512 hash (like npm/npx).
14+
*
15+
* Rationale for SHA-512 truncated (vs full SHA-256):
16+
* - Matches npm/npx ecosystem behavior
17+
* - Shorter paths for Windows MAX_PATH compatibility (260 chars)
18+
* - 16 hex chars = 64 bits = acceptable collision risk for local cache
19+
* - Collision probability ~1 in 18 quintillion with 1000 entries
20+
*
21+
* Input strategy (aligned with npx):
22+
* - npx uses package spec strings (e.g., '@scope/pkg@1.0.0', 'prettier@3.0.0')
23+
* - Caller provides complete spec string with version for accurate cache keying
24+
* - For package installs: Use PURL-style spec with version
25+
* Examples: 'npm:prettier@3.0.0', 'pypi:requests@2.31.0', 'gem:rails@7.0.0'
26+
* Note: Socket uses shorthand format without 'pkg:' prefix
27+
* (handled by @socketregistry/packageurl-js)
28+
* - For binary downloads: Use URL:name for uniqueness
29+
*
30+
* Reference: npm/cli v11.6.2 libnpmexec/lib/index.js#L233-L244
31+
* https://github.com/npm/cli/blob/v11.6.2/workspaces/libnpmexec/lib/index.js#L233-L244
32+
* Implementation: packages.map().sort().join('\n') → SHA-512 → slice(0,16)
33+
* npx hashes the package spec (name@version), not just name
34+
*/
35+
export function generateCacheKey(spec: string): string {
36+
return createHash('sha512').update(spec).digest('hex').substring(0, 16)
37+
}
38+
1039
let _path: typeof import('path') | undefined
1140
/**
1241
* Lazily load the path module to avoid Webpack errors.

0 commit comments

Comments
 (0)