diff --git a/.husky/pre-commit b/.husky/pre-commit index 660b8209689..2c1850f157c 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,4 +2,4 @@ . "$(dirname "$0")/_/husky.sh" npm run lint -npm run test +npm run test \ No newline at end of file diff --git a/index-fetch.js b/index-fetch.js index aaf70af701d..2937144bbf8 100644 --- a/index-fetch.js +++ b/index-fetch.js @@ -1,12 +1,10 @@ 'use strict' -const Agent = require('./lib/agent') - -const globalDispatcher = new Agent() - +const { getGlobalDispatcher } = require('./lib/global') const fetchImpl = require('./lib/fetch') + module.exports.fetch = async function fetch (resource) { - return fetchImpl.apply(globalDispatcher, arguments) + return fetchImpl.apply(getGlobalDispatcher(), arguments) } module.exports.FormData = require('./lib/fetch/formdata').FormData module.exports.Headers = require('./lib/fetch/headers').Headers diff --git a/index.js b/index.js index 888eb6a5a4f..a77e40eb9f0 100644 --- a/index.js +++ b/index.js @@ -15,6 +15,7 @@ const MockAgent = require('./lib/mock/mock-agent') const MockPool = require('./lib/mock/mock-pool') const mockErrors = require('./lib/mock/mock-errors') const ProxyAgent = require('./lib/proxy-agent') +const { getGlobalDispatcher, setGlobalDispatcher } = require('./lib/global') const nodeVersion = process.versions.node.split('.') const nodeMajor = Number(nodeVersion[0]) @@ -32,19 +33,6 @@ module.exports.ProxyAgent = ProxyAgent module.exports.buildConnector = buildConnector module.exports.errors = errors -let globalDispatcher = new Agent() - -function setGlobalDispatcher (agent) { - if (!agent || typeof agent.dispatch !== 'function') { - throw new InvalidArgumentError('Argument agent must implement Agent') - } - globalDispatcher = agent -} - -function getGlobalDispatcher () { - return globalDispatcher -} - function makeDispatcher (fn) { return (url, opts, handler) => { if (typeof opts === 'function') { diff --git a/lib/global.js b/lib/global.js new file mode 100644 index 00000000000..18bfd73cc92 --- /dev/null +++ b/lib/global.js @@ -0,0 +1,32 @@ +'use strict' + +// We include a version number for the Dispatcher API. In case of breaking changes, +// this version number must be increased to avoid conflicts. +const globalDispatcher = Symbol.for('undici.globalDispatcher.1') +const { InvalidArgumentError } = require('./core/errors') +const Agent = require('./agent') + +if (getGlobalDispatcher() === undefined) { + setGlobalDispatcher(new Agent()) +} + +function setGlobalDispatcher (agent) { + if (!agent || typeof agent.dispatch !== 'function') { + throw new InvalidArgumentError('Argument agent must implement Agent') + } + Object.defineProperty(globalThis, globalDispatcher, { + value: agent, + writable: true, + enumerable: false, + configurable: false + }) +} + +function getGlobalDispatcher () { + return globalThis[globalDispatcher] +} + +module.exports = { + setGlobalDispatcher, + getGlobalDispatcher +} diff --git a/package.json b/package.json index 74f9639350c..51e8f56d2dd 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "formdata-node": "^4.3.1", "https-pem": "^2.0.0", "husky": "^7.0.2", + "import-fresh": "^3.3.0", "jest": "^28.0.1", "jsfuzz": "^1.0.15", "mocha": "^10.0.0", diff --git a/test/agent.js b/test/agent.js index f341a16dea8..0d3c84d9d53 100644 --- a/test/agent.js +++ b/test/agent.js @@ -10,8 +10,10 @@ const { request, stream, pipeline, - setGlobalDispatcher + setGlobalDispatcher, + getGlobalDispatcher } = require('../') +const importFresh = require('import-fresh') test('setGlobalDispatcher', t => { t.plan(2) @@ -645,34 +647,6 @@ test('drain', t => { }) }) -// Port 80 is no accessible on CI. -// test('agent works with port 80', t => { -// t.plan(1) - -// const server = http.createServer((req, res) => { -// res.setHeader('Content-Type', 'text/plain') -// res.end() -// }) - -// t.teardown(server.close.bind(server)) - -// server.listen(80, async () => { -// const dispatcher = new Agent() - -// const origin = `http://localhost:${server.address().port}` - -// try { -// const { body } = await dispatcher.request({ origin, method: 'GET', path: '/' }) - -// body.on('end', () => { -// t.pass() -// }).resume() -// } catch (err) { -// t.error(err) -// } -// }) -// }) - test('global api', t => { t.plan(6 * 2) @@ -724,3 +698,10 @@ test('connect is not valid', t => { t.throws(() => new Agent({ connect: false }), errors.InvalidArgumentError, 'connect must be a function or an object') }) + +test('the dispatcher is truly global', t => { + const agent = getGlobalDispatcher() + const undiciFresh = importFresh('../index.js') + t.equal(agent, undiciFresh.getGlobalDispatcher()) + t.end() +})