or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

client-operations.mdconstants.mdcredentials.mdindex.mdinterceptors.mdmetadata.mdserver-operations.mdservice-definitions.md
tile.json

server-operations.mddocs/

Server Operations

Server-side gRPC functionality including service registration, handler functions, server lifecycle management, and support for all call types with interceptors and credential handling.

Capabilities

Server Class

The main server class for hosting gRPC services with support for multiple services, interceptors, and flexible binding options.

/**
 * Main gRPC server class for hosting services
 */
class Server {
  /**
   * Create a new gRPC server
   * @param options - Optional server configuration
   */
  constructor(options?: Partial<ServerOptions>);
  
  /**
   * Register a service implementation with the server
   * @param service - Service definition from proto loading
   * @param implementation - Object containing handler functions
   */
  addService<Implementation extends UntypedServiceImplementation>(
    service: ServiceDefinition,
    implementation: Implementation
  ): void;
  
  /**
   * Bind the server to a port with credentials (async)
   * @param port - Address to bind to (host:port format)
   * @param creds - Server credentials for the binding
   * @param callback - Called when binding completes
   */
  bindAsync(
    port: string,
    creds: ServerCredentials,
    callback: (error: Error | null, port: number) => void
  ): void;
  
  /**
   * Start accepting requests on bound ports
   */
  start(): void;
  
  /**
   * Gracefully shutdown the server, waiting for active calls to complete
   * @param callback - Called when shutdown completes
   */
  tryShutdown(callback: (error?: Error) => void): void;
  
  /**
   * Forcefully shutdown the server, terminating active calls
   */
  forceShutdown(): void;
}

Server Configuration

Configuration options for server instances including interceptors and channel options.

interface ServerOptions extends ChannelOptions {
  /** Array of server interceptors to apply to all calls */
  interceptors?: ServerInterceptor[];
}

Service Implementation

Interface for registering service handlers with the server.

interface UntypedServiceImplementation {
  [methodName: string]: UntypedHandleCall;
}

type UntypedHandleCall = 
  | handleUnaryCall<any, any>
  | handleClientStreamingCall<any, any>
  | handleServerStreamingCall<any, any>
  | handleBidiStreamingCall<any, any>;

Handler Functions

Type-safe handler function signatures for different call types.

Unary Call Handlers

Handle request-response style calls where client sends one message and expects one response.

/**
 * Handler for unary (request-response) calls
 * @param call - The server call object containing request and metadata
 * @param callback - Function to call with response or error
 */
type handleUnaryCall<RequestType, ResponseType> = (
  call: ServerUnaryCall<RequestType, ResponseType>,
  callback: sendUnaryData<ResponseType>
) => void;

/**
 * Callback for sending unary responses
 * @param error - Error if call failed, null for success
 * @param value - Response value for successful calls
 * @param trailer - Optional trailing metadata
 * @param flags - Optional response flags
 */
type sendUnaryData<ResponseType> = (
  error: ServiceError | null,
  value?: ResponseType | null,
  trailer?: Metadata,
  flags?: number
) => void;

Usage Example:

const server = new Server();

server.addService(serviceDefinition, {
  sayHello: (call, callback) => {
    console.log("Received request from:", call.getPeer());
    console.log("Request metadata:", call.metadata.getMap());
    
    const response = {
      message: `Hello ${call.request.name}!`
    };
    
    // Send successful response
    callback(null, response);
    
    // Or send error response
    // callback({
    //   code: status.INVALID_ARGUMENT,
    //   details: "Name cannot be empty"
    // });
  }
});

Client Streaming Call Handlers

Handle calls where client sends multiple messages and expects one response.

/**
 * Handler for client streaming calls
 * @param call - The server readable stream for receiving client messages
 * @param callback - Function to call with final response or error
 */
type handleClientStreamingCall<RequestType, ResponseType> = (
  call: ServerReadableStream<RequestType, ResponseType>,
  callback: sendUnaryData<ResponseType>
) => void;

Usage Example:

server.addService(serviceDefinition, {
  uploadData: (call, callback) => {
    const chunks: string[] = [];
    
    call.on('data', (request) => {
      chunks.push(request.chunk);
      console.log("Received chunk:", request.chunk);
    });
    
    call.on('end', () => {
      const response = {
        totalSize: chunks.join('').length,
        chunkCount: chunks.length
      };
      callback(null, response);
    });
    
    call.on('error', (error) => {
      console.error("Upload failed:", error);
      callback(error);
    });
  }
});

Server Streaming Call Handlers

Handle calls where client sends one message and server responds with multiple messages.

/**
 * Handler for server streaming calls
 * @param call - The server writable stream for sending responses
 */
type handleServerStreamingCall<RequestType, ResponseType> = (
  call: ServerWritableStream<RequestType, ResponseType>
) => void;

Usage Example:

