// src/Interceptor.ts import { Logger } from "@open-draft/logger"; import { Emitter } from "strict-event-emitter"; var INTERNAL_REQUEST_ID_HEADER_NAME = "x-interceptors-internal-request-id"; function getGlobalSymbol(symbol) { return ( // @ts-ignore https://github.com/Microsoft/TypeScript/issues/24587 globalThis[symbol] || void 0 ); } function setGlobalSymbol(symbol, value) { globalThis[symbol] = value; } function deleteGlobalSymbol(symbol) { delete globalThis[symbol]; } var InterceptorReadyState = /* @__PURE__ */ ((InterceptorReadyState2) => { InterceptorReadyState2["INACTIVE"] = "INACTIVE"; InterceptorReadyState2["APPLYING"] = "APPLYING"; InterceptorReadyState2["APPLIED"] = "APPLIED"; InterceptorReadyState2["DISPOSING"] = "DISPOSING"; InterceptorReadyState2["DISPOSED"] = "DISPOSED"; return InterceptorReadyState2; })(InterceptorReadyState || {}); var Interceptor = class { constructor(symbol) { this.symbol = symbol; this.readyState = "INACTIVE" /* INACTIVE */; this.emitter = new Emitter(); this.subscriptions = []; this.logger = new Logger(symbol.description); this.emitter.setMaxListeners(0); this.logger.info("constructing the interceptor..."); } /** * Determine if this interceptor can be applied * in the current environment. */ checkEnvironment() { return true; } /** * Apply this interceptor to the current process. * Returns an already running interceptor instance if it's present. */ apply() { const logger = this.logger.extend("apply"); logger.info("applying the interceptor..."); if (this.readyState === "APPLIED" /* APPLIED */) { logger.info("intercepted already applied!"); return; } const shouldApply = this.checkEnvironment(); if (!shouldApply) { logger.info("the interceptor cannot be applied in this environment!"); return; } this.readyState = "APPLYING" /* APPLYING */; const runningInstance = this.getInstance(); if (runningInstance) { logger.info("found a running instance, reusing..."); this.on = (event, listener) => { logger.info('proxying the "%s" listener', event); runningInstance.emitter.addListener(event, listener); this.subscriptions.push(() => { runningInstance.emitter.removeListener(event, listener); logger.info('removed proxied "%s" listener!', event); }); return this; }; this.readyState = "APPLIED" /* APPLIED */; return; } logger.info("no running instance found, setting up a new instance..."); this.setup(); this.setInstance(); this.readyState = "APPLIED" /* APPLIED */; } /** * Setup the module augments and stubs necessary for this interceptor. * This method is not run if there's a running interceptor instance * to prevent instantiating an interceptor multiple times. */ setup() { } /** * Listen to the interceptor's public events. */ on(event, listener) { const logger = this.logger.extend("on"); if (this.readyState === "DISPOSING" /* DISPOSING */ || this.readyState === "DISPOSED" /* DISPOSED */) { logger.info("cannot listen to events, already disposed!"); return this; } logger.info('adding "%s" event listener:', event, listener); this.emitter.on(event, listener); return this; } once(event, listener) { this.emitter.once(event, listener); return this; } off(event, listener) { this.emitter.off(event, listener); return this; } removeAllListeners(event) { this.emitter.removeAllListeners(event); return this; } /** * Disposes of any side-effects this interceptor has introduced. */ dispose() { const logger = this.logger.extend("dispose"); if (this.readyState === "DISPOSED" /* DISPOSED */) { logger.info("cannot dispose, already disposed!"); return; } logger.info("disposing the interceptor..."); this.readyState = "DISPOSING" /* DISPOSING */; if (!this.getInstance()) { logger.info("no interceptors running, skipping dispose..."); return; } this.clearInstance(); logger.info("global symbol deleted:", getGlobalSymbol(this.symbol)); if (this.subscriptions.length > 0) { logger.info("disposing of %d subscriptions...", this.subscriptions.length); for (const dispose of this.subscriptions) { dispose(); } this.subscriptions = []; logger.info("disposed of all subscriptions!", this.subscriptions.length); } this.emitter.removeAllListeners(); logger.info("destroyed the listener!"); this.readyState = "DISPOSED" /* DISPOSED */; } getInstance() { var _a; const instance = getGlobalSymbol(this.symbol); this.logger.info("retrieved global instance:", (_a = instance == null ? void 0 : instance.constructor) == null ? void 0 : _a.name); return instance; } setInstance() { setGlobalSymbol(this.symbol, this); this.logger.info("set global instance!", this.symbol.description); } clearInstance() { deleteGlobalSymbol(this.symbol); this.logger.info("cleared global instance!", this.symbol.description); } }; // src/createRequestId.ts function createRequestId() { return Math.random().toString(16).slice(2); } // src/utils/fetchUtils.ts var _FetchResponse = class extends Response { static isConfigurableStatusCode(status) { return status >= 200 && status <= 599; } static isRedirectResponse(status) { return _FetchResponse.STATUS_CODES_WITH_REDIRECT.includes(status); } /** * Returns a boolean indicating whether the given response status * code represents a response that can have a body. */ static isResponseWithBody(status) { return !_FetchResponse.STATUS_CODES_WITHOUT_BODY.includes(status); } static setUrl(url, response) { if (!url) { return; } if (response.url != "") { return; } Object.defineProperty(response, "url", { value: url, enumerable: true, configurable: true, writable: false }); } /** * Parses the given raw HTTP headers into a Fetch API `Headers` instance. */ static parseRawHeaders(rawHeaders) { const headers = new Headers(); for (let line = 0; line < rawHeaders.length; line += 2) { headers.append(rawHeaders[line], rawHeaders[line + 1]); } return headers; } constructor(body, init = {}) { var _a; const status = (_a = init.status) != null ? _a : 200; const safeStatus = _FetchResponse.isConfigurableStatusCode(status) ? status : 200; const finalBody = _FetchResponse.isResponseWithBody(status) ? body : null; super(finalBody, { ...init, status: safeStatus }); if (status !== safeStatus) { const stateSymbol = Object.getOwnPropertySymbols(this).find( (symbol) => symbol.description === "state" ); if (stateSymbol) { const state = Reflect.get(this, stateSymbol); Reflect.set(state, "status", status); } else { Object.defineProperty(this, "status", { value: status, enumerable: true, configurable: true, writable: false }); } } _FetchResponse.setUrl(init.url, this); } }; var FetchResponse = _FetchResponse; /** * Response status codes for responses that cannot have body. * @see https://fetch.spec.whatwg.org/#statuses */ FetchResponse.STATUS_CODES_WITHOUT_BODY = [101, 103, 204, 205, 304]; FetchResponse.STATUS_CODES_WITH_REDIRECT = [301, 302, 303, 307, 308]; export { INTERNAL_REQUEST_ID_HEADER_NAME, getGlobalSymbol, deleteGlobalSymbol, InterceptorReadyState, Interceptor, createRequestId, FetchResponse }; //# sourceMappingURL=chunk-I7HQIBT7.mjs.map