Skip to content

Runtime

Runtime adapters abstract filesystem and network operations for different environments.

The IO adapter handles filesystem operations.

interface IO {
readFile(path: string): Promise<string>;
readBinaryFile(path: string): Promise<Uint8Array>;
resolvePath(base: string, relative: string): string;
}

Creates an IO adapter for Node.js.

import { createNodeIO } from '@t-req/core/runtime';
const io = createNodeIO();
const client = createClient({
io: io,
});

Uses Node.js fs/promises for file operations.

In Bun, the IO adapter is optional. @t-req/core automatically uses Bun’s filesystem APIs:

const client = createClient(); // No io needed in Bun

Create custom adapters for other environments:

const customIO: IO = {
async readFile(path: string): Promise<string> {
// Your implementation
return await myFileSystem.read(path);
},
async readBinaryFile(path: string): Promise<Uint8Array> {
// Your implementation
return await myFileSystem.readBinary(path);
},
resolvePath(base: string, relative: string): string {
// Your path resolution logic
return myPathResolver.resolve(base, relative);
},
};
const client = createClient({ io: customIO });

The Transport adapter handles HTTP execution.

interface Transport {
execute(request: ExecuteRequest): Promise<Response>;
}

Creates a transport using the Fetch API.

import { createFetchTransport } from '@t-req/core/runtime';
// Using global fetch
const transport = createFetchTransport(fetch);
// Using custom fetch
const transport = createFetchTransport(customFetch);

The request object passed to transport:

interface ExecuteRequest {
method: string;
url: string;
headers: Record<string, string>;
body?: string | Uint8Array | FormData;
timeout?: number;
signal?: AbortSignal;
}

Create custom transports for testing or special requirements:

const mockTransport: Transport = {
async execute(request: ExecuteRequest): Promise<Response> {
// Return mock response
return new Response(JSON.stringify({ mock: true }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
},
};
const client = createClient({ transport: mockTransport });

Wrap the default transport for logging:

import { createFetchTransport } from '@t-req/core/runtime';
function createLoggingTransport() {
const inner = createFetchTransport(fetch);
return {
async execute(request: ExecuteRequest): Promise<Response> {
console.log(`${request.method} ${request.url}`);
const start = performance.now();
try {
const response = await inner.execute(request);
const duration = performance.now() - start;
console.log(`${response.status} (${duration.toFixed(0)}ms)`);
return response;
} catch (error) {
console.log(`✗ Error: ${error.message}`);
throw error;
}
},
};
}

@t-req/core provides auto-detection for the transport:

import { createAutoTransport } from '@t-req/core/runtime';
// Automatically uses the appropriate fetch implementation
const transport = createAutoTransport();

Check the current runtime:

const isBun = typeof Bun !== 'undefined';
const isNode = typeof process !== 'undefined' && process.versions?.node;
// Configure based on runtime
const client = createClient({
io: isBun ? undefined : createNodeIO(),
});
import type {
IO,
Transport,
ExecuteRequest,
} from '@t-req/core/runtime';