@crashlab/http-proxy 0.1.1 → 0.1.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"HttpInterceptor.d.ts","sourceRoot":"","sources":["../src/HttpInterceptor.ts"],"names":[],"mappings":"AAOA,oDAAoD;AACpD,MAAM,WAAW,MAAM;IACrB,GAAG,IAAI,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CACrE;AAED,gDAAgD;AAChD,MAAM,WAAW,UAAU;IACzB,iBAAiB,CAAC,EAAE,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3F,cAAc,CAAC,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IACvG;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;CACtC;AAED,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AA6HD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAa;IAEzC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAAK;IAE5B,OAAO,CAAC,gBAAgB,CAAC,CAAsB;IAC/C,OAAO,CAAC,YAAY,CAAC,CAAkB;IACvC,OAAO,CAAC,iBAAiB,CAAC,CAAuB;IACjD,OAAO,CAAC,aAAa,CAAC,CAAmB;gBAE7B,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,UAAU,CAAA;KAAE;IAO7D,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAKzD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAKjD,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE;IAQ1D;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAahC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAMnC,OAAO,IAAI,IAAI;IAoCf,SAAS,IAAI,IAAI;IASjB,KAAK,IAAI,IAAI;IASb,OAAO,CAAC,UAAU;CA8EnB"}
1
+ {"version":3,"file":"HttpInterceptor.d.ts","sourceRoot":"","sources":["../src/HttpInterceptor.ts"],"names":[],"mappings":"AAQA,oDAAoD;AACpD,MAAM,WAAW,MAAM;IACrB,GAAG,IAAI,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CACrE;AAED,gDAAgD;AAChD,MAAM,WAAW,UAAU;IACzB,iBAAiB,CAAC,EAAE,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3F,cAAc,CAAC,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IACvG;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;CACtC;AAED,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AA4HD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAa;IAEzC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAAK;IAE5B,OAAO,CAAC,gBAAgB,CAAC,CAAsB;IAC/C,OAAO,CAAC,YAAY,CAAC,CAAkB;IACvC,OAAO,CAAC,iBAAiB,CAAC,CAAuB;IACjD,OAAO,CAAC,aAAa,CAAC,CAAmB;gBAE7B,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,UAAU,CAAA;KAAE;IAO7D,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAKzD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAKjD,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE;IAQ1D;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAahC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAMnC,OAAO,IAAI,IAAI;IAoCf,SAAS,IAAI,IAAI;IASjB,KAAK,IAAI,IAAI;IASb,OAAO,CAAC,UAAU;CA8EnB"}
package/dist/index.cjs CHANGED
@@ -44,6 +44,17 @@ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
44
44
  var import_node_events = require("events");
45
45
  var http = __toESM(require("http"), 1);
46
46
  var import_node_url = require("url");
47
+
48
+ // src/req-hash.ts
49
+ function reqHash(s) {
50
+ let h = 5381;
51
+ for (let i = 0; i < s.length; i++) {
52
+ h = (h << 5) + h + s.charCodeAt(i) >>> 0;
53
+ }
54
+ return h;
55
+ }
56
+
57
+ // src/HttpInterceptor.ts
47
58
  var import_node_module = require("module");
