or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

async-operations.mdauthentication.mdcache.mderrors.mdindex.mdlogging.mdtransport.mduser-agent.md
tile.json

transport.mddocs/

Transport Layer

HTTP transport system with retry logic, host failover, request/response caching, and comprehensive error handling. Manages communication between clients and Algolia's API infrastructure.

Capabilities

Create Transporter

Creates a comprehensive HTTP transport layer with retry logic, caching, and host management.

/**
 * Creates an HTTP transporter with retry logic and caching
 * @param options - Configuration for the transporter
 * @returns Transporter instance for making HTTP requests
 */
function createTransporter(options: TransporterOptions): Transporter;

interface TransporterOptions {
  /** Cache for host state management */
  hostsCache: Cache;
  /** Logger for transport events and debugging */
  logger: Logger;
  /** HTTP requester implementation */
  requester: Requester;
  /** Cache for in-flight requests */
  requestsCache: Cache;
  /** Cache for completed responses */
  responsesCache: Cache;
  /** Timeout configuration */
  timeouts: Timeouts;
  /** Available hosts for requests */
  hosts: Host[];
  /** Base headers for all requests */
  baseHeaders: Headers;
  /** Base query parameters for all requests */
  baseQueryParameters: QueryParameters;
  /** User agent for request identification */
  algoliaAgent: AlgoliaAgent;
}

interface Transporter extends TransporterOptions {
  /**
   * Performs an HTTP request with retry logic and caching
   * @param baseRequest - Request configuration
   * @param baseRequestOptions - Optional request overrides
   * @returns Promise resolving to the response
   */
  request: <TResponse>(
    baseRequest: Request,
    baseRequestOptions?: RequestOptions
  ) => Promise<TResponse>;
}

Usage Examples:

import {
  createTransporter,
  createMemoryCache,
  createNullLogger,
  createAuth,
  createAlgoliaAgent
} from "@algolia/client-common";

// Create dependencies
const hostsCache = createMemoryCache();
const requestsCache = createMemoryCache();
const responsesCache = createMemoryCache();
const logger = createNullLogger();
const auth = createAuth("AppID", "APIKey");
const algoliaAgent = createAlgoliaAgent("5.35.0");

// Create transporter
const transporter = createTransporter({
  hosts: [
    { url: "algolia.net", accept: "readWrite", protocol: "https" },
    { url: "algolia.com", accept: "readWrite", protocol: "https" }
  ],
  hostsCache,
  logger,
  requester: myRequesterImplementation, // Must provide requester
  requestsCache,
  responsesCache,
  timeouts: { connect: 2000, read: 5000, write: 30000 },
  baseHeaders: auth.headers(),
  baseQueryParameters: auth.queryParameters(),
  algoliaAgent
});

// Make requests
const response = await transporter.request({
  method: 'GET',
  path: '/1/indexes',
  queryParameters: {},
  headers: {}
});

Create Stateful Host

Creates a host with state tracking for availability and timeout management.

/**
 * Creates a stateful host with availability tracking
 * @param host - Base host configuration
 * @param status - Initial host status (default: 'up')
 * @returns Stateful host with availability methods
 */
function createStatefulHost(
  host: Host,
  status?: StatefulHost['status']
): StatefulHost;

interface StatefulHost extends Host {
  /** Current host status */
  status: 'down' | 'timed out' | 'up';
  /** Timestamp of last status update */
  lastUpdate: number;
  /** Check if host is available for requests */
  isUp: () => boolean;
  /** Check if host is in timeout state */
  isTimedOut: () => boolean;
}

Usage Examples:

import { createStatefulHost } from "@algolia/client-common";

const host = createStatefulHost({
  url: "algolia.net",
  accept: "readWrite",
  protocol: "https"
});

console.log(host.isUp()); // true (initially up)
console.log(host.isTimedOut()); // false

// Host becomes available again after 2 minutes even if marked down
const downHost = createStatefulHost(
  { url: "algolia.com", accept: "read", protocol: "https" },
  "down"
);

// Will return true after 2 minutes regardless of status
setTimeout(() => {
  console.log(downHost.isUp()); // true after expiration delay
}, 2 * 60 * 1000 + 100);

Core Types

Host Configuration:

interface Host {
  /** Host URL (without protocol) */
  url: string;
  /** Host capabilities */
  accept: 'read' | 'readWrite' | 'write';
  /** Protocol to use */
  protocol: 'http' | 'https';
  /** Optional port number */
  port?: number;
}

Request/Response Types:

interface Request {
  /** HTTP method */
  method: Method;
  /** API path */
  path: string;
  /** Query parameters */
  queryParameters: QueryParameters;
  /** Request body data */
  data?: Array<Record<string, any>> | Record<string, any>;
  /** Request headers */
  headers: Headers;
  /** Whether response should be cached */
  cacheable?: boolean;
  /** Whether to use read transporter for POST requests */
  useReadTransporter?: boolean;
}

interface Response {
  /** Response body as string */
  content: string;
  /** Whether request timed out */
  isTimedOut: boolean;
  /** HTTP status code */
  status: number;
}

interface EndRequest extends Pick<Request, 'headers' | 'method'> {
  /** Full URL for the request */
  url: string;
  /** Connection timeout in milliseconds */
  connectTimeout: number;
  /** Response timeout in milliseconds */
  responseTimeout: number;
  /** Serialized request body */
  data?: string;
}

Request Options:

