Skip to content

Commit 1b81abe

Browse files
committed
fix: update dynamic requires to use path aliases
Fix module resolution in dynamic require statements to use consistent path alias pattern, resolving circular dependencies. Changes: - Update src/agent.ts: 7 require path fixes + SUPPORTS_NODE_RUN function call fix - Update src/path.ts: 2 require path fixes, remove redundant requires - Update src/paths.ts: add _getUserHomeDir helper for direct env access - Update src/dlx-binary.ts: 2 require path fixes - Update src/globs.ts: 3 require path fixes - Update src/packages/normalize.ts: lazy loader with path alias - Update src/packages/operations.ts: lazy loader with path alias - Update src/fs.ts: require path fix - Update src/github.ts: use env getters
1 parent 7b94d07 commit 1b81abe

9 files changed

Lines changed: 151 additions & 58 deletions

File tree

src/agent.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
* file resolution, because Node.js properly escapes each array element.
2424
*/
2525

26-
import { CI } from '#env/ci'
26+
import { getCI } from '#env/ci'
2727

2828
import { WIN32 } from '#constants/platform'
2929
import { execBin } from './bin'
@@ -109,7 +109,7 @@ export function execNpm(args: string[], options?: SpawnOptions | undefined) {
109109
//
110110
// We also use the npm binary wrapper instead of calling cli.js directly because
111111
// cli.js exports a function that needs to be invoked with process as an argument.
112-
const npmBin = /*@__PURE__*/ require('../constants/agents').NPM_BIN_PATH
112+
const npmBin = /*@__PURE__*/ require('#constants/agents').NPM_BIN_PATH
113113
return spawn(
114114
npmBin,
115115
[
@@ -179,7 +179,7 @@ export function execPnpm(args: string[], options?: PnpmOptions | undefined) {
179179
// we need to explicitly add --no-frozen-lockfile in CI mode if not already present.
180180
const frozenLockfileArgs = []
181181
if (
182-
CI &&
182+
getCI() &&
183183
allowLockfileUpdate &&
184184
firstArg &&
185185
isPnpmInstallCommand(firstArg) &&
@@ -374,15 +374,15 @@ export function execScript(
374374
}
375375

376376
const useNodeRun =
377-
!prepost && /*@__PURE__*/ require('../constants/node').SUPPORTS_NODE_RUN
377+
!prepost && /*@__PURE__*/ require('#constants/node').supportsNodeRun()
378378

379379
// Detect package manager based on lockfile by traversing up from current directory.
380380
const cwd =
381381
(getOwn(spawnOptions, 'cwd') as string | undefined) ?? process.cwd()
382382

383383
// Check for pnpm-lock.yaml.
384384
const pnpmLockPath = findUpSync(
385-
/*@__INLINE__*/ require('../constants/agents').PNPM_LOCK_YAML,
385+
/*@__INLINE__*/ require('#constants/agents').PNPM_LOCK_YAML,
386386
{ cwd },
387387
) as string | undefined
388388
if (pnpmLockPath) {
@@ -392,7 +392,7 @@ export function execScript(
392392
// Check for package-lock.json.
393393
// When in an npm workspace, use npm run to ensure workspace binaries are available.
394394
const packageLockPath = findUpSync(
395-
/*@__INLINE__*/ require('../constants/agents').PACKAGE_LOCK_JSON,
395+
/*@__INLINE__*/ require('#constants/agents').PACKAGE_LOCK_JSON,
396396
{ cwd },
397397
) as string | undefined
398398
if (packageLockPath) {
@@ -401,21 +401,21 @@ export function execScript(
401401

402402
// Check for yarn.lock.
403403
const yarnLockPath = findUpSync(
404-
/*@__INLINE__*/ require('../constants/agents').YARN_LOCK,
404+
/*@__INLINE__*/ require('#constants/agents').YARN_LOCK,
405405
{ cwd },
406406
) as string | undefined
407407
if (yarnLockPath) {
408408
return execYarn(['run', scriptName, ...resolvedArgs], spawnOptions)
409409
}
410410

411411
return spawn(
412-
/*@__PURE__*/ require('../constants/node').getExecPath(),
412+
/*@__PURE__*/ require('#constants/node').getExecPath(),
413413
[
414-
.../*@__PURE__*/ require('../constants/node').getNodeNoWarningsFlags(),
414+
.../*@__PURE__*/ require('#constants/node').getNodeNoWarningsFlags(),
415415
...(useNodeRun
416416
? ['--run']
417417
: [
418-
/*@__PURE__*/ require('../constants/agents').NPM_REAL_EXEC_PATH,
418+
/*@__PURE__*/ require('#constants/agents').NPM_REAL_EXEC_PATH,
419419
'run',
420420
]),
421421
scriptName,

src/dlx-binary.ts

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,13 @@ export interface DlxBinaryResult {
4040
}
4141

4242
/**
43-
* Generate a cache directory name from URL, similar to pnpm/npx.
43+
* Generate a cache directory name from URL and binary name.
4444
* Uses SHA256 hash to create content-addressed storage.
45+
* Includes binary name to prevent collisions when multiple binaries
46+
* are downloaded from the same URL with different names.
4547
*/
46-
function generateCacheKey(url: string): string {
47-
return createHash('sha256').update(url).digest('hex')
48+
function generateCacheKey(url: string, name: string): string {
49+
return createHash('sha256').update(`${url}:${name}`).digest('hex')
4850
}
4951

5052
/**
@@ -72,9 +74,12 @@ async function isCacheValid(
7274
return false
7375
}
7476
const now = Date.now()
75-
const age =
76-
now -
77-
(((metadata as Record<string, unknown>)['timestamp'] as number) || 0)
77+
const timestamp = (metadata as Record<string, unknown>)['timestamp']
78+
// If timestamp is missing or invalid, cache is invalid
79+
if (typeof timestamp !== 'number' || timestamp <= 0) {
80+
return false
81+
}
82+
const age = now - timestamp
7883

7984
return age < cacheTtl
8085
} catch {
@@ -166,7 +171,7 @@ async function writeMetadata(
166171
* Clean expired entries from the DLX cache.
167172
*/
168173
export async function cleanDlxCache(
169-
maxAge: number = /*@__INLINE__*/ require('../constants/time').DLX_BINARY_CACHE_TTL,
174+
maxAge: number = /*@__INLINE__*/ require('#constants/time').DLX_BINARY_CACHE_TTL,
170175
): Promise<number> {
171176
const cacheDir = getDlxCachePath()
172177

@@ -197,9 +202,12 @@ export async function cleanDlxCache(
197202
) {
198203
continue
199204
}
205+
const timestamp = (metadata as Record<string, unknown>)['timestamp']
206+
// If timestamp is missing or invalid, treat as expired (age = infinity)
200207
const age =
201-
now -
202-
(((metadata as Record<string, unknown>)['timestamp'] as number) || 0)
208+
typeof timestamp === 'number' && timestamp > 0
209+
? now - timestamp
210+
: Number.POSITIVE_INFINITY
203211

204212
if (age > maxAge) {
205213
// Remove entire cache entry directory.
@@ -234,7 +242,7 @@ export async function dlxBinary(
234242
spawnExtra?: SpawnExtra | undefined,
235243
): Promise<DlxBinaryResult> {
236244
const {
237-
cacheTtl = /*@__INLINE__*/ require('../constants/time').DLX_BINARY_CACHE_TTL,
245+
cacheTtl = /*@__INLINE__*/ require('#constants/time').DLX_BINARY_CACHE_TTL,
238246
checksum,
239247
force = false,
240248
name,
@@ -244,9 +252,9 @@ export async function dlxBinary(
244252

245253
// Generate cache paths similar to pnpm/npx structure.
246254
const cacheDir = getDlxCachePath()
247-
const cacheKey = generateCacheKey(url)
248-
const cacheEntryDir = path.join(cacheDir, cacheKey)
249255
const binaryName = name || `binary-${process.platform}-${os.arch()}`
256+
const cacheKey = generateCacheKey(url, binaryName)
257+
const cacheEntryDir = path.join(cacheDir, cacheKey)
250258
const binaryPath = normalizePath(path.join(cacheEntryDir, binaryName))
251259

252260
let downloaded = false

src/fs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,7 +1118,7 @@ export async function safeDelete(
11181118
const {
11191119
getSocketCacacheDir,
11201120
getSocketUserDir,
1121-
} = /*@__PURE__*/ require('./paths')
1121+
} = /*@__PURE__*/ require('#lib/paths')
11221122

11231123
// Get allowed directories
11241124
const tmpDir = os.tmpdir()
@@ -1209,7 +1209,7 @@ export function safeDeleteSync(
12091209
const {
12101210
getSocketCacacheDir,
12111211
getSocketUserDir,
1212-
} = /*@__PURE__*/ require('./paths')
1212+
} = /*@__PURE__*/ require('#lib/paths')
12131213

12141214
// Get allowed directories
12151215
const tmpDir = os.tmpdir()

src/github.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
import type { TtlCache } from './cache-with-ttl'
2525
import { createTtlCache } from './cache-with-ttl'
26+
import { getGhToken, getGithubToken } from '#env/github'
27+
import { getSocketCliGithubToken } from '#env/socket-cli'
2628
import { httpRequest } from './http-request'
2729
import type { SpawnOptions } from './spawn'
2830
import { spawn } from './spawn'
@@ -105,12 +107,8 @@ export interface GitHubRateLimitError extends Error {
105107
* ```
106108
*/
107109
export function getGitHubToken(): string | undefined {
108-
const { env } = process
109110
return (
110-
env['GITHUB_TOKEN'] ||
111-
env['GH_TOKEN'] ||
112-
env['SOCKET_CLI_GITHUB_TOKEN'] ||
113-
undefined
111+
getGithubToken() || getGhToken() || getSocketCliGithubToken() || undefined
114112
)
115113
}
116114

src/globs.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,16 +130,16 @@ export function globStreamLicenses(
130130
]
131131
if (ignoreOriginals) {
132132
ignore.push(
133-
/*@__INLINE__*/ require('../constants/paths')
133+
/*@__INLINE__*/ require('#constants/paths')
134134
.LICENSE_ORIGINAL_GLOB_RECURSIVE,
135135
)
136136
}
137137
const fastGlob = getFastGlob()
138138
return fastGlob.globStream(
139139
[
140140
recursive
141-
? /*@__INLINE__*/ require('../constants/paths').LICENSE_GLOB_RECURSIVE
142-
: /*@__INLINE__*/ require('../constants/paths').LICENSE_GLOB,
141+
? /*@__INLINE__*/ require('#constants/paths').LICENSE_GLOB_RECURSIVE
142+
: /*@__INLINE__*/ require('#constants/paths').LICENSE_GLOB,
143143
],
144144
{
145145
__proto__: null,

src/packages/normalize.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,26 @@ function getNormalizePackageData() {
5858
return _normalizePackageData as typeof import('normalize-package-data')
5959
}
6060

61+
let _findPackageExtensions:
62+
| ((name: string, version: string) => unknown)
63+
| undefined
64+
/**
65+
* Get the findPackageExtensions function from operations module.
66+
* Lazy loaded to avoid circular dependency.
67+
*/
68+
/*@__NO_SIDE_EFFECTS__*/
69+
function _getFindPackageExtensions() {
70+
if (_findPackageExtensions === undefined) {
71+
// Dynamically import to avoid circular dependency.
72+
// Use path alias for reliable resolution in both test and production environments.
73+
const operations: {
74+
findPackageExtensions: (name: string, version: string) => unknown
75+
} = require('#packages/operations')
76+
_findPackageExtensions = operations.findPackageExtensions
77+
}
78+
return _findPackageExtensions as (name: string, version: string) => unknown
79+
}
80+
6181
/**
6282
* Normalize a package.json object with standard npm package normalization.
6383
*/
@@ -86,10 +106,13 @@ export function normalizePackageJson(
86106
]
87107
const normalizePackageData = getNormalizePackageData()
88108
normalizePackageData(pkgJson)
89-
// Import findPackageExtensions from operations to avoid circular dependency.
90-
const { findPackageExtensions } = require('./operations')
109+
// Apply package extensions if name and version are present.
91110
if (pkgJson.name && pkgJson.version) {
92-
merge(pkgJson, findPackageExtensions(pkgJson.name, pkgJson.version))
111+
const findPackageExtensions = _getFindPackageExtensions()
112+
const extensions = findPackageExtensions(pkgJson.name, pkgJson.version)
113+
if (extensions && typeof extensions === 'object') {
114+
merge(pkgJson, extensions)
115+
}
93116
}
94117
// Revert/remove properties we don't care to have normalized.
95118
// Properties with undefined values are omitted when saved as JSON.

src/packages/operations.ts

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,46 @@ function getSemver() {
120120
return _semver as typeof import('semver')
121121
}
122122

123+
let _toEditablePackageJson:
124+
| ((pkgJson: PackageJson, options?: unknown) => Promise<PackageJson>)
125+
| undefined
126+
/**
127+
* Get the toEditablePackageJson function from editable module.
128+
* Lazy loaded to avoid circular dependency.
129+
*/
130+
/*@__NO_SIDE_EFFECTS__*/
131+
function _getToEditablePackageJson() {
132+
if (_toEditablePackageJson === undefined) {
133+
// Use path alias for reliable resolution in both test and production environments.
134+
_toEditablePackageJson =
135+
/*@__PURE__*/ require('#packages/editable').toEditablePackageJson
136+
}
137+
return _toEditablePackageJson as (
138+
pkgJson: PackageJson,
139+
options?: unknown,
140+
) => Promise<PackageJson>
141+
}
142+
143+
let _toEditablePackageJsonSync:
144+
| ((pkgJson: PackageJson, options?: unknown) => PackageJson)
145+
| undefined
146+
/**
147+
* Get the toEditablePackageJsonSync function from editable module.
148+
* Lazy loaded to avoid circular dependency.
149+
*/
150+
/*@__NO_SIDE_EFFECTS__*/
151+
function _getToEditablePackageJsonSync() {
152+
if (_toEditablePackageJsonSync === undefined) {
153+
// Use path alias for reliable resolution in both test and production environments.
154+
_toEditablePackageJsonSync =
155+
/*@__PURE__*/ require('#packages/editable').toEditablePackageJsonSync
156+
}
157+
return _toEditablePackageJsonSync as (
158+
pkgJson: PackageJson,
159+
options?: unknown,
160+
) => PackageJson
161+
}
162+
123163
/**
124164
* Extract a package to a destination directory.
125165
*/
@@ -256,8 +296,7 @@ export async function readPackageJson(
256296
})) as PackageJson | undefined
257297
if (pkgJson) {
258298
if (editable) {
259-
// Import toEditablePackageJson to avoid circular dependency.
260-
const { toEditablePackageJson } = require('./editable')
299+
const toEditablePackageJson = _getToEditablePackageJson()
261300
return await toEditablePackageJson(pkgJson, {
262301
path: filepath,
263302
normalize,
@@ -290,8 +329,7 @@ export function readPackageJsonSync(
290329
| undefined
291330
if (pkgJson) {
292331
if (editable) {
293-
// Import toEditablePackageJsonSync to avoid circular dependency.
294-
const { toEditablePackageJsonSync } = require('./editable')
332+
const toEditablePackageJsonSync = _getToEditablePackageJsonSync()
295333
return toEditablePackageJsonSync(pkgJson, {
296334
path: filepath,
297335
normalize,

src/path.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -389,8 +389,8 @@ export function isRelative(pathLike: string | Buffer | URL): boolean {
389389
* normalizePath('foo/bar/../baz') // 'foo/baz'
390390
*
391391
* // Windows paths
392-
* normalizePath('C:\\Users\\John\\file.txt') // 'C:/Users/John/file.txt'
393-
* normalizePath('foo\\bar\\baz') // 'foo/bar/baz'
392+
* normalizePath('C:\\Users\\username\\file.txt') // 'C:/Users/username/file.txt'
393+
* normalizePath('foo\\bar\\baz') // 'foo/bar/baz'
394394
*
395395
* // UNC paths
396396
* normalizePath('\\\\server\\share\\file') // '//server/share/file'
@@ -706,7 +706,6 @@ export function pathLikeToString(
706706
// On Windows, strip the leading slash only for malformed URLs that lack drive letters
707707
// (e.g., `/path` should be `path`, but `/C:/path` should be `C:/path`).
708708
// On Unix, keep the leading slash for absolute paths (e.g., `/home/user`).
709-
const WIN32 = require('../constants/platform').WIN32
710709
if (WIN32 && decodedPathname.startsWith('/')) {
711710
// Check for drive letter pattern following Node.js source: /[a-zA-Z]:/
712711
// Character at index 1 should be a letter, character at index 2 should be ':'
@@ -951,8 +950,6 @@ function relative(from: string, to: string): string {
951950
return ''
952951
}
953952

954-
const WIN32 = require('../constants/platform').WIN32
955-
956953
// Windows: perform case-insensitive comparison.
957954
// NTFS and FAT32 preserve case but are case-insensitive for lookups.
958955
// This means 'C:\Foo\bar.txt' and 'c:\foo\BAR.TXT' refer to the same file.

0 commit comments

Comments
 (0)