import-in-the-middle 2.0.6 → 3.0.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.0.1](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v3.0.0...import-in-the-middle-v3.0.1) (2026-04-07)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * handle file specifiers from turbopacked packages better ([#246](https://github.com/nodejs/import-in-the-middle/issues/246)) ([04539fb](https://github.com/nodejs/import-in-the-middle/commit/04539fb5ceb9e4816933bd4310c1334077af1643))
9
+
10
+ ## [3.0.0](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v2.0.6...import-in-the-middle-v3.0.0) (2026-01-30)
11
+
12
+
13
+ ### ⚠ BREAKING CHANGES
14
+
15
+ * drop support for Node.js < v18 ([#230](https://github.com/nodejs/import-in-the-middle/issues/230))
16
+
17
+ ### Miscellaneous Chores
18
+
19
+ * drop support for Node.js &lt; v18 ([#230](https://github.com/nodejs/import-in-the-middle/issues/230)) ([f463b13](https://github.com/nodejs/import-in-the-middle/commit/f463b1342ca946608432c9be39fecb86e7f7cbf0))
20
+
3
21
  ## [2.0.6](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v2.0.5...import-in-the-middle-v2.0.6) (2026-01-27)
4
22
 
5
23
 
package/create-hook.mjs CHANGED
@@ -29,8 +29,6 @@ if (NODE_MAJOR > 16 || (NODE_MAJOR === 16 && NODE_MINOR >= 16)) {
29
29
  getExports = (url) => import(url).then(Object.keys)
30
30
  }
31
31
 
32
- let entrypoint
33
-
34
32
  function hasIitm (url) {
35
33
  // Fast path: avoid URL parsing on the hot path when there's clearly no iitm.
36
34
  if (typeof url !== 'string' || url.indexOf('iitm') === -1) {
@@ -73,28 +71,6 @@ function deleteIitm (url) {
73
71
  return resultUrl
74
72
  }
75
73
 
76
- function isNodeMajor16AndMinor17OrGreater () {
77
- return NODE_MAJOR === 16 && NODE_MINOR >= 17
78
- }
79
-
80
- function isFileProtocol (urlObj) {
81
- return urlObj.protocol === 'file:'
82
- }
83
-
84
- function isNodeProtocol (urlObj) {
85
- return urlObj.protocol === 'node:'
86
- }
87
-
88
- function needsToAddFileProtocol (urlObj) {
89
- if (NODE_MAJOR === 17) {
90
- return !isFileProtocol(urlObj)
91
- }
92
- if (isNodeMajor16AndMinor17OrGreater()) {
93
- return !isFileProtocol(urlObj) && !isNodeProtocol(urlObj)
94
- }
95
- return !isFileProtocol(urlObj) && NODE_MAJOR < 18
96
- }
97
-
98
74
  /**
99
75
  * Determines if a specifier represents an export all ESM line.
100
76
  * Note that the expected `line` isn't 100% valid ESM. It is derived
@@ -287,7 +263,7 @@ async function processModule ({ srcUrl, context, parentGetSource, parentResolve,
287
263
  } else {
288
264
  const variableName = `$${n.replace(/[^a-zA-Z0-9_$]/g, '_')}`
289
265
  const objectKey = JSON.stringify(n)
290
- const reExportedName = n === 'default' || NODE_MAJOR < 16 ? n : objectKey
266
+ const reExportedName = n === 'default' ? n : objectKey
291
267
 
292
268
  addSetter(n, `
293
269
  let ${variableName}
@@ -324,7 +300,7 @@ async function processModule ({ srcUrl, context, parentGetSource, parentResolve,
324
300
  function addIitm (url) {
325
301
  const urlObj = new URL(url)
326
302
  urlObj.searchParams.set('iitm', 'true')
327
- return needsToAddFileProtocol(urlObj) ? 'file:' + urlObj.href : urlObj.href
303
+ return urlObj.href
328
304
  }
329
305
 
330
306
  export function createHook (meta) {
@@ -386,13 +362,9 @@ export function createHook (meta) {
386
362
  // are evaluated, and can make them exit without doing anything.
387
363
  if (parentURL === '') {
388
364
  if (!EXTENSION_RE.test(result.url) && !hasIitm(result.url)) {
389
- entrypoint = result.url
390
365
  return { url: result.url, format: 'commonjs' }
391
366
  }
392
- if (NODE_MAJOR > 16 || (NODE_MAJOR === 16 && NODE_MINOR >= 16)) {
393
- entrypoint = result.url
394
- return result
395
- }
367
+ return result
396
368
  }
397
369
 
398
370
  // For included/excluded modules, we check the specifier to match libraries
@@ -574,7 +546,6 @@ register(${JSON.stringify(realUrl)}, _, set, get, ${JSON.stringify(originalSpeci
574
546
  return parentGetSource(url, context)
575
547
  }
576
548
 
577
- // For Node.js 16.12.0 and higher.
578
549
  async function load (url, context, parentLoad) {
579
550
  if (hasIitm(url)) {
580
551
  const result = await getSource(url, context, parentLoad)
@@ -595,28 +566,5 @@ register(${JSON.stringify(realUrl)}, _, set, get, ${JSON.stringify(originalSpeci
595
566
  return parentLoad(url, context)
596
567
  }
597
568
 
598
- if (NODE_MAJOR >= 17 || (NODE_MAJOR === 16 && NODE_MINOR >= 12)) {
599
- return { initialize, load, resolve }
600
- } else {
601
- return {
602
- initialize,
603
- load,
604
- resolve,
605
- getSource,
606
- getFormat (url, context, parentGetFormat) {
607
- if (hasIitm(url)) {
608
- return {
609
- format: 'module'
610
- }
611
- }
612
- if (url === entrypoint) {
613
- return {
614
- format: 'commonjs'
615
- }
616
- }
617
-
618
- return parentGetFormat(url, context)
619
- }
620
- }
621
- }
569
+ return { initialize, load, resolve }
622
570
  }
package/hook.mjs CHANGED
@@ -4,6 +4,6 @@
4
4
 
5
5
  import { createHook } from './create-hook.mjs'
6
6
 
7
- const { initialize, load, resolve, getFormat, getSource } = createHook(import.meta)
7
+ const { initialize, load, resolve } = createHook(import.meta)
8
8
 
9
- export { initialize, load, resolve, getFormat, getSource }
9
+ export { initialize, load, resolve }
package/index.js CHANGED
@@ -18,6 +18,26 @@ const {
18
18
  toHook
19
19
  } = require('./lib/register')
20
20
 
21
+ /**
22
+ * Checks turbopack specifiers separately (for Next.js 16+).
23
+ *
24
+ * If turbopack is used, specifiers will have an additional hash appended to the end.
25
+ * Something like "ai" might become "ai-5e7181a616786b24". This only happens in Next.js 16+.
26
+ * Just checking if the baseDir ends with this new specifier won't match, as the baseDir still has the plain package.
27
+ *
28
+ * This logic isolates a new check for checking the actual name in the case turbopack is being used.
29
+ *
30
+ * @param specifier {string}
31
+ * @param baseDir {string}
32
+ */
33
+ function isTurbopackSpecifier (specifier, baseDir) {
34
+ const usingTurbopack = process.env.TURBOPACK ?? process.argv.includes('--turbo')
35
+ if (!usingTurbopack) return false
36
+
37
+ const specifierWithoutTurbopackHash = specifier.slice(0, specifier.lastIndexOf('-'))
38
+ return baseDir.endsWith(specifierWithoutTurbopackHash)
39
+ }
40
+
21
41
  function addHook (hook) {
22
42
  importHooks.push(hook)
23
43
  toHook.forEach(([name, namespace, specifier]) => hook(name, namespace, specifier))
@@ -167,7 +187,7 @@ function Hook (modules, options, hookFn) {
167
187
  if (!baseDir) {
168
188
  // built-in module (or unexpected non file:// name?)
169
189
  callHookFn(hookFn, namespace, name, baseDir)
170
- } else if (baseDir.endsWith(specifiers.get(loadUrl))) {
190
+ } else if (baseDir.endsWith(specifiers.get(loadUrl)) || isTurbopackSpecifier(specifiers.get(loadUrl), baseDir)) {
171
191
  // An import of the top-level module (e.g. `import 'ioredis'`).
172
192
  // Note: Slight behaviour difference from RITM. RITM uses
173
193
  // `require.resolve(name)` to see if filename is the module
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "import-in-the-middle",
3
- "version": "2.0.6",
3
+ "version": "3.0.1",
4
4
  "description": "Intercept imports in Node.js",
5
+ "engines": {
6
+ "node": ">=18"
7
+ },
5
8
  "main": "index.js",
6
9
  "scripts": {
7
10
  "test": "c8 --reporter lcov --check-coverage --lines 45 imhotap --files test/{hook,low-level,other,get-esm-exports,register}/*",
8
- "test:e2e": "node test/check-exports/test.mjs",
11
+ "test:e2e": "node test/check-exports/test.mjs && node test/integration-tests/turbopack-dev.mjs && node test/integration-tests/turbopack-build-start.mjs",
9
12
  "test:ts": "c8 --reporter lcov imhotap --files test/typescript/*.test.mts",
10
13
  "coverage": "c8 --reporter html imhotap --files test/{hook,low-level,other,get-esm-exports,register}/* && echo \"\nNow open coverage/index.html\n\"",
11
14
  "lint": "eslint .",