Server-side components for hosting Perspective engines and WebSocket communication. These components are available in Node.js environments only and provide the server infrastructure for Perspective applications.
Core server engine for hosting tables and processing queries.
/**
* Perspective server engine
*/
class PerspectiveServer {
constructor(options?: PerspectiveServerOptions);
/** Create server session for client communication */
make_session(send_response: (buffer: Uint8Array) => Promise<void>): Promise<Session>;
}
interface PerspectiveServerOptions {
/** Custom polling configuration */
on_poll_request?: () => void;
}
interface Session {
/** Handle incoming client request */
handle_request(buffer: Uint8Array): Promise<void>;
/** Close the session */
close(): void;
}Usage Examples:
import { PerspectiveServer } from "@finos/perspective";
// Create server instance
const server = new PerspectiveServer();
// Create session for custom transport
const session = await server.make_session(async (responseBuffer) => {
// Send response via custom transport
customTransport.send(responseBuffer);
});
// Handle incoming requests
customTransport.onMessage = async (requestBuffer) => {
await session.handle_request(requestBuffer);
};Complete WebSocket server with static file serving and Perspective protocol support.
/**
* WebSocket server with static file serving
*/
class WebSocketServer {
constructor(options?: WebSocketServerOptions);
/** Close server and cleanup resources */
close(): Promise<void>;
}
interface WebSocketServerOptions {
/** Port number (default: 8080) */
port?: number;
/** Static asset directories to serve */
assets?: string[];
/** Custom PerspectiveServer instance */
server?: PerspectiveServer;
}Usage Examples:
import { WebSocketServer } from "@finos/perspective";
// Basic WebSocket server
const wsServer = new WebSocketServer({
port: 8080,
});
// Server with custom assets and port
const customServer = new WebSocketServer({
port: 3000,
assets: ["./public", "./dist"],
});
// Server with custom Perspective engine
const customPerspectiveServer = new PerspectiveServer();
const wsServer = new WebSocketServer({
port: 8080,
server: customPerspectiveServer,
});
// Cleanup when shutting down
process.on("SIGINT", async () => {
await wsServer.close();
process.exit(0);
});Create and manage server-side sessions for client communication.
/**
* Create server session for custom protocols
* @param send_response - Function to send responses to client
* @returns Promise resolving to Session instance
*/
function make_session(
send_response: (buffer: Uint8Array) => Promise<void>
): Promise<Session>;
/**
* Create client with custom transport
* @param send_request - Function to send requests to server
* @param close - Optional cleanup function
* @returns Client instance
*/
function make_client(
send_request: (buffer: Uint8Array) => Promise<void>,
close?: () => void
): Client;Usage Examples:
import { make_session, make_client } from "@finos/perspective";
// Server side - create session
const session = await make_session(async (response) => {
socket.send(response);
});
socket.on("message", async (request) => {
await session.handle_request(request);
});
// Client side - create client with custom transport
const client = make_client(
async (request) => {
socket.send(request);
},
() => {
socket.close();
}
);
socket.on("message", async (response) => {
await client.handle_response(response);
});HTTP handler for serving static assets with Perspective-specific optimizations.
/**
* Static file handler for HTTP servers
* @param request - HTTP request object
* @param response - HTTP response object
* @param assets - Asset directories to serve from
* @param options - Handler configuration
*/
function cwd_static_file_handler(
request: http.IncomingMessage,
response: http.ServerResponse,
assets?: string[],
options?: StaticHandlerOptions
): Promise<void>;
interface StaticHandlerOptions {
/** Enable debug logging */
debug?: boolean;
}Usage Examples:
import http from "http";
import { cwd_static_file_handler } from "@finos/perspective";
// Create HTTP server with static file serving
const server = http.createServer(async (req, res) => {
await cwd_static_file_handler(req, res, ["./public", "./assets"], {
debug: true,
});
});
server.listen(8080, () => {
console.log("Server running on port 8080");
});Node.js provides a global synchronous server instance for immediate use.
// Default export provides direct table access
const perspective = {
/** Create table on global server instance */
table: (data: TableInitData, options?: TableInitOptions) => Promise<Table>;
/** Connect to remote WebSocket server */
websocket: (url: string) => Promise<Client>;
/** Get hosted table names from global server */
get_hosted_table_names: () => Promise<string[]>;
/** Monitor hosted table changes on global server */
on_hosted_tables_update: (callback: () => void) => Promise<number>;
/** Remove hosted table update callback */
remove_hosted_tables_update: (id: number) => Promise<void>;
/** Register error callback on global server */
on_error: (callback: (error: Error) => void) => Promise<number>;
/** Get system information from global server */
system_info: () => Promise<SystemInfo>;
/** WebSocketServer class for custom servers */
WebSocketServer: typeof WebSocketServer;
};Usage Examples:
import perspective from "@finos/perspective";
// Direct table creation (uses global server)
const table = perspective.table([
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 },
]);
// Monitor global server
const updateId = await perspective.on_hosted_tables_update(() => {
console.log("Table added or removed from global server");
});
// Get server status
const info = await perspective.system_info();
console.log("Server memory usage:", info.server_used);
// Create custom WebSocket server
const wsServer = new perspective.WebSocketServer({
port: 3000,
});Common server deployment patterns and integration examples.
Express.js Integration:
import express from "express";
import { WebSocketServer, cwd_static_file_handler } from "@finos/perspective";
const app = express();
// Serve static files through Express
app.use("*", async (req, res, next) => {
try {
await cwd_static_file_handler(req, res, ["./public"]);
} catch (error) {
next();
}
});
const server = app.listen(8080);
// Add WebSocket support
const wsServer = new WebSocketServer({
port: 8081,
assets: ["./public"],
});Custom Protocol Integration:
import { PerspectiveServer, make_session } from "@finos/perspective";
// Create custom server with specific configuration
const server = new PerspectiveServer({
on_poll_request: () => {
// Custom polling logic
console.log("Poll request received");
},
});
// Handle custom transport protocol
class CustomTransport {
async handleConnection(connection) {
const session = await server.make_session(async (response) => {
connection.send(response);
});
connection.on("message", async (request) => {
await session.handle_request(request);
});
connection.on("close", () => {
session.close();
});
}
}Production Deployment:
import { WebSocketServer, PerspectiveServer } from "@finos/perspective";
import { createProxyMiddleware } from "http-proxy-middleware";
// Production server configuration
const perspectiveServer = new PerspectiveServer();
const wsServer = new WebSocketServer({
port: process.env.PERSPECTIVE_PORT || 8080,
assets: ["./dist", "./public"],
server: perspectiveServer,
});
// Add health check endpoint
import http from "http";
const healthServer = http.createServer(async (req, res) => {
if (req.url === "/health") {
const info = await perspectiveServer.system_info();
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ status: "healthy", ...info }));
} else {
res.writeHead(404);
res.end("Not found");
}
});
healthServer.listen(9090);Server-side error handling and monitoring patterns.
// Global error monitoring
import perspective from "@finos/perspective";
const errorId = await perspective.on_error((error) => {
console.error("Perspective server error:", error);
// Send to monitoring service
monitoring.reportError(error);
});
// WebSocket server error handling
const wsServer = new WebSocketServer({ port: 8080 });
process.on("uncaughtException", async (error) => {
console.error("Uncaught exception:", error);
await wsServer.close();
process.exit(1);
});
process.on("SIGTERM", async () => {
console.log("Received SIGTERM, gracefully shutting down");
await wsServer.close();
process.exit(0);
});