interface RequestOptions extends Pick<Request, 'cacheable'> {
  /** Custom timeout overrides */
  timeouts?: Partial<Timeouts>;
  /** Additional headers for this request */
  headers?: Headers;
  /** Additional query parameters for this request */
  queryParameters?: QueryParameters;
  /** Additional data for this request */
  data?: Array<Record<string, any>> | Record<string, any>;
}

interface Timeouts {
  /** Connection timeout in milliseconds */
  connect: number;
  /** Read timeout in milliseconds */
  read: number;
  /** Write timeout in milliseconds */
  write: number;
}

Requester Interface:

interface Requester {
  /**
   * Sends an HTTP request
   * @param request - Complete request configuration
   * @returns Promise resolving to response
   */
  send: (request: EndRequest) => Promise<Response>;
}

Transport Utilities

URL Serialization:

/**
 * Builds complete URL from host, path, and query parameters
 * @param host - Host configuration
 * @param path - API path
 * @param queryParameters - Query parameters to append
 * @returns Complete URL string
 */
function serializeUrl(host: Host, path: string, queryParameters: QueryParameters): string;

/**
 * Serializes query parameters to URL query string
 * @param parameters - Query parameters object
 * @returns URL-encoded query string
 */
function serializeQueryParameters(parameters: QueryParameters): string;

Data Serialization:

/**
 * Serializes request data to JSON string
 * @param request - Base request
 * @param requestOptions - Request options with additional data
 * @returns JSON string or undefined for GET requests
 */
function serializeData(request: Request, requestOptions: RequestOptions): string | undefined;

/**
 * Merges and normalizes HTTP headers
 * @param baseHeaders - Base headers
 * @param requestHeaders - Request-specific headers  
 * @param requestOptionsHeaders - Options headers
 * @returns Merged headers with normalized keys
 */
function serializeHeaders(
  baseHeaders: Headers,
  requestHeaders: Headers,
  requestOptionsHeaders?: Headers
): Headers;

Response Handling:

/**
 * Deserializes successful response content
 * @param response - HTTP response
 * @returns Parsed response object
 * @throws DeserializationError if JSON parsing fails
 */
function deserializeSuccess<TObject>(response: Response): TObject;

/**
 * Creates appropriate error from failed response
 * @param response - Failed HTTP response
 * @param stackFrame - Request stack trace
 * @returns Error instance (ApiError or DetailedApiError)
 */
function deserializeFailure(response: Response, stackFrame: StackFrame[]): Error;

Response Classification:

/**
 * Checks if response indicates network error
 * @param response - Response to check (excluding content)
 * @returns True if network error occurred
 */
function isNetworkError(response: Omit<Response, 'content'>): boolean;

/**
 * Checks if response should trigger retry logic
 * @param response - Response to check (excluding content)
 * @returns True if request should be retried
 */
function isRetryable(response: Omit<Response, 'content'>): boolean;

/**
 * Checks if response indicates success (2xx status)
 * @param response - Response to check
 * @returns True if response is successful
 */
function isSuccess(response: Pick<Response, 'status'>): boolean;

Utility Functions:

/**
 * Shuffles array elements randomly
 * @param array - Array to shuffle
 * @returns Shuffled array (modifies original)
 */
function shuffle<TData>(array: TData[]): TData[];

Stack Trace Management

Stack Frame Types:

interface StackFrame {
  /** Request that was made */
  request: EndRequest;
  /** Response that was received */
  response: Response;
  /** Host that handled the request */
  host: Host;
  /** Number of retries remaining */
  triesLeft: number;
}

Credential Sanitization:

/**
 * Removes credentials from stack trace for safe logging
 * @param stackTrace - Stack trace with potential credentials
 * @returns Sanitized stack trace
 */
function stackTraceWithoutCredentials(stackTrace: StackFrame[]): StackFrame[];

/**
 * Removes credentials from single stack frame
 * @param stackFrame - Stack frame with potential credentials
 * @returns Sanitized stack frame
 */
function stackFrameWithoutCredentials(stackFrame: StackFrame): StackFrame;

Advanced Usage

Custom Requester Implementation:

import { Requester, EndRequest, Response } from "@algolia/client-common";

class FetchRequester implements Requester {
  async send(request: EndRequest): Promise<Response> {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), request.responseTimeout);

    try {
      const response = await fetch(request.url, {
        method: request.method,
        headers: request.headers,
        body: request.data,
        signal: controller.signal
      });

      clearTimeout(timeoutId);

      return {
        content: await response.text(),
        status: response.status,
        isTimedOut: false
      };
    } catch (error) {
      clearTimeout(timeoutId);
      
      if (error.name === 'AbortError') {
        return {
          content: '',
          status: 0,
          isTimedOut: true
        };
      }
      
      throw error;
    }
  }
}

Host Failover Strategy:

The transporter automatically manages host failover:

  1. Host Selection: Filters hosts by read/write capability
  2. State Management: Prioritizes healthy hosts over timed-out hosts
  3. Retry Logic: Increases timeouts with each retry attempt
  4. State Recovery: Hosts automatically recover after 2-minute expiration

Caching Strategy:

  • Request Deduplication: Multiple identical requests share the same promise
  • Response Caching: Successful responses are cached for future requests
  • Cache Keys: Include request, options, and transporter configuration
  • Selective Caching: Only cacheable requests use the cache system

Performance Considerations

  • Use appropriate cache implementations for your environment
  • Configure reasonable timeouts to balance reliability and performance
  • Consider host ordering for geographic optimization
  • Monitor cache hit rates for optimization opportunities
  • Implement proper requester with connection pooling for production use