@interfere/test-utils 10.1.0-rc.2 → 10.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/_virtual/_rolldown/runtime.mjs +1 -0
- package/dist/playwright/protection-bypass.d.mts +1 -3
- package/dist/playwright/protection-bypass.mjs +1 -1
- package/dist/vitest/otlp.d.mts +1 -2
- package/dist/vitest/package-contract.d.mts +1 -2
- package/dist/vitest/package-contract.mjs +1 -1
- package/dist/vitest/packed-application.d.mts +1 -3
- package/dist/vitest/packed-application.mjs +1 -1
- package/dist/vitest/server-contract.d.mts +15 -0
- package/dist/vitest/server-contract.mjs +2 -0
- package/dist/vitest/telemetry-receiver.d.mts +2 -3
- package/dist/vitest/telemetry-receiver.mjs +1 -1
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @interfere/test-utils
|
|
2
2
|
|
|
3
|
+
## 10.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 2b931b4: `application()` accepts `{ tarballs }`, a map from package name to a prebuilt tarball, so a consumer can install a listed `@interfere/*` package from a release pack directory instead of packing it from the workspace.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- f584c2f: Preserve every shared JavaScript chunk alias and align its debug ID with the uploaded source map. Retain initiating callsites on XHR and transport failures, server error causes, and structured thrown values. Report partial client and server source-map coverage and verify delivered source evidence during packed SDK qualification.
|
|
12
|
+
|
|
13
|
+
Publish source maps on Next.js 15 after its final Webpack client compilation, preserving customer hooks and waiting for publication and cleanup before prerendering.
|
|
14
|
+
|
|
15
|
+
- ec97a9c: Ship CHANGELOG.md inside the published tarball of every package so release notes travel with the installed version.
|
|
16
|
+
- 7c8441a: `exportedSpans()` and `exceptions()` keep each span's `links` (trace and span ids).
|
|
17
|
+
- Updated dependencies [ec97a9c]
|
|
18
|
+
- @interfere/helpers@9.3.2
|
|
19
|
+
|
|
3
20
|
## 10.1.0-rc.2
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"node:module";var __commonJSMin=(cb,mod)=>()=>(mod||(cb((mod={exports:{}}).exports,mod,mod.exports),cb=null),mod.exports);export{__commonJSMin};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
//#region src/playwright/protection-bypass.d.ts
|
|
2
1
|
export type ProtectionProvider = "cloudflare-access";
|
|
3
2
|
export declare function protectionBypassHeaders(baseURL: string | undefined, provider: ProtectionProvider): {
|
|
4
3
|
"CF-Access-Client-Id": string;
|
|
5
4
|
"CF-Access-Client-Secret": string;
|
|
6
|
-
} | undefined;
|
|
7
|
-
//#endregion
|
|
5
|
+
} | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const LOCAL_HOSTNAMES
|
|
1
|
+
const LOCAL_HOSTNAMES=/* @__PURE__ */ new Set([`localhost`,`127.0.0.1`,`0.0.0.0`,`[::1]`]);function isLocal(baseURL){try{return LOCAL_HOSTNAMES.has(new URL(baseURL).hostname)}catch{return!1}}function cloudflareAccessHeaders(baseURL){let clientId=process.env.CF_ACCESS_CLIENT_ID,clientSecret=process.env.CF_ACCESS_CLIENT_SECRET;if(!(clientId&&clientSecret))throw Error([`Missing CF_ACCESS_CLIENT_ID / CF_ACCESS_CLIENT_SECRET while baseURL points at a remote Cloudflare deployment.`,`baseURL=${baseURL}`,`Set both environment variables to a Cloudflare Access service token authorized for this deployment.`].join(` `));return{"CF-Access-Client-Id":clientId,"CF-Access-Client-Secret":clientSecret}}function protectionBypassHeaders(baseURL,provider){if(baseURL&&!isLocal(baseURL)){if(provider===`cloudflare-access`)return cloudflareAccessHeaders(baseURL);throw Error(`Unsupported protection provider: ${String(provider)}`)}}export{protectionBypassHeaders};
|
package/dist/vitest/otlp.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ReceivedRequest } from "./telemetry-receiver.mjs";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
//#region src/vitest/otlp.d.ts
|
|
4
3
|
declare const attributes: z.ZodArray<z.ZodObject<{
|
|
5
4
|
key: z.ZodString;
|
|
6
5
|
value: z.ZodObject<{
|
|
@@ -111,4 +110,4 @@ export declare function exportedLogRecords(requests: ReceivedRequest[]): {
|
|
|
111
110
|
};
|
|
112
111
|
}[];
|
|
113
112
|
}[];
|
|
114
|
-
|
|
113
|
+
export {};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
//#region src/vitest/package-contract.d.ts
|
|
2
1
|
interface PackageJson {
|
|
3
2
|
dependencies?: Record<string, string>;
|
|
4
3
|
devDependencies?: Record<string, string>;
|
|
@@ -12,4 +11,4 @@ export declare function createPackedPackage(packageJsonUrl: URL): Promise<{
|
|
|
12
11
|
files: string[];
|
|
13
12
|
packageJson: PackageJson;
|
|
14
13
|
}>;
|
|
15
|
-
|
|
14
|
+
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{mapWithConcurrency}from"@interfere/helpers/map-with-concurrency";import{execFile}from"node:child_process";import{mkdir,mkdtemp,readFile,rename,rm,symlink}from"node:fs/promises";import{tmpdir}from"node:os";import path from"node:path";import{fileURLToPath}from"node:url";import{promisify}from"node:util";const execFileAsync=promisify(execFile),PACKED_LINE=/^packed\s+\S+\s+(?<file>.+)$/u,TGZ_LINE=/^(?<filename>\S+\.tgz)$/u;function isDependencyMap(value){return typeof value==`object`&&!!value&&!Array.isArray(value)&&Object.values(value).every(version=>typeof version==`string`)}function isPackageJson(value){return typeof value==`object`&&!!value&&`name`in value&&typeof value.name==`string`&&(!(`private`in value)||typeof value.private==`boolean`)&&(!(`dependencies`in value)||isDependencyMap(value.dependencies))&&(!(`devDependencies`in value)||isDependencyMap(value.devDependencies))&&(!(`peerDependencies`in value)||isDependencyMap(value.peerDependencies))}async function readPackageJson(file){let value=JSON.parse(await readFile(file,`utf8`));if(!isPackageJson(value))throw TypeError(`Package manifest has an invalid name, privacy flag, or dependency map.`);return value}async function createPackedPackage(packageJsonUrl){let packageDir=path.dirname(fileURLToPath(packageJsonUrl)),packageJson=await readPackageJson(packageJsonUrl),tempDir=await mkdtemp(path.join(tmpdir(),`interfere-package-contract-`)),consumerDir=path.join(tempDir,`consumer`),nodeModulesDir=path.join(consumerDir,`node_modules`);try{let installedPackageDir=joinPackageName(nodeModulesDir,packageJson.name);await mkdir(path.dirname(installedPackageDir),{recursive:!0});let{stdout}=await execFileAsync(`bun`,[`pm`,`pack`,`--ignore-scripts`,`--destination`,tempDir],{cwd:packageDir}),{filename,files}=parseBunPackOutput(stdout),tarballPath=path.join(tempDir,path.basename(filename)),extractedDir=path.join(tempDir,`extracted`);await mkdir(extractedDir),await execFileAsync(`tar`,[`-xzf`,tarballPath,`-C`,extractedDir]),await rm(tarballPath),await rename(path.join(extractedDir,`package`),installedPackageDir),await linkRuntimeDependencies({nodeModulesDir,packageDir,packageJson});let packedPackageJson=await readPackageJson(path.join(installedPackageDir,`package.json`));return{cleanup:async()=>rm(tempDir,{force:!0,recursive:!0}),consumerDir,files:files.toSorted(),packageJson:packedPackageJson}}catch(error){throw await rm(tempDir,{force:!0,recursive:!0}),error}}function parseBunPackOutput(stdout){let files=[],filename=``;for(let line of stdout.split(`
|
|
2
|
-
`)){let packMatch=PACKED_LINE.exec(line);if(packMatch?.[1]){files.push(packMatch[1]);continue}let tgzName=TGZ_LINE.exec(line)?.groups?.filename;tgzName&&(filename=tgzName)}if(!filename)throw Error(`bun pm pack did not produce a tarball:\n${stdout}`);return{filename,files}}async function linkRuntimeDependencies({nodeModulesDir,packageDir,packageJson}){let dependencies
|
|
2
|
+
`)){let packMatch=PACKED_LINE.exec(line);if(packMatch?.[1]){files.push(packMatch[1]);continue}let tgzName=TGZ_LINE.exec(line)?.groups?.filename;tgzName&&(filename=tgzName)}if(!filename)throw Error(`bun pm pack did not produce a tarball:\n${stdout}`);return{filename,files}}async function linkRuntimeDependencies({nodeModulesDir,packageDir,packageJson}){let dependencies=/* @__PURE__ */ new Set([...Object.keys(packageJson.dependencies??{}),...Object.keys(packageJson.peerDependencies??{})]),results=await mapWithConcurrency([...dependencies],16,async dependencyName=>{if(dependencyName===packageJson.name)return{ok:!0};try{let source=joinPackageName(path.join(packageDir,`node_modules`),dependencyName),target=joinPackageName(nodeModulesDir,dependencyName);return await mkdir(path.dirname(target),{recursive:!0}),await symlink(source,target,`junction`),{ok:!0}}catch(error){return{ok:!1,error}}});for(let result of results)if(!result.ok)throw result.error}function joinPackageName(nodeModulesDir,packageName){let segments=packageName.split(`/`),validSegments=packageName.startsWith(`@`)?segments.length===2&&segments[0]!==`@`:segments.length===1,target=path.resolve(nodeModulesDir,packageName),relative=path.relative(nodeModulesDir,target);if(!validSegments||packageName.includes(`\\`)||segments.some(segment=>!segment||segment===`.`||segment===`..`)||!relative||relative===`..`||relative.startsWith(`..${path.sep}`)||path.isAbsolute(relative))throw Error(`Package path must remain inside the owned node_modules directory.`);return target}export{createPackedPackage};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
//#region src/vitest/packed-application.d.ts
|
|
2
1
|
export type PackageSelection = string | {
|
|
3
2
|
as: string;
|
|
4
3
|
from: string;
|
|
@@ -28,5 +27,4 @@ export declare function application(packageRoot: string, packages: PackageSelect
|
|
|
28
27
|
close(): Promise<void>;
|
|
29
28
|
}>;
|
|
30
29
|
close(): Promise<void>;
|
|
31
|
-
}>;
|
|
32
|
-
//#endregion
|
|
30
|
+
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createRequire}from"node:module";import{z}from"zod";import{execFile,spawn}from"node:child_process";import{cp,mkdir,mkdtemp,readFile,realpath,rm,symlink,writeFile}from"node:fs/promises";import{tmpdir}from"node:os";import{dirname,join}from"node:path";import{promisify}from"node:util";import{once}from"node:events";const exec=promisify(execFile),metadata=z.object({name:z.string(),dependencies:z.record(z.string(),z.string()).default({})});function childEnvironment(overrides){return Object.fromEntries([[`PATH`,process.env.PATH],[`NODE_ENV`,`production`],[`NEXT_TELEMETRY_DISABLED`,`1`],...Object.entries(overrides)])}async function application(packageRoot,packages,options={}){let root=await mkdtemp(join(tmpdir(),`interfere-packed-application-`)),installed
|
|
1
|
+
import{createRequire}from"node:module";import{z}from"zod";import{execFile,spawn}from"node:child_process";import{cp,mkdir,mkdtemp,readFile,realpath,rm,symlink,writeFile}from"node:fs/promises";import{tmpdir}from"node:os";import{dirname,join}from"node:path";import{promisify}from"node:util";import{once}from"node:events";const exec=promisify(execFile),metadata=z.object({name:z.string(),dependencies:z.record(z.string(),z.string()).default({})});function childEnvironment(overrides){return Object.fromEntries([[`PATH`,process.env.PATH],[`NODE_ENV`,`production`],[`NEXT_TELEMETRY_DISABLED`,`1`],...Object.entries(overrides)])}async function application(packageRoot,packages,options={}){let root=await mkdtemp(join(tmpdir(),`interfere-packed-application-`)),installed=/* @__PURE__ */ new Set,require=createRequire(join(packageRoot,`package.json`));async function install(name,from,as=name){if(installed.has(as))return;installed.add(as);let modules=join(from,`node_modules`,name),source=metadata.parse(JSON.parse(await readFile(join(from,`package.json`),`utf8`))).name===name?from:await realpath(modules),manifest=metadata.parse(JSON.parse(await readFile(join(source,`package.json`),`utf8`))),destination=join(root,`node_modules`,as);if(await mkdir(dirname(destination),{recursive:!0}),!name.startsWith(`@interfere/`)){await symlink(source,destination,`dir`);return}let tarball=join(root,`${name.replaceAll(`/`,`-`)}.tgz`),prebuilt=options.tarballs?.[name];prebuilt===void 0?await exec(`bun`,[`pm`,`pack`,`--ignore-scripts`,`--quiet`,`--filename`,tarball],{cwd:source}):await cp(prebuilt,tarball),await mkdir(destination,{recursive:!0}),await exec(`tar`,[`-xzf`,tarball,`--strip-components=1`,`-C`,destination]),await Promise.all(Object.keys(manifest.dependencies).map(async dependency=>install(dependency,source)))}try{return await writeFile(join(root,`package.json`),JSON.stringify({private:!0,type:`module`})),await Promise.all(packages.map(async selection=>selection instanceof Object?install(selection.from,packageRoot,selection.as):install(selection,packageRoot))),{root,async copyFixture(name){await cp(join(packageRoot,`test/fixtures`,name),root,{recursive:!0})},async run(script,env={},runtime=process.execPath){return exec(runtime,[script],{cwd:root,timeout:3e4,maxBuffer:5242880,env:childEnvironment(env)})},async build(env,cwd=root){return exec(process.execPath,[join(dirname(require.resolve(`vite/package.json`)),`bin/vite.js`),`build`],{cwd,timeout:9e4,maxBuffer:5242880,env:childEnvironment(env)})},async buildNext(env,bundler,cwd=root){let installedNext=join(root,`node_modules`,`next`,`dist`,`bin`,`next`),bin=installed.has(`next`)?installedNext:require.resolve(`next/dist/bin/next`);return exec(process.execPath,[bin,`build`,...bundler?[`--${bundler}`]:[]],{cwd,timeout:15e4,maxBuffer:10485760,env:childEnvironment(env)})},async start(script,env,cwd=root){let child=spawn(process.execPath,[script],{cwd,env:childEnvironment(env),stdio:[`ignore`,`pipe`,`pipe`,`ipc`]}),output=``;child.stdout?.on(`data`,chunk=>{output+=chunk.toString()}),child.stderr?.on(`data`,chunk=>{output+=chunk.toString()});let exited=once(child,`exit`);try{let messages=await once(child,`message`,{signal:AbortSignal.timeout(3e4)});return{url:z.url().parse(messages[0]),output:()=>output,async close(){child.kill(`SIGTERM`),await exited}}}catch(error){throw child.kill(`SIGKILL`),await exited,Error(`Application startup failed: ${output}`,{cause:error})}},async close(){await rm(root,{recursive:!0,force:!0})}}}catch(error){throw await rm(root,{recursive:!0,force:!0}),error}}export{application};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface ServerAdapter {
|
|
2
|
+
register: () => Promise<void>;
|
|
3
|
+
capture: (error: Error) => void;
|
|
4
|
+
recordUrl: (url: string) => void;
|
|
5
|
+
flush: () => Promise<void>;
|
|
6
|
+
dispose: () => Promise<void>;
|
|
7
|
+
installHost: () => {
|
|
8
|
+
run: (capture: () => void) => void;
|
|
9
|
+
captured: () => number;
|
|
10
|
+
ownsTracing: () => boolean;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/** Exercises the same lifecycle, privacy and delivery promises through each server adapter. */
|
|
14
|
+
export declare function serverContract(load: (url: string) => Promise<ServerAdapter>): void;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{l as afterEach,t as beforeEach,z as test}from"../node_modules/.bun/vitest@5.1.0_c373f03cbec31808/node_modules/vitest/dist/chunks/run.CjdgFZiW.mjs";import{g as globalExpect,v as vi}from"../node_modules/.bun/vitest@5.1.0_c373f03cbec31808/node_modules/vitest/dist/chunks/index.CZzC1gGg.mjs";import{exportedSpans}from"./otlp.mjs";import{receiver}from"./telemetry-receiver.mjs";function serverContract(load){let collector,adapter,originalConsole={...console};beforeEach(async()=>{vi.resetModules(),collector=await receiver(),adapter=await load(collector.url)}),afterEach(async()=>{Object.assign(console,originalConsole),await adapter.dispose(),await collector.close(),vi.unstubAllEnvs(),vi.restoreAllMocks()}),test(`concurrent registration has one owner and exports each log once`,async()=>{globalExpect.hasAssertions(),await Promise.all([adapter.register(),adapter.register(),adapter.register()]),console.info(`server-contract-once`),await Promise.resolve(),await adapter.flush();let bodies=collector.requests.filter(request=>request.url.includes(`logs`)).map(request=>request.body).join(`
|
|
2
|
+
`);globalExpect(bodies.match(/server-contract-once/gu)).toHaveLength(1)}),test(`preserves application ownership while delivering captured errors once`,async()=>{let host=adapter.installHost();await Promise.all([adapter.register(),adapter.register()]),host.run(()=>adapter.capture(/* @__PURE__ */ Error(`host-contract-error`))),await adapter.flush(),globalExpect(host.ownsTracing()).toBe(!0),globalExpect(host.captured()).toBe(1),globalExpect(JSON.stringify(exportedSpans(collector.requests)).match(/host-contract-error/gu)?.length).toBeGreaterThan(0),globalExpect(exportedSpans(collector.requests)).toHaveLength(1)}),test(`redacts sensitive URLs before exporting spans and captured exceptions`,async()=>{globalExpect.hasAssertions(),await adapter.register(),adapter.recordUrl(`https://service.example/orders?token=contract-secret&sort=asc`),adapter.capture(/* @__PURE__ */ Error(`failed https://service.example/orders?token=contract-secret&sort=asc`)),await adapter.flush();let spans=exportedSpans(collector.requests),body=JSON.stringify(spans);globalExpect(spans.length).toBeGreaterThanOrEqual(2),globalExpect(body).not.toContain(`contract-secret`),globalExpect(body).toContain(`REDACTED`),globalExpect(body).toContain(`sort=asc`)})}export{serverContract};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
//#region src/vitest/telemetry-receiver.d.ts
|
|
2
1
|
export interface ReceivedRequest {
|
|
3
2
|
method: string;
|
|
4
3
|
url: string;
|
|
@@ -8,6 +7,7 @@ export interface ReceivedRequest {
|
|
|
8
7
|
}
|
|
9
8
|
export declare function receiver(options?: {
|
|
10
9
|
readonly sdkConfig?: Readonly<Record<string, string>>;
|
|
10
|
+
readonly respond?: (request: ReceivedRequest, body: Uint8Array) => Response | undefined;
|
|
11
11
|
}): Promise<{
|
|
12
12
|
url: string;
|
|
13
13
|
requests: ReceivedRequest[];
|
|
@@ -17,5 +17,4 @@ export declare function receiver(options?: {
|
|
|
17
17
|
fail(path: string, status: number, attempts?: number, body?: string): void;
|
|
18
18
|
stall(path: string, ms: number): void;
|
|
19
19
|
close(): Promise<void>;
|
|
20
|
-
}>;
|
|
21
|
-
//#endregion
|
|
20
|
+
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFile}from"node:fs/promises";import{extname,resolve,sep}from"node:path";import{once}from"node:events";import{HttpResponse,getResponse,http}from"msw";import{buffer}from"node:stream/consumers";import{createServer}from"node:http";import{setTimeout}from"node:timers/promises";import{gunzipSync}from"node:zlib";async function receiver(options={}){let requests=[],failures
|
|
1
|
+
import{readFile}from"node:fs/promises";import{extname,resolve,sep}from"node:path";import{once}from"node:events";import{HttpResponse,getResponse,http}from"msw";import{buffer}from"node:stream/consumers";import{createServer}from"node:http";import{setTimeout}from"node:timers/promises";import{gunzipSync}from"node:zlib";async function receiver(options={}){let requests=[],failures=/* @__PURE__ */ new Map,stalls=/* @__PURE__ */ new Map,assets,upstream;async function resolveResponse(request,incoming){let url=new URL(request.url),{headers}=request,responseHeaders=new Headers({"access-control-allow-origin":`*`,"access-control-allow-headers":headers.get(`access-control-request-headers`)??`*`,"access-control-allow-methods":`GET, POST, OPTIONS`});try{if(request.method===`OPTIONS`)return new HttpResponse(null,{status:204,headers:responseHeaders});if(assets&&request.method===`GET`&&!url.pathname.startsWith(`/v3/`)){let file=resolve(assets,`.${url.pathname===`/`?`/index.html`:url.pathname}`);return file.startsWith(`${resolve(assets)}${sep}`)?(responseHeaders.set(`content-type`,extname(file)===`.html`?`text/html`:`text/javascript`),new HttpResponse(await readFile(file),{headers:responseHeaders})):new HttpResponse(null,{status:403,headers:responseHeaders})}let stall=[...stalls].find(([prefix])=>url.pathname.startsWith(prefix))?.[1];stall!==void 0&&(incoming.pause(),await setTimeout(stall),incoming.resume());let raw=await buffer(incoming),decoded=headers.get(`content-encoding`)===`gzip`?gunzipSync(raw):raw,body=decoded.toString(),failure=[...failures].find(([prefix])=>url.pathname.startsWith(prefix))?.[1],entry={method:request.method,url:url.pathname+url.search,headers,body,status:200};if(requests.push(entry),failure&&failure.remaining>0)return--failure.remaining,entry.status=failure.status,responseHeaders.set(`content-type`,`application/json`),new HttpResponse([204,205,304].includes(failure.status)?null:failure.body,{status:failure.status,headers:responseHeaders});if(upstream){let init={method:entry.method,headers};raw.length>0&&(init.body=raw);let result=await upstream(new Request(url,init));entry.status=result.status;for(let[key,value]of result.headers)responseHeaders.set(key,value);return new HttpResponse(result.body===null?null:await result.arrayBuffer(),{status:result.status,headers:responseHeaders})}let custom=options.respond?.(entry,decoded);if(custom){entry.status=custom.status;for(let[key,value]of responseHeaders)custom.headers.set(key,value);return custom}return url.pathname===`/v3/releases/config`?HttpResponse.json({org:{id:`org_acceptance`,slug:`acceptance`},surface:{id:`surface_acceptance`,slug:`web`,sourceProvider:`github`,destinationProvider:`cli`,environmentFiltering:!0,sdkConfig:null}},{headers:responseHeaders}):HttpResponse.json(url.pathname.includes(`config`)?{plugins:{errors:!0,logs:!0,device:!0,pageEvents:!0,rageClick:!0,replay:!0},...options.sdkConfig}:{},{headers:responseHeaders})}catch(error){return new HttpResponse(new TextEncoder().encode(String(error)),{status:500,headers:responseHeaders})}}async function handle(request,response){try{let headers=new Headers;for(let[key,value]of Object.entries(request.headers))value!==void 0&&headers.set(key,Array.isArray(value)?value.join(`, `):value);let init={method:request.method??`GET`,headers},resolved=await getResponse([http.all(`*`,async({request:intercepted})=>resolveResponse(intercepted,request))],new Request(new URL(request.url??`/`,`http://localhost`),init));if(!resolved)throw Error(`Missing telemetry receiver response`);for(let[key,value]of resolved.headers)response.setHeader(key,value);response.writeHead(resolved.status).end(Buffer.from(await resolved.arrayBuffer()))}catch(error){response.destroy(error instanceof Error?error:Error(String(error)))}}let server=createServer((request,response)=>{handle(request,response)});server.listen(0,`127.0.0.1`),await once(server,`listening`);let address=server.address();if(!(address instanceof Object))throw TypeError(`Receiver did not bind a TCP port`);return{url:`http://127.0.0.1:${address.port}`,requests,serve(directory){assets=directory},forward(handler){upstream=handler},reset(){requests.length=0,failures.clear(),stalls.clear()},fail(path,status,attempts=1,body=`{}`){failures.set(path,{status,remaining:attempts,body})},stall(path,ms){stalls.set(path,ms)},async close(){server.closeAllConnections(),await new Promise((resolve,reject)=>{server.close(error=>{error?reject(error):resolve()})})}}}export{receiver};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@interfere/test-utils",
|
|
3
|
-
"version": "10.1.0
|
|
3
|
+
"version": "10.1.0",
|
|
4
4
|
"description": "Shared test utilities used across Interfere packages.",
|
|
5
5
|
"homepage": "https://interfere.com",
|
|
6
6
|
"bugs": "mailto:support@interfere.com",
|
|
@@ -39,16 +39,16 @@
|
|
|
39
39
|
"typecheck": "bun check"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@interfere/helpers": "^9.3.2
|
|
42
|
+
"@interfere/helpers": "^9.3.2",
|
|
43
43
|
"msw": "2.15.0",
|
|
44
44
|
"zod": "4.6.7"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@interfere/typescript-config": "^9.0.3
|
|
47
|
+
"@interfere/typescript-config": "^9.0.3",
|
|
48
48
|
"@interfere/vitest-config": "0.0.0",
|
|
49
49
|
"@types/node": "26.6.6",
|
|
50
|
-
"tsdown": "0.23.
|
|
50
|
+
"tsdown": "0.23.4",
|
|
51
51
|
"typescript": "7.0.2",
|
|
52
|
-
"vitest": "5.0
|
|
52
|
+
"vitest": "5.1.0"
|
|
53
53
|
}
|
|
54
54
|
}
|