server.addService(serviceDefinition, {
  downloadData: (call) => {
    console.log("Download request:", call.request);
    
    // Send multiple responses
    for (let i = 0; i < 10; i++) {
      call.write({
        chunk: `data-chunk-${i}`,
        progress: (i + 1) / 10
      });
    }
    
    // End the stream
    call.end();
  }
});

Bidirectional Streaming Call Handlers

Handle calls where both client and server can send multiple messages simultaneously.

/**
 * Handler for bidirectional streaming calls
 * @param call - The server duplex stream for sending and receiving messages
 */
type handleBidiStreamingCall<RequestType, ResponseType> = (
  call: ServerDuplexStream<RequestType, ResponseType>
) => void;

Usage Example:

server.addService(serviceDefinition, {
  chat: (call) => {
    console.log("Chat session started with:", call.getPeer());
    
    call.on('data', (request) => {
      console.log("Received message:", request.message);
      
      // Echo the message back
      call.write({
        message: `Echo: ${request.message}`,
        timestamp: new Date().toISOString()
      });
    });
    
    call.on('end', () => {
      console.log("Chat session ended");
      call.end();
    });
    
    call.on('error', (error) => {
      console.error("Chat error:", error);
    });
  }
});

Server Call Types

Server-side representations of different call types with request access and metadata handling.

Server Unary Call

Server-side representation of unary calls with request data and metadata access.

interface ServerUnaryCall<RequestType, ResponseType> {
  /** The client request data */
  request: RequestType;
  /** Request metadata sent by client */
  metadata: Metadata;
  /** Get the peer address of the client */
  getPeer(): string;
  /** Send initial metadata to client */
  sendMetadata(responseMetadata: Metadata): void;
  /** Check if the call has been cancelled */
  isCancelled(): boolean;
}

Server Readable Stream

Server-side client streaming call for receiving multiple messages from client.

interface ServerReadableStream<RequestType, ResponseType> extends Readable {
  /** Request metadata sent by client */
  metadata: Metadata;
  /** Get the peer address of the client */
  getPeer(): string;
  /** Send initial metadata to client */
  sendMetadata(responseMetadata: Metadata): void;
  /** Check if the call has been cancelled */
  isCancelled(): boolean;
}

Server Writable Stream

Server-side server streaming call for sending multiple messages to client.

interface ServerWritableStream<RequestType, ResponseType> extends Writable {
  /** The client request data */
  request: RequestType;
  /** Request metadata sent by client */
  metadata: Metadata;
  /** Get the peer address of the client */
  getPeer(): string;
  /** Send initial metadata to client */
  sendMetadata(responseMetadata: Metadata): void;
  /** Check if the call has been cancelled */
  isCancelled(): boolean;
}

Server Duplex Stream

Server-side bidirectional streaming call for sending and receiving multiple messages.

interface ServerDuplexStream<RequestType, ResponseType> extends Duplex {
  /** Request metadata sent by client */
  metadata: Metadata;
  /** Get the peer address of the client */
  getPeer(): string;
  /** Send initial metadata to client */
  sendMetadata(responseMetadata: Metadata): void;
  /** Check if the call has been cancelled */
  isCancelled(): boolean;
}

Server Error Handling

Servers can send structured error responses with gRPC status codes and metadata.

interface ServerErrorResponse {
  /** gRPC status code */
  code: status;
  /** Detailed error message */
  details: string;
  /** Optional trailing metadata */
  metadata?: Metadata;
}

Error Response Example:

server.addService(serviceDefinition, {
  validateInput: (call, callback) => {
    if (!call.request.data) {
      callback({
        code: status.INVALID_ARGUMENT,
        details: "Data field is required",
        metadata: new Metadata()
      });
      return;
    }
    
    // Process valid input
    callback(null, { result: "success" });
  }
});

Server Lifecycle Management

Complete server lifecycle with binding, starting, and graceful shutdown.

Complete Server Example:

import { Server, ServerCredentials, status } from "@grpc/grpc-js";

const server = new Server();

// Add service implementation
server.addService(serviceDefinition, {
  // Service handlers here
});

// Bind to port
server.bindAsync(
  "0.0.0.0:50051",
  ServerCredentials.createInsecure(),
  (error, port) => {
    if (error) {
      console.error("Failed to bind server:", error);
      return;
    }
    
    console.log(`Server bound to port ${port}`);
    server.start();
    console.log("Server started");
  }
);

// Graceful shutdown
process.on('SIGINT', () => {
  console.log("Shutting down server...");
  server.tryShutdown((error) => {
    if (error) {
      console.error("Error during shutdown:", error);
      server.forceShutdown();
    } else {
      console.log("Server shut down gracefully");
    }
    process.exit(0);
  });
});

Connection Injection

Advanced server functionality for connection management and injection.

interface ConnectionInjector {
  /** Inject a connection into the server */
  injectConnection(connection: any): void;
}