48
59
  var FakeIncomingMessage = class extends import_node_events.EventEmitter {
49
60
  constructor(status, headers, _body) {
@@ -151,7 +162,6 @@ var MockRoute = class {
151
162
  var _require = (0, import_node_module.createRequire)(importMetaUrl);
152
163
  var httpCjs = _require("node:http");
153
164
  var httpsCjs = _require("node:https");
154
- var _httpReqCounter = 0;
155
165
  var HttpInterceptor = class {
156
166
  _routes = [];
157
167
  _allCalls = [];
@@ -291,7 +301,7 @@ var HttpInterceptor = class {
291
301
  if (this._scheduler) {
292
302
  const now = this._clock?.now() ?? 0;
293
303
  const when = now + latency;
294
- const opId = `http-${++_httpReqCounter}`;
304
+ const opId = `http-${now}-${reqHash(method + "|" + url + "|" + (fakeReq.body ?? ""))}`;
295
305
  this._scheduler.enqueueCompletion({
296
306
  id: opId,
297
307
  when,
@@ -354,7 +364,6 @@ function normalizeArgs(defaultProto, args) {
354
364
 
355
365
  // src/fetch-patch.ts
356
366
  var import_node_buffer = require("buffer");
357
- var _fetchReqCounter = 0;
358
367
  function createFetchPatch(interceptor, originalFetch) {
359
368
  return async function fakeFetch(input, init) {
360
369
  let url;
@@ -444,7 +453,7 @@ function createFetchPatch(interceptor, originalFetch) {
444
453
  if (anyInterceptor._scheduler) {
445
454
  const now = anyInterceptor._clock?.now() ?? 0;
446
455
  const when = now + latency;
447
- const opId = `fetch-${++_fetchReqCounter}`;
456
+ const opId = `fetch-${now}-${reqHash(method + "|" + url + "|" + (body ?? ""))}`;
448
457
  anyInterceptor._scheduler.enqueueCompletion({
449
458
  id: opId,
450
459
  when,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../../../node_modules/tsup/assets/cjs_shims.js","../src/HttpInterceptor.ts","../src/fetch-patch.ts","../src/install.ts"],"sourcesContent":["export { HttpInterceptor } from './HttpInterceptor.js';\nexport type { IClock, MockResponseConfig, FailConfig, RecordedCall } from './HttpInterceptor.js';\nexport { install } from './install.js';\nexport type { HttpProxyInstallResult } from './install.js';\nexport { createFetchPatch } from './fetch-patch.js';\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","import { EventEmitter } from 'node:events';\nimport * as http from 'node:http';\nimport * as https from 'node:https';\nimport { URL } from 'node:url';\n\n// Types\n\n/** Minimal virtual-clock interface (duck-typed). */\nexport interface IClock {\n now(): number;\n setTimeout(cb: (...args: unknown[]) => void, delay: number): number;\n}\n\n/** Minimal scheduler interface (duck-typed). */\nexport interface IScheduler {\n enqueueCompletion(op: { id: string; when: number; run: () => Promise<void> | void }): void;\n requestRunTick?(virtualTime: number): void;\n}\n\nexport interface MockResponseConfig {\n status?: number;\n headers?: Record<string, string>;\n body?: unknown;\n /** Virtual-clock latency in ms (requires an IClock instance). */\n latency?: number;\n /** Dynamic handler — overrides static body/status when provided. */\n handler?: (call: RecordedCall) => { status: number; body?: unknown; headers?: Record<string, string> };\n /**\n * URL match mode.\n * - `'exact'` (default): `url === urlPattern` — only matches the exact URL.\n * - `'prefix'`: `url.startsWith(urlPattern)` — matches any URL that begins with the pattern.\n * - `'regex'`: `new RegExp(urlPattern).test(url)` — matches via regular expression.\n */\n match?: 'exact' | 'prefix' | 'regex';\n}\n\nexport interface FailConfig {\n /** Succeed the first N calls, then error. */\n after?: number;\n error: string;\n}\n\nexport interface RecordedCall {\n method: string;\n url: string;\n headers: Record<string, string>;\n body: string;\n timestamp: number;\n}\n\n// Fakes\n\nclass FakeIncomingMessage extends EventEmitter {\n statusCode: number;\n statusMessage: string;\n headers: Record<string, string>;\n\n constructor(status: number, headers: Record<string, string>, private readonly _body: string) {\n super();\n this.statusCode = status;\n this.statusMessage = http.STATUS_CODES[status] ?? '';\n this.headers = headers;\n }\n\n _flush(): void {\n queueMicrotask(() => {\n this.emit('data', Buffer.from(this._body));\n this.emit('end');\n });\n }\n}\n\nclass FakeClientRequest extends EventEmitter {\n private _chunks: Buffer[] = [];\n headersSent = false;\n\n write(chunk: string | Buffer): boolean {\n this._chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n return true;\n }\n\n end(chunk?: string | Buffer): this {\n if (chunk) this.write(chunk);\n this.emit('_end');\n return this;\n }\n\n get body(): string {\n return Buffer.concat(this._chunks).toString();\n }\n\n // no-ops for compat\n setHeader(): this { return this; }\n getHeader(): undefined { return undefined; }\n removeHeader(): void {}\n flushHeaders(): void {}\n setTimeout(): this { return this; }\n setNoDelay(): void {}\n setSocketKeepAlive(): void {}\n abort(): void {}\n destroy(): this { return this; }\n}\n\n// Route\n\nclass MockRoute {\n readonly calls: RecordedCall[] = [];\n private _callCount = 0;\n private readonly _matchMode: 'exact' | 'prefix' | 'regex';\n private readonly _regex?: RegExp;\n\n constructor(\n readonly urlPattern: string,\n readonly config: MockResponseConfig,\n readonly failConfig?: FailConfig,\n ) {\n this._matchMode = config.match ?? 'exact';\n if (this._matchMode === 'regex') {\n this._regex = new RegExp(urlPattern);\n }\n }\n\n matches(url: string): boolean {\n switch (this._matchMode) {\n case 'exact': return url === this.urlPattern;\n case 'prefix': return url.startsWith(this.urlPattern);\n case 'regex': return this._regex!.test(url);\n }\n }\n\n respond(call: RecordedCall): { error?: string; status: number; headers: Record<string, string>; body: string } {\n this.calls.push(call);\n this._callCount++;\n\n if (this.failConfig) {\n const limit = this.failConfig.after ?? 0;\n if (this._callCount > limit) {\n return { error: this.failConfig.error, status: 0, headers: {}, body: '' };\n }\n }\n\n if (this.config.handler) {\n const r = this.config.handler(call);\n const body = typeof r.body === 'string' ? r.body : JSON.stringify(r.body ?? '');\n return { status: r.status, headers: r.headers ?? { 'content-type': 'application/json' }, body };\n }\n\n const body = typeof this.config.body === 'string'\n ? this.config.body\n : JSON.stringify(this.config.body ?? '');\n return {\n status: this.config.status ?? 200,\n headers: this.config.headers ?? { 'content-type': 'application/json' },\n body,\n };\n }\n}\n\n// Interceptor\n\n// We need to write directly to the module object's internal property.\n// ESM `import * as http` creates a frozen namespace — we can't assign\n// to it. Instead we grab the *CJS* module from require.cache and\n// patch the exports object there, which IS mutable.\n//\n// We use createRequire so this file can stay ESM.\nimport { createRequire } from 'node:module';\nconst _require = createRequire(import.meta.url);\nconst httpCjs = _require('node:http') as typeof http;\nconst httpsCjs = _require('node:https') as typeof https;\n\nlet _httpReqCounter = 0;\n\nexport class HttpInterceptor {\n private readonly _routes: MockRoute[] = [];\n private readonly _allCalls: RecordedCall[] = [];\n private readonly _clock?: IClock;\n private readonly _scheduler?: IScheduler;\n\n private _partitioned = false;\n private _defaultLatency = 0;\n\n private _origHttpRequest?: typeof http.request;\n private _origHttpGet?: typeof http.get;\n private _origHttpsRequest?: typeof https.request;\n private _origHttpsGet?: typeof https.get;\n\n constructor(opts?: { clock?: IClock; scheduler?: IScheduler }) {\n this._clock = opts?.clock;\n this._scheduler = opts?.scheduler;\n }\n\n // mock registration\n\n mock(urlPrefix: string, config: MockResponseConfig): this {\n this._routes.push(new MockRoute(urlPrefix, config));\n return this;\n }\n\n fail(urlPrefix: string, config: FailConfig): this {\n this._routes.push(new MockRoute(urlPrefix, { status: 0 }, config));\n return this;\n }\n\n calls(method?: string, urlPrefix?: string): RecordedCall[] {\n return this._allCalls.filter((c) => {\n if (method && c.method !== method.toUpperCase()) return false;\n if (urlPrefix && !c.url.startsWith(urlPrefix)) return false;\n return true;\n });\n }\n\n /**\n * Block all HTTP requests for `duration` virtual ms.\n * Requests made during the partition receive a connection-refused error.\n */\n blockAll(duration: number): void {\n this._partitioned = true;\n if (this._clock) {\n this._clock.setTimeout(() => { this._partitioned = false; }, duration);\n } else {\n console.warn(\n 'SimNode: HttpInterceptor.blockAll() called without a virtual clock. ' +\n 'Falling back to real setTimeout — partition duration will be wall-clock, not deterministic.',\n );\n setTimeout(() => { this._partitioned = false; }, duration);\n }\n }\n\n /**\n * Add a global extra latency (ms) to all HTTP responses.\n * Used by FaultInjector.slowDatabase() for HTTP-based DBs.\n */\n setDefaultLatency(ms: number): void {\n this._defaultLatency = ms;\n }\n\n // patching\n\n install(): void {\n this._origHttpRequest = httpCjs.request;\n this._origHttpGet = httpCjs.get;\n this._origHttpsRequest = httpsCjs.request;\n this._origHttpsGet = httpsCjs.get;\n\n const self = this;\n\n const origHttpReq = this._origHttpRequest!;\n const origHttpsReq = this._origHttpsRequest!;\n\n const makeRequest = (proto: string, origReq: typeof http.request) =>\n function fakeRequest(this: unknown, ...args: unknown[]): FakeClientRequest | http.ClientRequest {\n const { url, method, headers, callback } = normalizeArgs(proto, args);\n // Passthrough: unmatched localhost requests (supertest, local test\n // servers) ALWAYS go through the real http stack — even during a\n // network partition. blockAll() only affects external / mocked URLs.\n if (_isLocalUrl(url) && !self._routes.find(r => r.matches(url))) {\n return origReq.apply(null, args as any);\n }\n return self._intercept(url, method, headers, callback);\n } as unknown as typeof http.request;\n\n const makeGet = (reqFn: typeof http.request) =>\n function fakeGet(this: unknown, ...args: unknown[]): FakeClientRequest | http.ClientRequest {\n const req = (reqFn as any)(...args);\n req.end();\n return req;\n } as unknown as typeof http.get;\n\n httpCjs.request = makeRequest('http:', origHttpReq);\n httpCjs.get = makeGet(httpCjs.request);\n httpsCjs.request = makeRequest('https:', origHttpsReq);\n httpsCjs.get = makeGet(httpsCjs.request);\n }\n\n uninstall(): void {\n if (this._origHttpRequest) httpCjs.request = this._origHttpRequest;\n if (this._origHttpGet) httpCjs.get = this._origHttpGet;\n if (this._origHttpsRequest) httpsCjs.request = this._origHttpsRequest;\n if (this._origHttpsGet) httpsCjs.get = this._origHttpsGet;\n this._partitioned = false;\n this._defaultLatency = 0;\n }\n\n reset(): void {\n this._routes.length = 0;\n this._allCalls.length = 0;\n this._partitioned = false;\n this._defaultLatency = 0;\n }\n\n // internal\n\n private _intercept(\n url: string,\n method: string,\n headers: Record<string, string>,\n callback?: (res: FakeIncomingMessage) => void,\n ): FakeClientRequest {\n const route = this._routes.find((r) => r.matches(url));\n const fakeReq = new FakeClientRequest();\n if (callback) fakeReq.on('response', callback);\n\n fakeReq.on('_end', () => {\n const call: RecordedCall = {\n method,\n url,\n headers,\n body: fakeReq.body,\n timestamp: this._clock?.now() ?? Date.now(),\n };\n this._allCalls.push(call);\n\n // Network partition: reject with error\n if (this._partitioned) {\n fakeReq.emit('error', Object.assign(new Error(`Network partition: ${method} ${url} rejected`), { code: 'ECONNREFUSED' }));\n return;\n }\n\n if (!route) {\n fakeReq.emit('error', new Error(`No mock matched: ${method} ${url}`));\n return;\n }\n\n let result: { error?: string; status: number; headers: Record<string, string>; body: string };\n try {\n result = route.respond(call);\n } catch (err: unknown) {\n fakeReq.emit('error', err instanceof Error ? err : new Error(String(err)));\n return;\n }\n\n const deliver = (): void => {\n if (result.error) {\n fakeReq.emit('error', new Error(result.error));\n return;\n }\n const fakeRes = new FakeIncomingMessage(result.status, result.headers, result.body);\n fakeReq.emit('response', fakeRes);\n fakeRes._flush();\n };\n\n // Effective latency = route latency + global default (from fault injection)\n const latency = (route.config.latency ?? 0) + this._defaultLatency;\n\n // Spec v3: Always route through scheduler when available — even zero-latency\n // responses — so PRNG ordering applies to all same-tick HTTP completions.\n if (this._scheduler) {\n const now = this._clock?.now() ?? 0;\n const when = now + latency;\n const opId = `http-${++_httpReqCounter}`;\n this._scheduler.enqueueCompletion({\n id: opId,\n when,\n run: () => { deliver(); return Promise.resolve(); },\n });\n if (latency <= 0) {\n this._scheduler.requestRunTick?.(now);\n }\n } else if (this._clock && latency > 0) {\n this._clock.setTimeout(deliver, latency);\n } else {\n throw new Error(\n '[SimNode] HttpInterceptor: a Scheduler is required for deterministic delivery. ' +\n 'Pass { scheduler } when constructing HttpInterceptor.',\n );\n }\n });\n\n return fakeReq;\n }\n}\n\n// Helpers\n\n/** Return true if the URL targets a loopback address (localhost, 127.0.0.1, ::1). */\nfunction _isLocalUrl(url: string): boolean {\n try {\n const h = new URL(url).hostname.toLowerCase();\n return h === 'localhost' || h === '127.0.0.1' || h === '::1' || h === '[::1]';\n } catch {\n return false;\n }\n}\n\nfunction normalizeArgs(\n defaultProto: string,\n args: unknown[],\n): { url: string; method: string; headers: Record<string, string>; callback?: (res: any) => void } {\n let url: string;\n let options: Record<string, any> = {};\n let callback: ((res: any) => void) | undefined;\n\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\n const parsed = new URL(args[0].toString());\n url = parsed.toString();\n if (typeof args[1] === 'function') {\n callback = args[1] as (res: any) => void;\n } else if (typeof args[1] === 'object' && args[1] !== null) {\n options = args[1] as Record<string, any>;\n if (typeof args[2] === 'function') callback = args[2] as (res: any) => void;\n }\n } else {\n options = (args[0] ?? {}) as Record<string, any>;\n if (typeof args[1] === 'function') callback = args[1] as (res: any) => void;\n const proto = (options.protocol as string) ?? defaultProto;\n const host = (options.hostname ?? options.host ?? 'localhost') as string;\n const port = options.port ? `:${options.port as string}` : '';\n const path = (options.path ?? '/') as string;\n url = `${proto}//${host}${port}${path}`;\n }\n\n return {\n url,\n method: ((options.method as string) ?? 'GET').toUpperCase(),\n headers: (options.headers ?? {}) as Record<string, string>,\n callback,\n };\n}\n","import type { HttpInterceptor, IScheduler, RecordedCall } from './HttpInterceptor.js';\nimport { Buffer } from 'node:buffer';\n\nlet _fetchReqCounter = 0;\n\nexport function createFetchPatch(interceptor: HttpInterceptor, originalFetch: typeof globalThis.fetch) {\n return async function fakeFetch(input: string | URL | Request, init?: RequestInit): Promise<Response> {\n // 1. Normalize input to URL string and extract method/headers/body\n let url: string;\n let method = 'GET';\n const headers: Record<string, string> = {};\n let body = '';\n\n if (input instanceof Request) {\n url = input.url;\n method = input.method;\n input.headers.forEach((value, key) => {\n headers[key.toLowerCase()] = value;\n });\n if (input.body) {\n try {\n const ab = await input.arrayBuffer();\n body = Buffer.from(ab).toString('utf-8');\n } catch {\n body = '';\n }\n }\n } else {\n url = typeof input === 'string' ? input : input.toString();\n }\n\n if (init) {\n if (init.method) method = init.method.toUpperCase();\n if (init.headers) {\n if (init.headers instanceof Headers) {\n init.headers.forEach((value, key) => {\n headers[key.toLowerCase()] = value;\n });\n } else if (Array.isArray(init.headers)) {\n for (const [key, value] of init.headers) {\n headers[key.toLowerCase()] = value;\n }\n } else {\n for (const [key, value] of Object.entries(init.headers)) {\n headers[key.toLowerCase()] = value as string;\n }\n }\n }\n if (init.body) {\n if (typeof init.body === 'string') {\n body = init.body;\n } else if (init.body instanceof Buffer) {\n body = init.body.toString('utf-8');\n } else {\n body = String(init.body);\n }\n }\n }\n\n return new Promise((resolve, reject) => {\n const anyInterceptor = interceptor as any;\n const route = anyInterceptor._routes.find((r: any) => r.matches(url));\n\n const call: RecordedCall = {\n method,\n url,\n headers,\n body,\n timestamp: anyInterceptor._clock?.now() ?? Date.now(),\n };\n anyInterceptor._allCalls.push(call);\n\n // Network partition check\n if (anyInterceptor._partitioned) {\n return reject(Object.assign(new TypeError(`fetch failed: Network partition active — ${method} ${url} rejected`), { code: 'ECONNREFUSED' }));\n }\n\n if (!route) {\n return reject(new TypeError(`fetch failed: No mock matched: ${method} ${url}`));\n }\n\n let result: { error?: string; status: number; headers: Record<string, string>; body: string };\n try {\n result = route.respond(call);\n } catch (err: unknown) {\n return reject(err instanceof Error ? err : new TypeError(String(err)));\n }\n\n const deliver = (): void => {\n if (result.error) {\n return reject(new TypeError(result.error));\n }\n\n const responseHeaders = new Headers(result.headers);\n const response = new Response(result.body, {\n status: result.status,\n statusText: 'MOCKED',\n headers: responseHeaders,\n });\n\n resolve(response);\n };\n\n // Effective latency = route latency + global defaultLatency (from fault injection)\n const latency = (route.config.latency ?? 0) + (anyInterceptor._defaultLatency ?? 0);\n\n // Spec v3: Always route through scheduler when available — even zero-latency\n // responses — so PRNG ordering applies to all same-tick completions.\n if (anyInterceptor._scheduler) {\n const now = anyInterceptor._clock?.now() ?? 0;\n const when = now + latency;\n const opId = `fetch-${++_fetchReqCounter}`;\n (anyInterceptor._scheduler as IScheduler).enqueueCompletion({\n id: opId,\n when,\n run: () => { deliver(); return Promise.resolve(); },\n });\n if (latency <= 0) {\n (anyInterceptor._scheduler as IScheduler).requestRunTick?.(now);\n }\n } else if (anyInterceptor._clock && latency > 0) {\n anyInterceptor._clock.setTimeout(deliver, latency);\n } else {\n throw new Error(\n '[SimNode] fetch: a Scheduler is required for deterministic delivery. ' +\n 'Pass { scheduler } when constructing HttpInterceptor.',\n );\n }\n });\n };\n}\n","import { HttpInterceptor } from './HttpInterceptor.js';\nimport { createFetchPatch } from './fetch-patch.js';\nimport { createRequire } from 'node:module';\n\nconst _require = createRequire(import.meta.url);\n\n\nexport interface HttpProxyInstallResult {\n interceptor: HttpInterceptor;\n uninstall: () => void;\n}\n\nexport function install(interceptorOrClock?: HttpInterceptor | any): HttpProxyInstallResult {\n let interceptor: HttpInterceptor;\n \n if (interceptorOrClock instanceof HttpInterceptor) {\n interceptor = interceptorOrClock;\n } else {\n interceptor = new HttpInterceptor({ clock: interceptorOrClock });\n }\n\n // 1. Install http/https patches\n interceptor.install();\n\n // 2. Install fetch patch\n const origFetch = globalThis.fetch;\n if (origFetch) {\n globalThis.fetch = createFetchPatch(interceptor, origFetch);\n }\n\n // 3. Try to patch undici if available in the module graph\n // Undici is what powers Node's native fetch. A lot of libraries (like Prisma, Axios in some cases)\n // might use undici directly.\n let undiciUninstall: (() => void) | undefined;\n try {\n const customRequire = createRequire(process.cwd() + '/'); // Attempt to require from workspace root\n \n let undici: any;\n try {\n undici = customRequire('undici');\n } catch {\n undici = _require('undici');\n }\n\n if (undici) {\n const origUndiciFetch = undici.fetch;\n const origUndiciRequest = undici.request;\n\n undici.fetch = createFetchPatch(interceptor, origUndiciFetch);\n // undici.request is a bit different API, but if any libraries use it, we can wrap it.\n // For this fix, wrapping undici.fetch handles most cases. \n // We can also wrap undici.request if necessary, but returning a dispatcher response is complex.\n // Let's at least wrap fetch.\n \n undiciUninstall = () => {\n undici.fetch = origUndiciFetch;\n undici.request = origUndiciRequest;\n };\n }\n } catch (err) {\n // ignore if undici is not found\n }\n\n function uninstall(): void {\n interceptor.uninstall();\n globalThis.fetch = origFetch;\n if (undiciUninstall) {\n undiciUninstall();\n }\n }\n\n return { interceptor, uninstall };\n}\n"],"mappings":"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","names":["body","import_node_module","_require"]}
1
+ {"version":3,"sources":["../src/index.ts","../../../node_modules/tsup/assets/cjs_shims.js","../src/HttpInterceptor.ts","../src/req-hash.ts","../src/fetch-patch.ts","../src/install.ts"],"sourcesContent":["export { HttpInterceptor } from './HttpInterceptor.js';\nexport type { IClock, MockResponseConfig, FailConfig, RecordedCall } from './HttpInterceptor.js';\nexport { install } from './install.js';\nexport type { HttpProxyInstallResult } from './install.js';\nexport { createFetchPatch } from './fetch-patch.js';\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","import { EventEmitter } from 'node:events';\nimport * as http from 'node:http';\nimport * as https from 'node:https';\nimport { URL } from 'node:url';\nimport { reqHash } from './req-hash.js';\n\n// Types\n\n/** Minimal virtual-clock interface (duck-typed). */\nexport interface IClock {\n now(): number;\n setTimeout(cb: (...args: unknown[]) => void, delay: number): number;\n}\n\n/** Minimal scheduler interface (duck-typed). */\nexport interface IScheduler {\n enqueueCompletion(op: { id: string; when: number; run: () => Promise<void> | void }): void;\n requestRunTick?(virtualTime: number): void;\n}\n\nexport interface MockResponseConfig {\n status?: number;\n headers?: Record<string, string>;\n body?: unknown;\n /** Virtual-clock latency in ms (requires an IClock instance). */\n latency?: number;\n /** Dynamic handler — overrides static body/status when provided. */\n handler?: (call: RecordedCall) => { status: number; body?: unknown; headers?: Record<string, string> };\n /**\n * URL match mode.\n * - `'exact'` (default): `url === urlPattern` — only matches the exact URL.\n * - `'prefix'`: `url.startsWith(urlPattern)` — matches any URL that begins with the pattern.\n * - `'regex'`: `new RegExp(urlPattern).test(url)` — matches via regular expression.\n */\n match?: 'exact' | 'prefix' | 'regex';\n}\n\nexport interface FailConfig {\n /** Succeed the first N calls, then error. */\n after?: number;\n error: string;\n}\n\nexport interface RecordedCall {\n method: string;\n url: string;\n headers: Record<string, string>;\n body: string;\n timestamp: number;\n}\n\n// Fakes\n\nclass FakeIncomingMessage extends EventEmitter {\n statusCode: number;\n statusMessage: string;\n headers: Record<string, string>;\n\n constructor(status: number, headers: Record<string, string>, private readonly _body: string) {\n super();\n this.statusCode = status;\n this.statusMessage = http.STATUS_CODES[status] ?? '';\n this.headers = headers;\n }\n\n _flush(): void {\n queueMicrotask(() => {\n this.emit('data', Buffer.from(this._body));\n this.emit('end');\n });\n }\n}\n\nclass FakeClientRequest extends EventEmitter {\n private _chunks: Buffer[] = [];\n headersSent = false;\n\n write(chunk: string | Buffer): boolean {\n this._chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n return true;\n }\n\n end(chunk?: string | Buffer): this {\n if (chunk) this.write(chunk);\n this.emit('_end');\n return this;\n }\n\n get body(): string {\n return Buffer.concat(this._chunks).toString();\n }\n\n // no-ops for compat\n setHeader(): this { return this; }\n getHeader(): undefined { return undefined; }\n removeHeader(): void {}\n flushHeaders(): void {}\n setTimeout(): this { return this; }\n setNoDelay(): void {}\n setSocketKeepAlive(): void {}\n abort(): void {}\n destroy(): this { return this; }\n}\n\n// Route\n\nclass MockRoute {\n readonly calls: RecordedCall[] = [];\n private _callCount = 0;\n private readonly _matchMode: 'exact' | 'prefix' | 'regex';\n private readonly _regex?: RegExp;\n\n constructor(\n readonly urlPattern: string,\n readonly config: MockResponseConfig,\n readonly failConfig?: FailConfig,\n ) {\n this._matchMode = config.match ?? 'exact';\n if (this._matchMode === 'regex') {\n this._regex = new RegExp(urlPattern);\n }\n }\n\n matches(url: string): boolean {\n switch (this._matchMode) {\n case 'exact': return url === this.urlPattern;\n case 'prefix': return url.startsWith(this.urlPattern);\n case 'regex': return this._regex!.test(url);\n }\n }\n\n respond(call: RecordedCall): { error?: string; status: number; headers: Record<string, string>; body: string } {\n this.calls.push(call);\n this._callCount++;\n\n if (this.failConfig) {\n const limit = this.failConfig.after ?? 0;\n if (this._callCount > limit) {\n return { error: this.failConfig.error, status: 0, headers: {}, body: '' };\n }\n }\n\n if (this.config.handler) {\n const r = this.config.handler(call);\n const body = typeof r.body === 'string' ? r.body : JSON.stringify(r.body ?? '');\n return { status: r.status, headers: r.headers ?? { 'content-type': 'application/json' }, body };\n }\n\n const body = typeof this.config.body === 'string'\n ? this.config.body\n : JSON.stringify(this.config.body ?? '');\n return {\n status: this.config.status ?? 200,\n headers: this.config.headers ?? { 'content-type': 'application/json' },\n body,\n };\n }\n}\n\n// Interceptor\n\n// We need to write directly to the module object's internal property.\n// ESM `import * as http` creates a frozen namespace — we can't assign\n// to it. Instead we grab the *CJS* module from require.cache and\n// patch the exports object there, which IS mutable.\n//\n// We use createRequire so this file can stay ESM.\nimport { createRequire } from 'node:module';\nconst _require = createRequire(import.meta.url);\nconst httpCjs = _require('node:http') as typeof http;\nconst httpsCjs = _require('node:https') as typeof https;\n\n\nexport class HttpInterceptor {\n private readonly _routes: MockRoute[] = [];\n private readonly _allCalls: RecordedCall[] = [];\n private readonly _clock?: IClock;\n private readonly _scheduler?: IScheduler;\n\n private _partitioned = false;\n private _defaultLatency = 0;\n\n private _origHttpRequest?: typeof http.request;\n private _origHttpGet?: typeof http.get;\n private _origHttpsRequest?: typeof https.request;\n private _origHttpsGet?: typeof https.get;\n\n constructor(opts?: { clock?: IClock; scheduler?: IScheduler }) {\n this._clock = opts?.clock;\n this._scheduler = opts?.scheduler;\n }\n\n // mock registration\n\n mock(urlPrefix: string, config: MockResponseConfig): this {\n this._routes.push(new MockRoute(urlPrefix, config));\n return this;\n }\n\n fail(urlPrefix: string, config: FailConfig): this {\n this._routes.push(new MockRoute(urlPrefix, { status: 0 }, config));\n return this;\n }\n\n calls(method?: string, urlPrefix?: string): RecordedCall[] {\n return this._allCalls.filter((c) => {\n if (method && c.method !== method.toUpperCase()) return false;\n if (urlPrefix && !c.url.startsWith(urlPrefix)) return false;\n return true;\n });\n }\n\n /**\n * Block all HTTP requests for `duration` virtual ms.\n * Requests made during the partition receive a connection-refused error.\n */\n blockAll(duration: number): void {\n this._partitioned = true;\n if (this._clock) {\n this._clock.setTimeout(() => { this._partitioned = false; }, duration);\n } else {\n console.warn(\n 'SimNode: HttpInterceptor.blockAll() called without a virtual clock. ' +\n 'Falling back to real setTimeout — partition duration will be wall-clock, not deterministic.',\n );\n setTimeout(() => { this._partitioned = false; }, duration);\n }\n }\n\n /**\n * Add a global extra latency (ms) to all HTTP responses.\n * Used by FaultInjector.slowDatabase() for HTTP-based DBs.\n */\n setDefaultLatency(ms: number): void {\n this._defaultLatency = ms;\n }\n\n // patching\n\n install(): void {\n this._origHttpRequest = httpCjs.request;\n this._origHttpGet = httpCjs.get;\n this._origHttpsRequest = httpsCjs.request;\n this._origHttpsGet = httpsCjs.get;\n\n const self = this;\n\n const origHttpReq = this._origHttpRequest!;\n const origHttpsReq = this._origHttpsRequest!;\n\n const makeRequest = (proto: string, origReq: typeof http.request) =>\n function fakeRequest(this: unknown, ...args: unknown[]): FakeClientRequest | http.ClientRequest {\n const { url, method, headers, callback } = normalizeArgs(proto, args);\n // Passthrough: unmatched localhost requests (supertest, local test\n // servers) ALWAYS go through the real http stack — even during a\n // network partition. blockAll() only affects external / mocked URLs.\n if (_isLocalUrl(url) && !self._routes.find(r => r.matches(url))) {\n return origReq.apply(null, args as any);\n }\n return self._intercept(url, method, headers, callback);\n } as unknown as typeof http.request;\n\n const makeGet = (reqFn: typeof http.request) =>\n function fakeGet(this: unknown, ...args: unknown[]): FakeClientRequest | http.ClientRequest {\n const req = (reqFn as any)(...args);\n req.end();\n return req;\n } as unknown as typeof http.get;\n\n httpCjs.request = makeRequest('http:', origHttpReq);\n httpCjs.get = makeGet(httpCjs.request);\n httpsCjs.request = makeRequest('https:', origHttpsReq);\n httpsCjs.get = makeGet(httpsCjs.request);\n }\n\n uninstall(): void {\n if (this._origHttpRequest) httpCjs.request = this._origHttpRequest;\n if (this._origHttpGet) httpCjs.get = this._origHttpGet;\n if (this._origHttpsRequest) httpsCjs.request = this._origHttpsRequest;\n if (this._origHttpsGet) httpsCjs.get = this._origHttpsGet;\n this._partitioned = false;\n this._defaultLatency = 0;\n }\n\n reset(): void {\n this._routes.length = 0;\n this._allCalls.length = 0;\n this._partitioned = false;\n this._defaultLatency = 0;\n }\n\n // internal\n\n private _intercept(\n url: string,\n method: string,\n headers: Record<string, string>,\n callback?: (res: FakeIncomingMessage) => void,\n ): FakeClientRequest {\n const route = this._routes.find((r) => r.matches(url));\n const fakeReq = new FakeClientRequest();\n if (callback) fakeReq.on('response', callback);\n\n fakeReq.on('_end', () => {\n const call: RecordedCall = {\n method,\n url,\n headers,\n body: fakeReq.body,\n timestamp: this._clock?.now() ?? Date.now(),\n };\n this._allCalls.push(call);\n\n // Network partition: reject with error\n if (this._partitioned) {\n fakeReq.emit('error', Object.assign(new Error(`Network partition: ${method} ${url} rejected`), { code: 'ECONNREFUSED' }));\n return;\n }\n\n if (!route) {\n fakeReq.emit('error', new Error(`No mock matched: ${method} ${url}`));\n return;\n }\n\n let result: { error?: string; status: number; headers: Record<string, string>; body: string };\n try {\n result = route.respond(call);\n } catch (err: unknown) {\n fakeReq.emit('error', err instanceof Error ? err : new Error(String(err)));\n return;\n }\n\n const deliver = (): void => {\n if (result.error) {\n fakeReq.emit('error', new Error(result.error));\n return;\n }\n const fakeRes = new FakeIncomingMessage(result.status, result.headers, result.body);\n fakeReq.emit('response', fakeRes);\n fakeRes._flush();\n };\n\n // Effective latency = route latency + global default (from fault injection)\n const latency = (route.config.latency ?? 0) + this._defaultLatency;\n\n // Spec v3: Always route through scheduler when available — even zero-latency\n // responses — so PRNG ordering applies to all same-tick HTTP completions.\n if (this._scheduler) {\n const now = this._clock?.now() ?? 0;\n const when = now + latency;\n const opId = `http-${now}-${reqHash(method + '|' + url + '|' + (fakeReq.body ?? ''))}`;\n this._scheduler.enqueueCompletion({\n id: opId,\n when,\n run: () => { deliver(); return Promise.resolve(); },\n });\n if (latency <= 0) {\n this._scheduler.requestRunTick?.(now);\n }\n } else if (this._clock && latency > 0) {\n this._clock.setTimeout(deliver, latency);\n } else {\n throw new Error(\n '[SimNode] HttpInterceptor: a Scheduler is required for deterministic delivery. ' +\n 'Pass { scheduler } when constructing HttpInterceptor.',\n );\n }\n });\n\n return fakeReq;\n }\n}\n\n// Helpers\n\n/** Return true if the URL targets a loopback address (localhost, 127.0.0.1, ::1). */\nfunction _isLocalUrl(url: string): boolean {\n try {\n const h = new URL(url).hostname.toLowerCase();\n return h === 'localhost' || h === '127.0.0.1' || h === '::1' || h === '[::1]';\n } catch {\n return false;\n }\n}\n\nfunction normalizeArgs(\n defaultProto: string,\n args: unknown[],\n): { url: string; method: string; headers: Record<string, string>; callback?: (res: any) => void } {\n let url: string;\n let options: Record<string, any> = {};\n let callback: ((res: any) => void) | undefined;\n\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\n const parsed = new URL(args[0].toString());\n url = parsed.toString();\n if (typeof args[1] === 'function') {\n callback = args[1] as (res: any) => void;\n } else if (typeof args[1] === 'object' && args[1] !== null) {\n options = args[1] as Record<string, any>;\n if (typeof args[2] === 'function') callback = args[2] as (res: any) => void;\n }\n } else {\n options = (args[0] ?? {}) as Record<string, any>;\n if (typeof args[1] === 'function') callback = args[1] as (res: any) => void;\n const proto = (options.protocol as string) ?? defaultProto;\n const host = (options.hostname ?? options.host ?? 'localhost') as string;\n const port = options.port ? `:${options.port as string}` : '';\n const path = (options.path ?? '/') as string;\n url = `${proto}//${host}${port}${path}`;\n }\n\n return {\n url,\n method: ((options.method as string) ?? 'GET').toUpperCase(),\n headers: (options.headers ?? {}) as Record<string, string>,\n callback,\n };\n}\n","/** DJB2 hash of a string — used to make op IDs content-derived. */\nexport function reqHash(s: string): number {\n let h = 5381;\n for (let i = 0; i < s.length; i++) {\n h = ((h << 5) + h + s.charCodeAt(i)) >>> 0;\n }\n return h;\n}\n","import type { HttpInterceptor, IScheduler, RecordedCall } from './HttpInterceptor.js';\nimport { Buffer } from 'node:buffer';\n\nimport { reqHash } from './req-hash.js';\n\nexport function createFetchPatch(interceptor: HttpInterceptor, originalFetch: typeof globalThis.fetch) {\n return async function fakeFetch(input: string | URL | Request, init?: RequestInit): Promise<Response> {\n // 1. Normalize input to URL string and extract method/headers/body\n let url: string;\n let method = 'GET';\n const headers: Record<string, string> = {};\n let body = '';\n\n if (input instanceof Request) {\n url = input.url;\n method = input.method;\n input.headers.forEach((value, key) => {\n headers[key.toLowerCase()] = value;\n });\n if (input.body) {\n try {\n const ab = await input.arrayBuffer();\n body = Buffer.from(ab).toString('utf-8');\n } catch {\n body = '';\n }\n }\n } else {\n url = typeof input === 'string' ? input : input.toString();\n }\n\n if (init) {\n if (init.method) method = init.method.toUpperCase();\n if (init.headers) {\n if (init.headers instanceof Headers) {\n init.headers.forEach((value, key) => {\n headers[key.toLowerCase()] = value;\n });\n } else if (Array.isArray(init.headers)) {\n for (const [key, value] of init.headers) {\n headers[key.toLowerCase()] = value;\n }\n } else {\n for (const [key, value] of Object.entries(init.headers)) {\n headers[key.toLowerCase()] = value as string;\n }\n }\n }\n if (init.body) {\n if (typeof init.body === 'string') {\n body = init.body;\n } else if (init.body instanceof Buffer) {\n body = init.body.toString('utf-8');\n } else {\n body = String(init.body);\n }\n }\n }\n\n return new Promise((resolve, reject) => {\n const anyInterceptor = interceptor as any;\n const route = anyInterceptor._routes.find((r: any) => r.matches(url));\n\n const call: RecordedCall = {\n method,\n url,\n headers,\n body,\n timestamp: anyInterceptor._clock?.now() ?? Date.now(),\n };\n anyInterceptor._allCalls.push(call);\n\n // Network partition check\n if (anyInterceptor._partitioned) {\n return reject(Object.assign(new TypeError(`fetch failed: Network partition active — ${method} ${url} rejected`), { code: 'ECONNREFUSED' }));\n }\n\n if (!route) {\n return reject(new TypeError(`fetch failed: No mock matched: ${method} ${url}`));\n }\n\n let result: { error?: string; status: number; headers: Record<string, string>; body: string };\n try {\n result = route.respond(call);\n } catch (err: unknown) {\n return reject(err instanceof Error ? err : new TypeError(String(err)));\n }\n\n const deliver = (): void => {\n if (result.error) {\n return reject(new TypeError(result.error));\n }\n\n const responseHeaders = new Headers(result.headers);\n const response = new Response(result.body, {\n status: result.status,\n statusText: 'MOCKED',\n headers: responseHeaders,\n });\n\n resolve(response);\n };\n\n // Effective latency = route latency + global defaultLatency (from fault injection)\n const latency = (route.config.latency ?? 0) + (anyInterceptor._defaultLatency ?? 0);\n\n // Spec v3: Always route through scheduler when available — even zero-latency\n // responses — so PRNG ordering applies to all same-tick completions.\n if (anyInterceptor._scheduler) {\n const now = anyInterceptor._clock?.now() ?? 0;\n const when = now + latency;\n const opId = `fetch-${now}-${reqHash(method + '|' + url + '|' + (body ?? ''))}`;\n (anyInterceptor._scheduler as IScheduler).enqueueCompletion({\n id: opId,\n when,\n run: () => { deliver(); return Promise.resolve(); },\n });\n if (latency <= 0) {\n (anyInterceptor._scheduler as IScheduler).requestRunTick?.(now);\n }\n } else if (anyInterceptor._clock && latency > 0) {\n anyInterceptor._clock.setTimeout(deliver, latency);\n } else {\n throw new Error(\n '[SimNode] fetch: a Scheduler is required for deterministic delivery. ' +\n 'Pass { scheduler } when constructing HttpInterceptor.',\n );\n }\n });\n };\n}\n","import { HttpInterceptor } from './HttpInterceptor.js';\nimport { createFetchPatch } from './fetch-patch.js';\nimport { createRequire } from 'node:module';\n\nconst _require = createRequire(import.meta.url);\n\n\nexport interface HttpProxyInstallResult {\n interceptor: HttpInterceptor;\n uninstall: () => void;\n}\n\nexport function install(interceptorOrClock?: HttpInterceptor | any): HttpProxyInstallResult {\n let interceptor: HttpInterceptor;\n \n if (interceptorOrClock instanceof HttpInterceptor) {\n interceptor = interceptorOrClock;\n } else {\n interceptor = new HttpInterceptor({ clock: interceptorOrClock });\n }\n\n // 1. Install http/https patches\n interceptor.install();\n\n // 2. Install fetch patch\n const origFetch = globalThis.fetch;\n if (origFetch) {\n globalThis.fetch = createFetchPatch(interceptor, origFetch);\n }\n\n // 3. Try to patch undici if available in the module graph\n // Undici is what powers Node's native fetch. A lot of libraries (like Prisma, Axios in some cases)\n // might use undici directly.\n let undiciUninstall: (() => void) | undefined;\n try {\n const customRequire = createRequire(process.cwd() + '/'); // Attempt to require from workspace root\n \n let undici: any;\n try {\n undici = customRequire('undici');\n } catch {\n undici = _require('undici');\n }\n\n if (undici) {\n const origUndiciFetch = undici.fetch;\n const origUndiciRequest = undici.request;\n\n undici.fetch = createFetchPatch(interceptor, origUndiciFetch);\n // undici.request is a bit different API, but if any libraries use it, we can wrap it.\n // For this fix, wrapping undici.fetch handles most cases. \n // We can also wrap undici.request if necessary, but returning a dispatcher response is complex.\n // Let's at least wrap fetch.\n \n undiciUninstall = () => {\n undici.fetch = origUndiciFetch;\n undici.request = origUndiciRequest;\n };\n }\n } catch (err) {\n // ignore if undici is not found\n }\n\n function uninstall(): void {\n interceptor.uninstall();\n globalThis.fetch = origFetch;\n if (undiciUninstall) {\n undiciUninstall();\n }\n }\n\n return { interceptor, uninstall };\n}\n"],"mappings":"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","names":["body","import_node_module","_require"]}
package/dist/index.js CHANGED
@@ -2,6 +2,17 @@
2
2
  import { EventEmitter } from "events";
3
3
  import * as http from "http";
4
4
  import { URL } from "url";
5
+
6
+ // src/req-hash.ts
7
+ function reqHash(s) {
8
+ let h = 5381;
9
+ for (let i = 0; i < s.length; i++) {
10
+ h = (h << 5) + h + s.charCodeAt(i) >>> 0;
11
+ }
12
+ return h;
13
+ }
14
+
15
+ // src/HttpInterceptor.ts
5
16
  import { createRequire } from "module";
6
17
  var FakeIncomingMessage = class extends EventEmitter {
7
18
  constructor(status, headers, _body) {
@@ -109,7 +120,6 @@ var MockRoute = class {
109
120
  var _require = createRequire(import.meta.url);
110
121
  var httpCjs = _require("node:http");
111
122
  var httpsCjs = _require("node:https");
112
- var _httpReqCounter = 0;
113
123
  var HttpInterceptor = class {
114
124
  _routes = [];
115
125
  _allCalls = [];
@@ -249,7 +259,7 @@ var HttpInterceptor = class {
249
259
  if (this._scheduler) {
250
260
  const now = this._clock?.now() ?? 0;
251
261
  const when = now + latency;
252
- const opId = `http-${++_httpReqCounter}`;
262
+ const opId = `http-${now}-${reqHash(method + "|" + url + "|" + (fakeReq.body ?? ""))}`;
253
263
  this._scheduler.enqueueCompletion({
254
264
  id: opId,
255
265
  when,
@@ -312,7 +322,6 @@ function normalizeArgs(defaultProto, args) {
312
322
 
313
323
  // src/fetch-patch.ts
314
324
  import { Buffer as Buffer2 } from "buffer";
315
- var _fetchReqCounter = 0;
316
325
  function createFetchPatch(interceptor, originalFetch) {
317
326
  return async function fakeFetch(input, init) {
318
327
  let url;
@@ -402,7 +411,7 @@ function createFetchPatch(interceptor, originalFetch) {
402
411
  if (anyInterceptor._scheduler) {
403
412
  const now = anyInterceptor._clock?.now() ?? 0;
404
413
  const when = now + latency;
405
- const opId = `fetch-${++_fetchReqCounter}`;
414
+ const opId = `fetch-${now}-${reqHash(method + "|" + url + "|" + (body ?? ""))}`;
406
415
  anyInterceptor._scheduler.enqueueCompletion({
407
416
  id: opId,
408
417
  when,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/HttpInterceptor.ts","../src/fetch-patch.ts","../src/install.ts"],"sourcesContent":["import { EventEmitter } from 'node:events';\nimport * as http from 'node:http';\nimport * as https from 'node:https';\nimport { URL } from 'node:url';\n\n// Types\n\n/** Minimal virtual-clock interface (duck-typed). */\nexport interface IClock {\n now(): number;\n setTimeout(cb: (...args: unknown[]) => void, delay: number): number;\n}\n\n/** Minimal scheduler interface (duck-typed). */\nexport interface IScheduler {\n enqueueCompletion(op: { id: string; when: number; run: () => Promise<void> | void }): void;\n requestRunTick?(virtualTime: number): void;\n}\n\nexport interface MockResponseConfig {\n status?: number;\n headers?: Record<string, string>;\n body?: unknown;\n /** Virtual-clock latency in ms (requires an IClock instance). */\n latency?: number;\n /** Dynamic handler — overrides static body/status when provided. */\n handler?: (call: RecordedCall) => { status: number; body?: unknown; headers?: Record<string, string> };\n /**\n * URL match mode.\n * - `'exact'` (default): `url === urlPattern` — only matches the exact URL.\n * - `'prefix'`: `url.startsWith(urlPattern)` — matches any URL that begins with the pattern.\n * - `'regex'`: `new RegExp(urlPattern).test(url)` — matches via regular expression.\n */\n match?: 'exact' | 'prefix' | 'regex';\n}\n\nexport interface FailConfig {\n /** Succeed the first N calls, then error. */\n after?: number;\n error: string;\n}\n\nexport interface RecordedCall {\n method: string;\n url: string;\n headers: Record<string, string>;\n body: string;\n timestamp: number;\n}\n\n// Fakes\n\nclass FakeIncomingMessage extends EventEmitter {\n statusCode: number;\n statusMessage: string;\n headers: Record<string, string>;\n\n constructor(status: number, headers: Record<string, string>, private readonly _body: string) {\n super();\n this.statusCode = status;\n this.statusMessage = http.STATUS_CODES[status] ?? '';\n this.headers = headers;\n }\n\n _flush(): void {\n queueMicrotask(() => {\n this.emit('data', Buffer.from(this._body));\n this.emit('end');\n });\n }\n}\n\nclass FakeClientRequest extends EventEmitter {\n private _chunks: Buffer[] = [];\n headersSent = false;\n\n write(chunk: string | Buffer): boolean {\n this._chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n return true;\n }\n\n end(chunk?: string | Buffer): this {\n if (chunk) this.write(chunk);\n this.emit('_end');\n return this;\n }\n\n get body(): string {\n return Buffer.concat(this._chunks).toString();\n }\n\n // no-ops for compat\n setHeader(): this { return this; }\n getHeader(): undefined { return undefined; }\n removeHeader(): void {}\n flushHeaders(): void {}\n setTimeout(): this { return this; }\n setNoDelay(): void {}\n setSocketKeepAlive(): void {}\n abort(): void {}\n destroy(): this { return this; }\n}\n\n// Route\n\nclass MockRoute {\n readonly calls: RecordedCall[] = [];\n private _callCount = 0;\n private readonly _matchMode: 'exact' | 'prefix' | 'regex';\n private readonly _regex?: RegExp;\n\n constructor(\n readonly urlPattern: string,\n readonly config: MockResponseConfig,\n readonly failConfig?: FailConfig,\n ) {\n this._matchMode = config.match ?? 'exact';\n if (this._matchMode === 'regex') {\n this._regex = new RegExp(urlPattern);\n }\n }\n\n matches(url: string): boolean {\n switch (this._matchMode) {\n case 'exact': return url === this.urlPattern;\n case 'prefix': return url.startsWith(this.urlPattern);\n case 'regex': return this._regex!.test(url);\n }\n }\n\n respond(call: RecordedCall): { error?: string; status: number; headers: Record<string, string>; body: string } {\n this.calls.push(call);\n this._callCount++;\n\n if (this.failConfig) {\n const limit = this.failConfig.after ?? 0;\n if (this._callCount > limit) {\n return { error: this.failConfig.error, status: 0, headers: {}, body: '' };\n }\n }\n\n if (this.config.handler) {\n const r = this.config.handler(call);\n const body = typeof r.body === 'string' ? r.body : JSON.stringify(r.body ?? '');\n return { status: r.status, headers: r.headers ?? { 'content-type': 'application/json' }, body };\n }\n\n const body = typeof this.config.body === 'string'\n ? this.config.body\n : JSON.stringify(this.config.body ?? '');\n return {\n status: this.config.status ?? 200,\n headers: this.config.headers ?? { 'content-type': 'application/json' },\n body,\n };\n }\n}\n\n// Interceptor\n\n// We need to write directly to the module object's internal property.\n// ESM `import * as http` creates a frozen namespace — we can't assign\n// to it. Instead we grab the *CJS* module from require.cache and\n// patch the exports object there, which IS mutable.\n//\n// We use createRequire so this file can stay ESM.\nimport { createRequire } from 'node:module';\nconst _require = createRequire(import.meta.url);\nconst httpCjs = _require('node:http') as typeof http;\nconst httpsCjs = _require('node:https') as typeof https;\n\nlet _httpReqCounter = 0;\n\nexport class HttpInterceptor {\n private readonly _routes: MockRoute[] = [];\n private readonly _allCalls: RecordedCall[] = [];\n private readonly _clock?: IClock;\n private readonly _scheduler?: IScheduler;\n\n private _partitioned = false;\n private _defaultLatency = 0;\n\n private _origHttpRequest?: typeof http.request;\n private _origHttpGet?: typeof http.get;\n private _origHttpsRequest?: typeof https.request;\n private _origHttpsGet?: typeof https.get;\n\n constructor(opts?: { clock?: IClock; scheduler?: IScheduler }) {\n this._clock = opts?.clock;\n this._scheduler = opts?.scheduler;\n }\n\n // mock registration\n\n mock(urlPrefix: string, config: MockResponseConfig): this {\n this._routes.push(new MockRoute(urlPrefix, config));\n return this;\n }\n\n fail(urlPrefix: string, config: FailConfig): this {\n this._routes.push(new MockRoute(urlPrefix, { status: 0 }, config));\n return this;\n }\n\n calls(method?: string, urlPrefix?: string): RecordedCall[] {\n return this._allCalls.filter((c) => {\n if (method && c.method !== method.toUpperCase()) return false;\n if (urlPrefix && !c.url.startsWith(urlPrefix)) return false;\n return true;\n });\n }\n\n /**\n * Block all HTTP requests for `duration` virtual ms.\n * Requests made during the partition receive a connection-refused error.\n */\n blockAll(duration: number): void {\n this._partitioned = true;\n if (this._clock) {\n this._clock.setTimeout(() => { this._partitioned = false; }, duration);\n } else {\n console.warn(\n 'SimNode: HttpInterceptor.blockAll() called without a virtual clock. ' +\n 'Falling back to real setTimeout — partition duration will be wall-clock, not deterministic.',\n );\n setTimeout(() => { this._partitioned = false; }, duration);\n }\n }\n\n /**\n * Add a global extra latency (ms) to all HTTP responses.\n * Used by FaultInjector.slowDatabase() for HTTP-based DBs.\n */\n setDefaultLatency(ms: number): void {\n this._defaultLatency = ms;\n }\n\n // patching\n\n install(): void {\n this._origHttpRequest = httpCjs.request;\n this._origHttpGet = httpCjs.get;\n this._origHttpsRequest = httpsCjs.request;\n this._origHttpsGet = httpsCjs.get;\n\n const self = this;\n\n const origHttpReq = this._origHttpRequest!;\n const origHttpsReq = this._origHttpsRequest!;\n\n const makeRequest = (proto: string, origReq: typeof http.request) =>\n function fakeRequest(this: unknown, ...args: unknown[]): FakeClientRequest | http.ClientRequest {\n const { url, method, headers, callback } = normalizeArgs(proto, args);\n // Passthrough: unmatched localhost requests (supertest, local test\n // servers) ALWAYS go through the real http stack — even during a\n // network partition. blockAll() only affects external / mocked URLs.\n if (_isLocalUrl(url) && !self._routes.find(r => r.matches(url))) {\n return origReq.apply(null, args as any);\n }\n return self._intercept(url, method, headers, callback);\n } as unknown as typeof http.request;\n\n const makeGet = (reqFn: typeof http.request) =>\n function fakeGet(this: unknown, ...args: unknown[]): FakeClientRequest | http.ClientRequest {\n const req = (reqFn as any)(...args);\n req.end();\n return req;\n } as unknown as typeof http.get;\n\n httpCjs.request = makeRequest('http:', origHttpReq);\n httpCjs.get = makeGet(httpCjs.request);\n httpsCjs.request = makeRequest('https:', origHttpsReq);\n httpsCjs.get = makeGet(httpsCjs.request);\n }\n\n uninstall(): void {\n if (this._origHttpRequest) httpCjs.request = this._origHttpRequest;\n if (this._origHttpGet) httpCjs.get = this._origHttpGet;\n if (this._origHttpsRequest) httpsCjs.request = this._origHttpsRequest;\n if (this._origHttpsGet) httpsCjs.get = this._origHttpsGet;\n this._partitioned = false;\n this._defaultLatency = 0;\n }\n\n reset(): void {\n this._routes.length = 0;\n this._allCalls.length = 0;\n this._partitioned = false;\n this._defaultLatency = 0;\n }\n\n // internal\n\n private _intercept(\n url: string,\n method: string,\n headers: Record<string, string>,\n callback?: (res: FakeIncomingMessage) => void,\n ): FakeClientRequest {\n const route = this._routes.find((r) => r.matches(url));\n const fakeReq = new FakeClientRequest();\n if (callback) fakeReq.on('response', callback);\n\n fakeReq.on('_end', () => {\n const call: RecordedCall = {\n method,\n url,\n headers,\n body: fakeReq.body,\n timestamp: this._clock?.now() ?? Date.now(),\n };\n this._allCalls.push(call);\n\n // Network partition: reject with error\n if (this._partitioned) {\n fakeReq.emit('error', Object.assign(new Error(`Network partition: ${method} ${url} rejected`), { code: 'ECONNREFUSED' }));\n return;\n }\n\n if (!route) {\n fakeReq.emit('error', new Error(`No mock matched: ${method} ${url}`));\n return;\n }\n\n let result: { error?: string; status: number; headers: Record<string, string>; body: string };\n try {\n result = route.respond(call);\n } catch (err: unknown) {\n fakeReq.emit('error', err instanceof Error ? err : new Error(String(err)));\n return;\n }\n\n const deliver = (): void => {\n if (result.error) {\n fakeReq.emit('error', new Error(result.error));\n return;\n }\n const fakeRes = new FakeIncomingMessage(result.status, result.headers, result.body);\n fakeReq.emit('response', fakeRes);\n fakeRes._flush();\n };\n\n // Effective latency = route latency + global default (from fault injection)\n const latency = (route.config.latency ?? 0) + this._defaultLatency;\n\n // Spec v3: Always route through scheduler when available — even zero-latency\n // responses — so PRNG ordering applies to all same-tick HTTP completions.\n if (this._scheduler) {\n const now = this._clock?.now() ?? 0;\n const when = now + latency;\n const opId = `http-${++_httpReqCounter}`;\n this._scheduler.enqueueCompletion({\n id: opId,\n when,\n run: () => { deliver(); return Promise.resolve(); },\n });\n if (latency <= 0) {\n this._scheduler.requestRunTick?.(now);\n }\n } else if (this._clock && latency > 0) {\n this._clock.setTimeout(deliver, latency);\n } else {\n throw new Error(\n '[SimNode] HttpInterceptor: a Scheduler is required for deterministic delivery. ' +\n 'Pass { scheduler } when constructing HttpInterceptor.',\n );\n }\n });\n\n return fakeReq;\n }\n}\n\n// Helpers\n\n/** Return true if the URL targets a loopback address (localhost, 127.0.0.1, ::1). */\nfunction _isLocalUrl(url: string): boolean {\n try {\n const h = new URL(url).hostname.toLowerCase();\n return h === 'localhost' || h === '127.0.0.1' || h === '::1' || h === '[::1]';\n } catch {\n return false;\n }\n}\n\nfunction normalizeArgs(\n defaultProto: string,\n args: unknown[],\n): { url: string; method: string; headers: Record<string, string>; callback?: (res: any) => void } {\n let url: string;\n let options: Record<string, any> = {};\n let callback: ((res: any) => void) | undefined;\n\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\n const parsed = new URL(args[0].toString());\n url = parsed.toString();\n if (typeof args[1] === 'function') {\n callback = args[1] as (res: any) => void;\n } else if (typeof args[1] === 'object' && args[1] !== null) {\n options = args[1] as Record<string, any>;\n if (typeof args[2] === 'function') callback = args[2] as (res: any) => void;\n }\n } else {\n options = (args[0] ?? {}) as Record<string, any>;\n if (typeof args[1] === 'function') callback = args[1] as (res: any) => void;\n const proto = (options.protocol as string) ?? defaultProto;\n const host = (options.hostname ?? options.host ?? 'localhost') as string;\n const port = options.port ? `:${options.port as string}` : '';\n const path = (options.path ?? '/') as string;\n url = `${proto}//${host}${port}${path}`;\n }\n\n return {\n url,\n method: ((options.method as string) ?? 'GET').toUpperCase(),\n headers: (options.headers ?? {}) as Record<string, string>,\n callback,\n };\n}\n","import type { HttpInterceptor, IScheduler, RecordedCall } from './HttpInterceptor.js';\nimport { Buffer } from 'node:buffer';\n\nlet _fetchReqCounter = 0;\n\nexport function createFetchPatch(interceptor: HttpInterceptor, originalFetch: typeof globalThis.fetch) {\n return async function fakeFetch(input: string | URL | Request, init?: RequestInit): Promise<Response> {\n // 1. Normalize input to URL string and extract method/headers/body\n let url: string;\n let method = 'GET';\n const headers: Record<string, string> = {};\n let body = '';\n\n if (input instanceof Request) {\n url = input.url;\n method = input.method;\n input.headers.forEach((value, key) => {\n headers[key.toLowerCase()] = value;\n });\n if (input.body) {\n try {\n const ab = await input.arrayBuffer();\n body = Buffer.from(ab).toString('utf-8');\n } catch {\n body = '';\n }\n }\n } else {\n url = typeof input === 'string' ? input : input.toString();\n }\n\n if (init) {\n if (init.method) method = init.method.toUpperCase();\n if (init.headers) {\n if (init.headers instanceof Headers) {\n init.headers.forEach((value, key) => {\n headers[key.toLowerCase()] = value;\n });\n } else if (Array.isArray(init.headers)) {\n for (const [key, value] of init.headers) {\n headers[key.toLowerCase()] = value;\n }\n } else {\n for (const [key, value] of Object.entries(init.headers)) {\n headers[key.toLowerCase()] = value as string;\n }\n }\n }\n if (init.body) {\n if (typeof init.body === 'string') {\n body = init.body;\n } else if (init.body instanceof Buffer) {\n body = init.body.toString('utf-8');\n } else {\n body = String(init.body);\n }\n }\n }\n\n return new Promise((resolve, reject) => {\n const anyInterceptor = interceptor as any;\n const route = anyInterceptor._routes.find((r: any) => r.matches(url));\n\n const call: RecordedCall = {\n method,\n url,\n headers,\n body,\n timestamp: anyInterceptor._clock?.now() ?? Date.now(),\n };\n anyInterceptor._allCalls.push(call);\n\n // Network partition check\n if (anyInterceptor._partitioned) {\n return reject(Object.assign(new TypeError(`fetch failed: Network partition active — ${method} ${url} rejected`), { code: 'ECONNREFUSED' }));\n }\n\n if (!route) {\n return reject(new TypeError(`fetch failed: No mock matched: ${method} ${url}`));\n }\n\n let result: { error?: string; status: number; headers: Record<string, string>; body: string };\n try {\n result = route.respond(call);\n } catch (err: unknown) {\n return reject(err instanceof Error ? err : new TypeError(String(err)));\n }\n\n const deliver = (): void => {\n if (result.error) {\n return reject(new TypeError(result.error));\n }\n\n const responseHeaders = new Headers(result.headers);\n const response = new Response(result.body, {\n status: result.status,\n statusText: 'MOCKED',\n headers: responseHeaders,\n });\n\n resolve(response);\n };\n\n // Effective latency = route latency + global defaultLatency (from fault injection)\n const latency = (route.config.latency ?? 0) + (anyInterceptor._defaultLatency ?? 0);\n\n // Spec v3: Always route through scheduler when available — even zero-latency\n // responses — so PRNG ordering applies to all same-tick completions.\n if (anyInterceptor._scheduler) {\n const now = anyInterceptor._clock?.now() ?? 0;\n const when = now + latency;\n const opId = `fetch-${++_fetchReqCounter}`;\n (anyInterceptor._scheduler as IScheduler).enqueueCompletion({\n id: opId,\n when,\n run: () => { deliver(); return Promise.resolve(); },\n });\n if (latency <= 0) {\n (anyInterceptor._scheduler as IScheduler).requestRunTick?.(now);\n }\n } else if (anyInterceptor._clock && latency > 0) {\n anyInterceptor._clock.setTimeout(deliver, latency);\n } else {\n throw new Error(\n '[SimNode] fetch: a Scheduler is required for deterministic delivery. ' +\n 'Pass { scheduler } when constructing HttpInterceptor.',\n );\n }\n });\n };\n}\n","import { HttpInterceptor } from './HttpInterceptor.js';\nimport { createFetchPatch } from './fetch-patch.js';\nimport { createRequire } from 'node:module';\n\nconst _require = createRequire(import.meta.url);\n\n\nexport interface HttpProxyInstallResult {\n interceptor: HttpInterceptor;\n uninstall: () => void;\n}\n\nexport function install(interceptorOrClock?: HttpInterceptor | any): HttpProxyInstallResult {\n let interceptor: HttpInterceptor;\n \n if (interceptorOrClock instanceof HttpInterceptor) {\n interceptor = interceptorOrClock;\n } else {\n interceptor = new HttpInterceptor({ clock: interceptorOrClock });\n }\n\n // 1. Install http/https patches\n interceptor.install();\n\n // 2. Install fetch patch\n const origFetch = globalThis.fetch;\n if (origFetch) {\n globalThis.fetch = createFetchPatch(interceptor, origFetch);\n }\n\n // 3. Try to patch undici if available in the module graph\n // Undici is what powers Node's native fetch. A lot of libraries (like Prisma, Axios in some cases)\n // might use undici directly.\n let undiciUninstall: (() => void) | undefined;\n try {\n const customRequire = createRequire(process.cwd() + '/'); // Attempt to require from workspace root\n \n let undici: any;\n try {\n undici = customRequire('undici');\n } catch {\n undici = _require('undici');\n }\n\n if (undici) {\n const origUndiciFetch = undici.fetch;\n const origUndiciRequest = undici.request;\n\n undici.fetch = createFetchPatch(interceptor, origUndiciFetch);\n // undici.request is a bit different API, but if any libraries use it, we can wrap it.\n // For this fix, wrapping undici.fetch handles most cases. \n // We can also wrap undici.request if necessary, but returning a dispatcher response is complex.\n // Let's at least wrap fetch.\n \n undiciUninstall = () => {\n undici.fetch = origUndiciFetch;\n undici.request = origUndiciRequest;\n };\n }\n } catch (err) {\n // ignore if undici is not found\n }\n\n function uninstall(): void {\n interceptor.uninstall();\n globalThis.fetch = origFetch;\n if (undiciUninstall) {\n undiciUninstall();\n }\n }\n\n return { interceptor, uninstall };\n}\n"],"mappings":";AAAA,SAAS,oBAAoB;AAC7B,YAAY,UAAU;AAEtB,SAAS,WAAW;AAmKpB,SAAS,qBAAqB;AAlH9B,IAAM,sBAAN,cAAkC,aAAa;AAAA,EAK7C,YAAY,QAAgB,SAAkD,OAAe;AAC3F,UAAM;AADsE;AAE5E,SAAK,aAAa;AAClB,SAAK,gBAAqB,kBAAa,MAAM,KAAK;AAClD,SAAK,UAAU;AAAA,EACjB;AAAA,EATA;AAAA,EACA;AAAA,EACA;AAAA,EASA,SAAe;AACb,mBAAe,MAAM;AACnB,WAAK,KAAK,QAAQ,OAAO,KAAK,KAAK,KAAK,CAAC;AACzC,WAAK,KAAK,KAAK;AAAA,IACjB,CAAC;AAAA,EACH;AACF;AAEA,IAAM,oBAAN,cAAgC,aAAa;AAAA,EACnC,UAAoB,CAAC;AAAA,EAC7B,cAAc;AAAA,EAEd,MAAM,OAAiC;AACrC,SAAK,QAAQ,KAAK,OAAO,SAAS,KAAK,IAAI,QAAQ,OAAO,KAAK,KAAK,CAAC;AACrE,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,OAA+B;AACjC,QAAI,MAAO,MAAK,MAAM,KAAK;AAC3B,SAAK,KAAK,MAAM;AAChB,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,OAAe;AACjB,WAAO,OAAO,OAAO,KAAK,OAAO,EAAE,SAAS;AAAA,EAC9C;AAAA;AAAA,EAGA,YAAkB;AAAE,WAAO;AAAA,EAAM;AAAA,EACjC,YAAuB;AAAE,WAAO;AAAA,EAAW;AAAA,EAC3C,eAAqB;AAAA,EAAC;AAAA,EACtB,eAAqB;AAAA,EAAC;AAAA,EACtB,aAAmB;AAAE,WAAO;AAAA,EAAM;AAAA,EAClC,aAAmB;AAAA,EAAC;AAAA,EACpB,qBAA2B;AAAA,EAAC;AAAA,EAC5B,QAAc;AAAA,EAAC;AAAA,EACf,UAAgB;AAAE,WAAO;AAAA,EAAM;AACjC;AAIA,IAAM,YAAN,MAAgB;AAAA,EAMd,YACW,YACA,QACA,YACT;AAHS;AACA;AACA;AAET,SAAK,aAAa,OAAO,SAAS;AAClC,QAAI,KAAK,eAAe,SAAS;AAC/B,WAAK,SAAS,IAAI,OAAO,UAAU;AAAA,IACrC;AAAA,EACF;AAAA,EAdS,QAAwB,CAAC;AAAA,EAC1B,aAAa;AAAA,EACJ;AAAA,EACA;AAAA,EAajB,QAAQ,KAAsB;AAC5B,YAAQ,KAAK,YAAY;AAAA,MACvB,KAAK;AAAU,eAAO,QAAQ,KAAK;AAAA,MACnC,KAAK;AAAU,eAAO,IAAI,WAAW,KAAK,UAAU;AAAA,MACpD,KAAK;AAAU,eAAO,KAAK,OAAQ,KAAK,GAAG;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,QAAQ,MAAuG;AAC7G,SAAK,MAAM,KAAK,IAAI;AACpB,SAAK;AAEL,QAAI,KAAK,YAAY;AACnB,YAAM,QAAQ,KAAK,WAAW,SAAS;AACvC,UAAI,KAAK,aAAa,OAAO;AAC3B,eAAO,EAAE,OAAO,KAAK,WAAW,OAAO,QAAQ,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG;AAAA,MAC1E;AAAA,IACF;AAEA,QAAI,KAAK,OAAO,SAAS;AACvB,YAAM,IAAI,KAAK,OAAO,QAAQ,IAAI;AAClC,YAAMA,QAAO,OAAO,EAAE,SAAS,WAAW,EAAE,OAAO,KAAK,UAAU,EAAE,QAAQ,EAAE;AAC9E,aAAO,EAAE,QAAQ,EAAE,QAAQ,SAAS,EAAE,WAAW,EAAE,gBAAgB,mBAAmB,GAAG,MAAAA,MAAK;AAAA,IAChG;AAEA,UAAM,OAAO,OAAO,KAAK,OAAO,SAAS,WACrC,KAAK,OAAO,OACZ,KAAK,UAAU,KAAK,OAAO,QAAQ,EAAE;AACzC,WAAO;AAAA,MACL,QAAQ,KAAK,OAAO,UAAU;AAAA,MAC9B,SAAS,KAAK,OAAO,WAAW,EAAE,gBAAgB,mBAAmB;AAAA,MACrE;AAAA,IACF;AAAA,EACF;AACF;AAWA,IAAM,WAAW,cAAc,YAAY,GAAG;AAC9C,IAAM,UAAU,SAAS,WAAW;AACpC,IAAM,WAAW,SAAS,YAAY;AAEtC,IAAI,kBAAkB;AAEf,IAAM,kBAAN,MAAsB;AAAA,EACV,UAAuB,CAAC;AAAA,EACxB,YAA4B,CAAC;AAAA,EAC7B;AAAA,EACA;AAAA,EAET,eAAe;AAAA,EACf,kBAAkB;AAAA,EAElB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,MAAmD;AAC7D,SAAK,SAAS,MAAM;AACpB,SAAK,aAAa,MAAM;AAAA,EAC1B;AAAA;AAAA,EAIA,KAAK,WAAmB,QAAkC;AACxD,SAAK,QAAQ,KAAK,IAAI,UAAU,WAAW,MAAM,CAAC;AAClD,WAAO;AAAA,EACT;AAAA,EAEA,KAAK,WAAmB,QAA0B;AAChD,SAAK,QAAQ,KAAK,IAAI,UAAU,WAAW,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;AACjE,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAiB,WAAoC;AACzD,WAAO,KAAK,UAAU,OAAO,CAAC,MAAM;AAClC,UAAI,UAAU,EAAE,WAAW,OAAO,YAAY,EAAG,QAAO;AACxD,UAAI,aAAa,CAAC,EAAE,IAAI,WAAW,SAAS,EAAG,QAAO;AACtD,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,UAAwB;AAC/B,SAAK,eAAe;AACpB,QAAI,KAAK,QAAQ;AACf,WAAK,OAAO,WAAW,MAAM;AAAE,aAAK,eAAe;AAAA,MAAO,GAAG,QAAQ;AAAA,IACvE,OAAO;AACL,cAAQ;AAAA,QACN;AAAA,MAEF;AACA,iBAAW,MAAM;AAAE,aAAK,eAAe;AAAA,MAAO,GAAG,QAAQ;AAAA,IAC3D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,kBAAkB,IAAkB;AAClC,SAAK,kBAAkB;AAAA,EACzB;AAAA;AAAA,EAIA,UAAgB;AACd,SAAK,mBAAmB,QAAQ;AAChC,SAAK,eAAe,QAAQ;AAC5B,SAAK,oBAAoB,SAAS;AAClC,SAAK,gBAAgB,SAAS;AAE9B,UAAM,OAAO;AAEb,UAAM,cAAe,KAAK;AAC1B,UAAM,eAAe,KAAK;AAE1B,UAAM,cAAc,CAAC,OAAe,YAClC,SAAS,eAA8B,MAAyD;AAC9F,YAAM,EAAE,KAAK,QAAQ,SAAS,SAAS,IAAI,cAAc,OAAO,IAAI;AAIpE,UAAI,YAAY,GAAG,KAAK,CAAC,KAAK,QAAQ,KAAK,OAAK,EAAE,QAAQ,GAAG,CAAC,GAAG;AAC/D,eAAO,QAAQ,MAAM,MAAM,IAAW;AAAA,MACxC;AACA,aAAO,KAAK,WAAW,KAAK,QAAQ,SAAS,QAAQ;AAAA,IACvD;AAEF,UAAM,UAAU,CAAC,UACf,SAAS,WAA0B,MAAyD;AAC1F,YAAM,MAAO,MAAc,GAAG,IAAI;AAClC,UAAI,IAAI;AACR,aAAO;AAAA,IACT;AAEF,YAAQ,UAAU,YAAY,SAAS,WAAW;AAClD,YAAQ,MAAM,QAAQ,QAAQ,OAAO;AACrC,aAAS,UAAU,YAAY,UAAU,YAAY;AACrD,aAAS,MAAM,QAAQ,SAAS,OAAO;AAAA,EACzC;AAAA,EAEA,YAAkB;AAChB,QAAI,KAAK,iBAAkB,SAAQ,UAAU,KAAK;AAClD,QAAI,KAAK,aAAc,SAAQ,MAAM,KAAK;AAC1C,QAAI,KAAK,kBAAmB,UAAS,UAAU,KAAK;AACpD,QAAI,KAAK,cAAe,UAAS,MAAM,KAAK;AAC5C,SAAK,eAAe;AACpB,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEA,QAAc;AACZ,SAAK,QAAQ,SAAS;AACtB,SAAK,UAAU,SAAS;AACxB,SAAK,eAAe;AACpB,SAAK,kBAAkB;AAAA,EACzB;AAAA;AAAA,EAIQ,WACN,KACA,QACA,SACA,UACmB;AACnB,UAAM,QAAQ,KAAK,QAAQ,KAAK,CAAC,MAAM,EAAE,QAAQ,GAAG,CAAC;AACrD,UAAM,UAAU,IAAI,kBAAkB;AACtC,QAAI,SAAU,SAAQ,GAAG,YAAY,QAAQ;AAE7C,YAAQ,GAAG,QAAQ,MAAM;AACvB,YAAM,OAAqB;AAAA,QACzB;AAAA,QACA;AAAA,QACA;AAAA,QACA,MAAM,QAAQ;AAAA,QACd,WAAW,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;AAAA,MAC5C;AACA,WAAK,UAAU,KAAK,IAAI;AAGxB,UAAI,KAAK,cAAc;AACrB,gBAAQ,KAAK,SAAS,OAAO,OAAO,IAAI,MAAM,sBAAsB,MAAM,IAAI,GAAG,WAAW,GAAG,EAAE,MAAM,eAAe,CAAC,CAAC;AACxH;AAAA,MACF;AAEA,UAAI,CAAC,OAAO;AACV,gBAAQ,KAAK,SAAS,IAAI,MAAM,oBAAoB,MAAM,IAAI,GAAG,EAAE,CAAC;AACpE;AAAA,MACF;AAEA,UAAI;AACJ,UAAI;AACF,iBAAS,MAAM,QAAQ,IAAI;AAAA,MAC7B,SAAS,KAAc;AACrB,gBAAQ,KAAK,SAAS,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AACzE;AAAA,MACF;AAEA,YAAM,UAAU,MAAY;AAC1B,YAAI,OAAO,OAAO;AAChB,kBAAQ,KAAK,SAAS,IAAI,MAAM,OAAO,KAAK,CAAC;AAC7C;AAAA,QACF;AACA,cAAM,UAAU,IAAI,oBAAoB,OAAO,QAAQ,OAAO,SAAS,OAAO,IAAI;AAClF,gBAAQ,KAAK,YAAY,OAAO;AAChC,gBAAQ,OAAO;AAAA,MACjB;AAGA,YAAM,WAAW,MAAM,OAAO,WAAW,KAAK,KAAK;AAInD,UAAI,KAAK,YAAY;AACnB,cAAM,MAAM,KAAK,QAAQ,IAAI,KAAK;AAClC,cAAM,OAAO,MAAM;AACnB,cAAM,OAAO,QAAQ,EAAE,eAAe;AACtC,aAAK,WAAW,kBAAkB;AAAA,UAChC,IAAI;AAAA,UACJ;AAAA,UACA,KAAK,MAAM;AAAE,oBAAQ;AAAG,mBAAO,QAAQ,QAAQ;AAAA,UAAG;AAAA,QACpD,CAAC;AACD,YAAI,WAAW,GAAG;AAChB,eAAK,WAAW,iBAAiB,GAAG;AAAA,QACtC;AAAA,MACF,WAAW,KAAK,UAAU,UAAU,GAAG;AACrC,aAAK,OAAO,WAAW,SAAS,OAAO;AAAA,MACzC,OAAO;AACL,cAAM,IAAI;AAAA,UACR;AAAA,QAEF;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AACF;AAKA,SAAS,YAAY,KAAsB;AACzC,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,GAAG,EAAE,SAAS,YAAY;AAC5C,WAAO,MAAM,eAAe,MAAM,eAAe,MAAM,SAAS,MAAM;AAAA,EACxE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,cACP,cACA,MACiG;AACjG,MAAI;AACJ,MAAI,UAA+B,CAAC;AACpC,MAAI;AAEJ,MAAI,OAAO,KAAK,CAAC,MAAM,YAAY,KAAK,CAAC,aAAa,KAAK;AACzD,UAAM,SAAS,IAAI,IAAI,KAAK,CAAC,EAAE,SAAS,CAAC;AACzC,UAAM,OAAO,SAAS;AACtB,QAAI,OAAO,KAAK,CAAC,MAAM,YAAY;AACjC,iBAAW,KAAK,CAAC;AAAA,IACnB,WAAW,OAAO,KAAK,CAAC,MAAM,YAAY,KAAK,CAAC,MAAM,MAAM;AAC1D,gBAAU,KAAK,CAAC;AAChB,UAAI,OAAO,KAAK,CAAC,MAAM,WAAY,YAAW,KAAK,CAAC;AAAA,IACtD;AAAA,EACF,OAAO;AACL,cAAW,KAAK,CAAC,KAAK,CAAC;AACvB,QAAI,OAAO,KAAK,CAAC,MAAM,WAAY,YAAW,KAAK,CAAC;AACpD,UAAM,QAAS,QAAQ,YAAuB;AAC9C,UAAM,OAAQ,QAAQ,YAAY,QAAQ,QAAQ;AAClD,UAAM,OAAO,QAAQ,OAAO,IAAI,QAAQ,IAAc,KAAK;AAC3D,UAAM,OAAQ,QAAQ,QAAQ;AAC9B,UAAM,GAAG,KAAK,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI;AAAA,EACvC;AAEA,SAAO;AAAA,IACL;AAAA,IACA,SAAU,QAAQ,UAAqB,OAAO,YAAY;AAAA,IAC1D,SAAU,QAAQ,WAAW,CAAC;AAAA,IAC9B;AAAA,EACF;AACF;;;ACjaA,SAAS,UAAAC,eAAc;AAEvB,IAAI,mBAAmB;AAEhB,SAAS,iBAAiB,aAA8B,eAAwC;AACrG,SAAO,eAAe,UAAU,OAA+B,MAAuC;AAEpG,QAAI;AACJ,QAAI,SAAS;AACb,UAAM,UAAkC,CAAC;AACzC,QAAI,OAAO;AAEX,QAAI,iBAAiB,SAAS;AAC5B,YAAM,MAAM;AACZ,eAAS,MAAM;AACf,YAAM,QAAQ,QAAQ,CAAC,OAAO,QAAQ;AACpC,gBAAQ,IAAI,YAAY,CAAC,IAAI;AAAA,MAC/B,CAAC;AACD,UAAI,MAAM,MAAM;AACb,YAAI;AACD,gBAAM,KAAK,MAAM,MAAM,YAAY;AACnC,iBAAOA,QAAO,KAAK,EAAE,EAAE,SAAS,OAAO;AAAA,QAC1C,QAAQ;AACL,iBAAO;AAAA,QACV;AAAA,MACH;AAAA,IACF,OAAO;AACL,YAAM,OAAO,UAAU,WAAW,QAAQ,MAAM,SAAS;AAAA,IAC3D;AAEA,QAAI,MAAM;AACR,UAAI,KAAK,OAAQ,UAAS,KAAK,OAAO,YAAY;AAClD,UAAI,KAAK,SAAS;AAChB,YAAI,KAAK,mBAAmB,SAAS;AACnC,eAAK,QAAQ,QAAQ,CAAC,OAAO,QAAQ;AACnC,oBAAQ,IAAI,YAAY,CAAC,IAAI;AAAA,UAC/B,CAAC;AAAA,QACH,WAAW,MAAM,QAAQ,KAAK,OAAO,GAAG;AACtC,qBAAW,CAAC,KAAK,KAAK,KAAK,KAAK,SAAS;AACvC,oBAAQ,IAAI,YAAY,CAAC,IAAI;AAAA,UAC/B;AAAA,QACF,OAAO;AACL,qBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,OAAO,GAAG;AACvD,oBAAQ,IAAI,YAAY,CAAC,IAAI;AAAA,UAC/B;AAAA,QACF;AAAA,MACF;AACA,UAAI,KAAK,MAAM;AACZ,YAAI,OAAO,KAAK,SAAS,UAAU;AAChC,iBAAO,KAAK;AAAA,QACf,WAAW,KAAK,gBAAgBA,SAAQ;AACrC,iBAAO,KAAK,KAAK,SAAS,OAAO;AAAA,QACpC,OAAO;AACH,iBAAO,OAAO,KAAK,IAAI;AAAA,QAC3B;AAAA,MACH;AAAA,IACF;AAEA,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACrC,YAAM,iBAAiB;AACvB,YAAM,QAAQ,eAAe,QAAQ,KAAK,CAAC,MAAW,EAAE,QAAQ,GAAG,CAAC;AAEpE,YAAM,OAAqB;AAAA,QACzB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAW,eAAe,QAAQ,IAAI,KAAK,KAAK,IAAI;AAAA,MACtD;AACA,qBAAe,UAAU,KAAK,IAAI;AAGlC,UAAI,eAAe,cAAc;AAC/B,eAAO,OAAO,OAAO,OAAO,IAAI,UAAU,iDAA4C,MAAM,IAAI,GAAG,WAAW,GAAG,EAAE,MAAM,eAAe,CAAC,CAAC;AAAA,MAC5I;AAEA,UAAI,CAAC,OAAO;AACV,eAAO,OAAO,IAAI,UAAU,kCAAkC,MAAM,IAAI,GAAG,EAAE,CAAC;AAAA,MAChF;AAEA,UAAI;AACJ,UAAI;AACF,iBAAS,MAAM,QAAQ,IAAI;AAAA,MAC7B,SAAS,KAAc;AACrB,eAAO,OAAO,eAAe,QAAQ,MAAM,IAAI,UAAU,OAAO,GAAG,CAAC,CAAC;AAAA,MACvE;AAEA,YAAM,UAAU,MAAY;AAC1B,YAAI,OAAO,OAAO;AAChB,iBAAO,OAAO,IAAI,UAAU,OAAO,KAAK,CAAC;AAAA,QAC3C;AAEA,cAAM,kBAAkB,IAAI,QAAQ,OAAO,OAAO;AAClD,cAAM,WAAW,IAAI,SAAS,OAAO,MAAM;AAAA,UACxC,QAAQ,OAAO;AAAA,UACf,YAAY;AAAA,UACZ,SAAS;AAAA,QACZ,CAAC;AAED,gBAAQ,QAAQ;AAAA,MAClB;AAGA,YAAM,WAAW,MAAM,OAAO,WAAW,MAAM,eAAe,mBAAmB;AAIjF,UAAI,eAAe,YAAY;AAC7B,cAAM,MAAM,eAAe,QAAQ,IAAI,KAAK;AAC5C,cAAM,OAAO,MAAM;AACnB,cAAM,OAAO,SAAS,EAAE,gBAAgB;AACxC,QAAC,eAAe,WAA0B,kBAAkB;AAAA,UAC1D,IAAI;AAAA,UACJ;AAAA,UACA,KAAK,MAAM;AAAE,oBAAQ;AAAG,mBAAO,QAAQ,QAAQ;AAAA,UAAG;AAAA,QACpD,CAAC;AACD,YAAI,WAAW,GAAG;AAChB,UAAC,eAAe,WAA0B,iBAAiB,GAAG;AAAA,QAChE;AAAA,MACF,WAAW,eAAe,UAAU,UAAU,GAAG;AAC/C,uBAAe,OAAO,WAAW,SAAS,OAAO;AAAA,MACnD,OAAO;AACL,cAAM,IAAI;AAAA,UACR;AAAA,QAEF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACJ;AACF;;;AChIA,SAAS,iBAAAC,sBAAqB;AAE9B,IAAMC,YAAWD,eAAc,YAAY,GAAG;AAQvC,SAAS,QAAQ,oBAAoE;AAC1F,MAAI;AAEJ,MAAI,8BAA8B,iBAAiB;AACjD,kBAAc;AAAA,EAChB,OAAO;AACL,kBAAc,IAAI,gBAAgB,EAAE,OAAO,mBAAmB,CAAC;AAAA,EACjE;AAGA,cAAY,QAAQ;AAGpB,QAAM,YAAY,WAAW;AAC7B,MAAI,WAAW;AACb,eAAW,QAAQ,iBAAiB,aAAa,SAAS;AAAA,EAC5D;AAKA,MAAI;AACJ,MAAI;AACF,UAAM,gBAAgBA,eAAc,QAAQ,IAAI,IAAI,GAAG;AAEvD,QAAI;AACJ,QAAI;AACF,eAAS,cAAc,QAAQ;AAAA,IACjC,QAAQ;AACL,eAASC,UAAS,QAAQ;AAAA,IAC7B;AAEA,QAAI,QAAQ;AACT,YAAM,kBAAkB,OAAO;AAC/B,YAAM,oBAAoB,OAAO;AAEjC,aAAO,QAAQ,iBAAiB,aAAa,eAAe;AAM5D,wBAAkB,MAAM;AACrB,eAAO,QAAQ;AACf,eAAO,UAAU;AAAA,MACpB;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AAAA,EAEd;AAEA,WAAS,YAAkB;AACzB,gBAAY,UAAU;AACtB,eAAW,QAAQ;AACnB,QAAI,iBAAiB;AAClB,sBAAgB;AAAA,IACnB;AAAA,EACF;AAEA,SAAO,EAAE,aAAa,UAAU;AAClC;","names":["body","Buffer","createRequire","_require"]}
1
+ {"version":3,"sources":["../src/HttpInterceptor.ts","../src/req-hash.ts","../src/fetch-patch.ts","../src/install.ts"],"sourcesContent":["import { EventEmitter } from 'node:events';\nimport * as http from 'node:http';\nimport * as https from 'node:https';\nimport { URL } from 'node:url';\nimport { reqHash } from './req-hash.js';\n\n// Types\n\n/** Minimal virtual-clock interface (duck-typed). */\nexport interface IClock {\n now(): number;\n setTimeout(cb: (...args: unknown[]) => void, delay: number): number;\n}\n\n/** Minimal scheduler interface (duck-typed). */\nexport interface IScheduler {\n enqueueCompletion(op: { id: string; when: number; run: () => Promise<void> | void }): void;\n requestRunTick?(virtualTime: number): void;\n}\n\nexport interface MockResponseConfig {\n status?: number;\n headers?: Record<string, string>;\n body?: unknown;\n /** Virtual-clock latency in ms (requires an IClock instance). */\n latency?: number;\n /** Dynamic handler — overrides static body/status when provided. */\n handler?: (call: RecordedCall) => { status: number; body?: unknown; headers?: Record<string, string> };\n /**\n * URL match mode.\n * - `'exact'` (default): `url === urlPattern` — only matches the exact URL.\n * - `'prefix'`: `url.startsWith(urlPattern)` — matches any URL that begins with the pattern.\n * - `'regex'`: `new RegExp(urlPattern).test(url)` — matches via regular expression.\n */\n match?: 'exact' | 'prefix' | 'regex';\n}\n\nexport interface FailConfig {\n /** Succeed the first N calls, then error. */\n after?: number;\n error: string;\n}\n\nexport interface RecordedCall {\n method: string;\n url: string;\n headers: Record<string, string>;\n body: string;\n timestamp: number;\n}\n\n// Fakes\n\nclass FakeIncomingMessage extends EventEmitter {\n statusCode: number;\n statusMessage: string;\n headers: Record<string, string>;\n\n constructor(status: number, headers: Record<string, string>, private readonly _body: string) {\n super();\n this.statusCode = status;\n this.statusMessage = http.STATUS_CODES[status] ?? '';\n this.headers = headers;\n }\n\n _flush(): void {\n queueMicrotask(() => {\n this.emit('data', Buffer.from(this._body));\n this.emit('end');\n });\n }\n}\n\nclass FakeClientRequest extends EventEmitter {\n private _chunks: Buffer[] = [];\n headersSent = false;\n\n write(chunk: string | Buffer): boolean {\n this._chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n return true;\n }\n\n end(chunk?: string | Buffer): this {\n if (chunk) this.write(chunk);\n this.emit('_end');\n return this;\n }\n\n get body(): string {\n return Buffer.concat(this._chunks).toString();\n }\n\n // no-ops for compat\n setHeader(): this { return this; }\n getHeader(): undefined { return undefined; }\n removeHeader(): void {}\n flushHeaders(): void {}\n setTimeout(): this { return this; }\n setNoDelay(): void {}\n setSocketKeepAlive(): void {}\n abort(): void {}\n destroy(): this { return this; }\n}\n\n// Route\n\nclass MockRoute {\n readonly calls: RecordedCall[] = [];\n private _callCount = 0;\n private readonly _matchMode: 'exact' | 'prefix' | 'regex';\n private readonly _regex?: RegExp;\n\n constructor(\n readonly urlPattern: string,\n readonly config: MockResponseConfig,\n readonly failConfig?: FailConfig,\n ) {\n this._matchMode = config.match ?? 'exact';\n if (this._matchMode === 'regex') {\n this._regex = new RegExp(urlPattern);\n }\n }\n\n matches(url: string): boolean {\n switch (this._matchMode) {\n case 'exact': return url === this.urlPattern;\n case 'prefix': return url.startsWith(this.urlPattern);\n case 'regex': return this._regex!.test(url);\n }\n }\n\n respond(call: RecordedCall): { error?: string; status: number; headers: Record<string, string>; body: string } {\n this.calls.push(call);\n this._callCount++;\n\n if (this.failConfig) {\n const limit = this.failConfig.after ?? 0;\n if (this._callCount > limit) {\n return { error: this.failConfig.error, status: 0, headers: {}, body: '' };\n }\n }\n\n if (this.config.handler) {\n const r = this.config.handler(call);\n const body = typeof r.body === 'string' ? r.body : JSON.stringify(r.body ?? '');\n return { status: r.status, headers: r.headers ?? { 'content-type': 'application/json' }, body };\n }\n\n const body = typeof this.config.body === 'string'\n ? this.config.body\n : JSON.stringify(this.config.body ?? '');\n return {\n status: this.config.status ?? 200,\n headers: this.config.headers ?? { 'content-type': 'application/json' },\n body,\n };\n }\n}\n\n// Interceptor\n\n// We need to write directly to the module object's internal property.\n// ESM `import * as http` creates a frozen namespace — we can't assign\n// to it. Instead we grab the *CJS* module from require.cache and\n// patch the exports object there, which IS mutable.\n//\n// We use createRequire so this file can stay ESM.\nimport { createRequire } from 'node:module';\nconst _require = createRequire(import.meta.url);\nconst httpCjs = _require('node:http') as typeof http;\nconst httpsCjs = _require('node:https') as typeof https;\n\n\nexport class HttpInterceptor {\n private readonly _routes: MockRoute[] = [];\n private readonly _allCalls: RecordedCall[] = [];\n private readonly _clock?: IClock;\n private readonly _scheduler?: IScheduler;\n\n private _partitioned = false;\n private _defaultLatency = 0;\n\n private _origHttpRequest?: typeof http.request;\n private _origHttpGet?: typeof http.get;\n private _origHttpsRequest?: typeof https.request;\n private _origHttpsGet?: typeof https.get;\n\n constructor(opts?: { clock?: IClock; scheduler?: IScheduler }) {\n this._clock = opts?.clock;\n this._scheduler = opts?.scheduler;\n }\n\n // mock registration\n\n mock(urlPrefix: string, config: MockResponseConfig): this {\n this._routes.push(new MockRoute(urlPrefix, config));\n return this;\n }\n\n fail(urlPrefix: string, config: FailConfig): this {\n this._routes.push(new MockRoute(urlPrefix, { status: 0 }, config));\n return this;\n }\n\n calls(method?: string, urlPrefix?: string): RecordedCall[] {\n return this._allCalls.filter((c) => {\n if (method && c.method !== method.toUpperCase()) return false;\n if (urlPrefix && !c.url.startsWith(urlPrefix)) return false;\n return true;\n });\n }\n\n /**\n * Block all HTTP requests for `duration` virtual ms.\n * Requests made during the partition receive a connection-refused error.\n */\n blockAll(duration: number): void {\n this._partitioned = true;\n if (this._clock) {\n this._clock.setTimeout(() => { this._partitioned = false; }, duration);\n } else {\n console.warn(\n 'SimNode: HttpInterceptor.blockAll() called without a virtual clock. ' +\n 'Falling back to real setTimeout — partition duration will be wall-clock, not deterministic.',\n );\n setTimeout(() => { this._partitioned = false; }, duration);\n }\n }\n\n /**\n * Add a global extra latency (ms) to all HTTP responses.\n * Used by FaultInjector.slowDatabase() for HTTP-based DBs.\n */\n setDefaultLatency(ms: number): void {\n this._defaultLatency = ms;\n }\n\n // patching\n\n install(): void {\n this._origHttpRequest = httpCjs.request;\n this._origHttpGet = httpCjs.get;\n this._origHttpsRequest = httpsCjs.request;\n this._origHttpsGet = httpsCjs.get;\n\n const self = this;\n\n const origHttpReq = this._origHttpRequest!;\n const origHttpsReq = this._origHttpsRequest!;\n\n const makeRequest = (proto: string, origReq: typeof http.request) =>\n function fakeRequest(this: unknown, ...args: unknown[]): FakeClientRequest | http.ClientRequest {\n const { url, method, headers, callback } = normalizeArgs(proto, args);\n // Passthrough: unmatched localhost requests (supertest, local test\n // servers) ALWAYS go through the real http stack — even during a\n // network partition. blockAll() only affects external / mocked URLs.\n if (_isLocalUrl(url) && !self._routes.find(r => r.matches(url))) {\n return origReq.apply(null, args as any);\n }\n return self._intercept(url, method, headers, callback);\n } as unknown as typeof http.request;\n\n const makeGet = (reqFn: typeof http.request) =>\n function fakeGet(this: unknown, ...args: unknown[]): FakeClientRequest | http.ClientRequest {\n const req = (reqFn as any)(...args);\n req.end();\n return req;\n } as unknown as typeof http.get;\n\n httpCjs.request = makeRequest('http:', origHttpReq);\n httpCjs.get = makeGet(httpCjs.request);\n httpsCjs.request = makeRequest('https:', origHttpsReq);\n httpsCjs.get = makeGet(httpsCjs.request);\n }\n\n uninstall(): void {\n if (this._origHttpRequest) httpCjs.request = this._origHttpRequest;\n if (this._origHttpGet) httpCjs.get = this._origHttpGet;\n if (this._origHttpsRequest) httpsCjs.request = this._origHttpsRequest;\n if (this._origHttpsGet) httpsCjs.get = this._origHttpsGet;\n this._partitioned = false;\n this._defaultLatency = 0;\n }\n\n reset(): void {\n this._routes.length = 0;\n this._allCalls.length = 0;\n this._partitioned = false;\n this._defaultLatency = 0;\n }\n\n // internal\n\n private _intercept(\n url: string,\n method: string,\n headers: Record<string, string>,\n callback?: (res: FakeIncomingMessage) => void,\n ): FakeClientRequest {\n const route = this._routes.find((r) => r.matches(url));\n const fakeReq = new FakeClientRequest();\n if (callback) fakeReq.on('response', callback);\n\n fakeReq.on('_end', () => {\n const call: RecordedCall = {\n method,\n url,\n headers,\n body: fakeReq.body,\n timestamp: this._clock?.now() ?? Date.now(),\n };\n this._allCalls.push(call);\n\n // Network partition: reject with error\n if (this._partitioned) {\n fakeReq.emit('error', Object.assign(new Error(`Network partition: ${method} ${url} rejected`), { code: 'ECONNREFUSED' }));\n return;\n }\n\n if (!route) {\n fakeReq.emit('error', new Error(`No mock matched: ${method} ${url}`));\n return;\n }\n\n let result: { error?: string; status: number; headers: Record<string, string>; body: string };\n try {\n result = route.respond(call);\n } catch (err: unknown) {\n fakeReq.emit('error', err instanceof Error ? err : new Error(String(err)));\n return;\n }\n\n const deliver = (): void => {\n if (result.error) {\n fakeReq.emit('error', new Error(result.error));\n return;\n }\n const fakeRes = new FakeIncomingMessage(result.status, result.headers, result.body);\n fakeReq.emit('response', fakeRes);\n fakeRes._flush();\n };\n\n // Effective latency = route latency + global default (from fault injection)\n const latency = (route.config.latency ?? 0) + this._defaultLatency;\n\n // Spec v3: Always route through scheduler when available — even zero-latency\n // responses — so PRNG ordering applies to all same-tick HTTP completions.\n if (this._scheduler) {\n const now = this._clock?.now() ?? 0;\n const when = now + latency;\n const opId = `http-${now}-${reqHash(method + '|' + url + '|' + (fakeReq.body ?? ''))}`;\n this._scheduler.enqueueCompletion({\n id: opId,\n when,\n run: () => { deliver(); return Promise.resolve(); },\n });\n if (latency <= 0) {\n this._scheduler.requestRunTick?.(now);\n }\n } else if (this._clock && latency > 0) {\n this._clock.setTimeout(deliver, latency);\n } else {\n throw new Error(\n '[SimNode] HttpInterceptor: a Scheduler is required for deterministic delivery. ' +\n 'Pass { scheduler } when constructing HttpInterceptor.',\n );\n }\n });\n\n return fakeReq;\n }\n}\n\n// Helpers\n\n/** Return true if the URL targets a loopback address (localhost, 127.0.0.1, ::1). */\nfunction _isLocalUrl(url: string): boolean {\n try {\n const h = new URL(url).hostname.toLowerCase();\n return h === 'localhost' || h === '127.0.0.1' || h === '::1' || h === '[::1]';\n } catch {\n return false;\n }\n}\n\nfunction normalizeArgs(\n defaultProto: string,\n args: unknown[],\n): { url: string; method: string; headers: Record<string, string>; callback?: (res: any) => void } {\n let url: string;\n let options: Record<string, any> = {};\n let callback: ((res: any) => void) | undefined;\n\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\n const parsed = new URL(args[0].toString());\n url = parsed.toString();\n if (typeof args[1] === 'function') {\n callback = args[1] as (res: any) => void;\n } else if (typeof args[1] === 'object' && args[1] !== null) {\n options = args[1] as Record<string, any>;\n if (typeof args[2] === 'function') callback = args[2] as (res: any) => void;\n }\n } else {\n options = (args[0] ?? {}) as Record<string, any>;\n if (typeof args[1] === 'function') callback = args[1] as (res: any) => void;\n const proto = (options.protocol as string) ?? defaultProto;\n const host = (options.hostname ?? options.host ?? 'localhost') as string;\n const port = options.port ? `:${options.port as string}` : '';\n const path = (options.path ?? '/') as string;\n url = `${proto}//${host}${port}${path}`;\n }\n\n return {\n url,\n method: ((options.method as string) ?? 'GET').toUpperCase(),\n headers: (options.headers ?? {}) as Record<string, string>,\n callback,\n };\n}\n","/** DJB2 hash of a string — used to make op IDs content-derived. */\nexport function reqHash(s: string): number {\n let h = 5381;\n for (let i = 0; i < s.length; i++) {\n h = ((h << 5) + h + s.charCodeAt(i)) >>> 0;\n }\n return h;\n}\n","import type { HttpInterceptor, IScheduler, RecordedCall } from './HttpInterceptor.js';\nimport { Buffer } from 'node:buffer';\n\nimport { reqHash } from './req-hash.js';\n\nexport function createFetchPatch(interceptor: HttpInterceptor, originalFetch: typeof globalThis.fetch) {\n return async function fakeFetch(input: string | URL | Request, init?: RequestInit): Promise<Response> {\n // 1. Normalize input to URL string and extract method/headers/body\n let url: string;\n let method = 'GET';\n const headers: Record<string, string> = {};\n let body = '';\n\n if (input instanceof Request) {\n url = input.url;\n method = input.method;\n input.headers.forEach((value, key) => {\n headers[key.toLowerCase()] = value;\n });\n if (input.body) {\n try {\n const ab = await input.arrayBuffer();\n body = Buffer.from(ab).toString('utf-8');\n } catch {\n body = '';\n }\n }\n } else {\n url = typeof input === 'string' ? input : input.toString();\n }\n\n if (init) {\n if (init.method) method = init.method.toUpperCase();\n if (init.headers) {\n if (init.headers instanceof Headers) {\n init.headers.forEach((value, key) => {\n headers[key.toLowerCase()] = value;\n });\n } else if (Array.isArray(init.headers)) {\n for (const [key, value] of init.headers) {\n headers[key.toLowerCase()] = value;\n }\n } else {\n for (const [key, value] of Object.entries(init.headers)) {\n headers[key.toLowerCase()] = value as string;\n }\n }\n }\n if (init.body) {\n if (typeof init.body === 'string') {\n body = init.body;\n } else if (init.body instanceof Buffer) {\n body = init.body.toString('utf-8');\n } else {\n body = String(init.body);\n }\n }\n }\n\n return new Promise((resolve, reject) => {\n const anyInterceptor = interceptor as any;\n const route = anyInterceptor._routes.find((r: any) => r.matches(url));\n\n const call: RecordedCall = {\n method,\n url,\n headers,\n body,\n timestamp: anyInterceptor._clock?.now() ?? Date.now(),\n };\n anyInterceptor._allCalls.push(call);\n\n // Network partition check\n if (anyInterceptor._partitioned) {\n return reject(Object.assign(new TypeError(`fetch failed: Network partition active — ${method} ${url} rejected`), { code: 'ECONNREFUSED' }));\n }\n\n if (!route) {\n return reject(new TypeError(`fetch failed: No mock matched: ${method} ${url}`));\n }\n\n let result: { error?: string; status: number; headers: Record<string, string>; body: string };\n try {\n result = route.respond(call);\n } catch (err: unknown) {\n return reject(err instanceof Error ? err : new TypeError(String(err)));\n }\n\n const deliver = (): void => {\n if (result.error) {\n return reject(new TypeError(result.error));\n }\n\n const responseHeaders = new Headers(result.headers);\n const response = new Response(result.body, {\n status: result.status,\n statusText: 'MOCKED',\n headers: responseHeaders,\n });\n\n resolve(response);\n };\n\n // Effective latency = route latency + global defaultLatency (from fault injection)\n const latency = (route.config.latency ?? 0) + (anyInterceptor._defaultLatency ?? 0);\n\n // Spec v3: Always route through scheduler when available — even zero-latency\n // responses — so PRNG ordering applies to all same-tick completions.\n if (anyInterceptor._scheduler) {\n const now = anyInterceptor._clock?.now() ?? 0;\n const when = now + latency;\n const opId = `fetch-${now}-${reqHash(method + '|' + url + '|' + (body ?? ''))}`;\n (anyInterceptor._scheduler as IScheduler).enqueueCompletion({\n id: opId,\n when,\n run: () => { deliver(); return Promise.resolve(); },\n });\n if (latency <= 0) {\n (anyInterceptor._scheduler as IScheduler).requestRunTick?.(now);\n }\n } else if (anyInterceptor._clock && latency > 0) {\n anyInterceptor._clock.setTimeout(deliver, latency);\n } else {\n throw new Error(\n '[SimNode] fetch: a Scheduler is required for deterministic delivery. ' +\n 'Pass { scheduler } when constructing HttpInterceptor.',\n );\n }\n });\n };\n}\n","import { HttpInterceptor } from './HttpInterceptor.js';\nimport { createFetchPatch } from './fetch-patch.js';\nimport { createRequire } from 'node:module';\n\nconst _require = createRequire(import.meta.url);\n\n\nexport interface HttpProxyInstallResult {\n interceptor: HttpInterceptor;\n uninstall: () => void;\n}\n\nexport function install(interceptorOrClock?: HttpInterceptor | any): HttpProxyInstallResult {\n let interceptor: HttpInterceptor;\n \n if (interceptorOrClock instanceof HttpInterceptor) {\n interceptor = interceptorOrClock;\n } else {\n interceptor = new HttpInterceptor({ clock: interceptorOrClock });\n }\n\n // 1. Install http/https patches\n interceptor.install();\n\n // 2. Install fetch patch\n const origFetch = globalThis.fetch;\n if (origFetch) {\n globalThis.fetch = createFetchPatch(interceptor, origFetch);\n }\n\n // 3. Try to patch undici if available in the module graph\n // Undici is what powers Node's native fetch. A lot of libraries (like Prisma, Axios in some cases)\n // might use undici directly.\n let undiciUninstall: (() => void) | undefined;\n try {\n const customRequire = createRequire(process.cwd() + '/'); // Attempt to require from workspace root\n \n let undici: any;\n try {\n undici = customRequire('undici');\n } catch {\n undici = _require('undici');\n }\n\n if (undici) {\n const origUndiciFetch = undici.fetch;\n const origUndiciRequest = undici.request;\n\n undici.fetch = createFetchPatch(interceptor, origUndiciFetch);\n // undici.request is a bit different API, but if any libraries use it, we can wrap it.\n // For this fix, wrapping undici.fetch handles most cases. \n // We can also wrap undici.request if necessary, but returning a dispatcher response is complex.\n // Let's at least wrap fetch.\n \n undiciUninstall = () => {\n undici.fetch = origUndiciFetch;\n undici.request = origUndiciRequest;\n };\n }\n } catch (err) {\n // ignore if undici is not found\n }\n\n function uninstall(): void {\n interceptor.uninstall();\n globalThis.fetch = origFetch;\n if (undiciUninstall) {\n undiciUninstall();\n }\n }\n\n return { interceptor, uninstall };\n}\n"],"mappings":"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","names":["body","Buffer","Buffer","createRequire","_require"]}
@@ -0,0 +1,3 @@
1
+ /** DJB2 hash of a string — used to make op IDs content-derived. */
2
+ export declare function reqHash(s: string): number;
3
+ //# sourceMappingURL=req-hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"req-hash.d.ts","sourceRoot":"","sources":["../src/req-hash.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAMzC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crashlab/http-proxy",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",