openvibe-sdk/service

Generated at from openvibe-contracts v0.114.0 and openvibe-sdk v0.35.1.

From types/service.d.ts (server only). Declarations are shown verbatim.

type StopHandle

A handle closed after the close steps: a function, or an object with close() (else stop(), end(), quit()).

export type StopHandle = (() => unknown) | { close(): unknown } | { stop(): unknown } | { end(): unknown } | { quit(): unknown };

interface GracefulStopOptions

export interface GracefulStopOptions {
    /** Log prefix, e.g. 'Network'. Default 'service'. */
    name?: string;
    /** The HTTP server to drain; leave it out for a worker without one. */
    server?: Server | null;
    /** Run first, in order (sync or async; a failure is logged and the stop goes on). */
    stop?: Step[];
    /** Run after the HTTP drain, in order. */
    close?: Step[];
    /** How long requests in flight may take before they are cut. Default 4000. */
    drainMs?: number;
    /** The whole stop; past it exit(deadlineExitCode). Default 5000. */
    deadlineMs?: number;
    /** Default 1 (Network, Community). The 5 s family and Media exit 0. */
    deadlineExitCode?: number;
    /** false: no SIGTERM/SIGINT handlers (tests; a caller that wires signals itself). Default true. */
    signals?: boolean;
    /** Default process.exit. Called once. */
    exit?: (code: number) => unknown;
    log?: Logger;
    /** After the stop steps, before the server stops taking connections. */
    beforeDrain?: (signal: string) => unknown;
    /** Closed after the close steps; a rejection makes the exit code 1. */
    handles?: StopHandle | StopHandle[];
}

interface GracefulStop

export interface GracefulStop {
    /** Starts the stop once; later calls return the same promise. Resolves with the exit code passed to exit. */
    stop(signal?: string): Promise<number>;
    /** True from the first stop() (or signal) on: a readiness check can answer 503. */
    stopping(): boolean;
}

function gracefulStop

export declare function gracefulStop(options?: GracefulStopOptions): GracefulStop;

function within

`promise`, but no longer than `ms`; a rejection is swallowed (a best-effort step inside the deadline).

export declare function within<T>(ms: number, promise: Promise<T> | T): Promise<T | void>;

const DRAIN_MS

export declare const DRAIN_MS: 4000;

const DEADLINE_MS

export declare const DEADLINE_MS: 5000;

interface ServiceErrorInstance

export interface ServiceErrorInstance extends Error {
    status: number;
    code: string;
    detail?: string;
    extra: Record<string, unknown> | null;
}

interface ServiceErrorClass

export interface ServiceErrorClass {
    new (status: number, code: string, detail?: string, extra?: Record<string, unknown> | null): ServiceErrorInstance;
    readonly prototype: ServiceErrorInstance;
}

interface ServiceErrorOptions

export interface ServiceErrorOptions {
    /** Log prefix ([name]). Default 'service'. */
    name?: string;
    log?: Pick<Console, 'error'>;
    /** 'spread' (default: Blog/Trade, Reviews/Wiki) or 'details' ({ details: extra } below 500: Tips/VIP). */
    extra?: 'spread' | 'details';
    /** The code of an unexpected error. Default 'internal.error'. */
    internalCode?: string;
    /** The detail of an unexpected error. Default 'Internal error'. */
    internalDetail?: string;
    /** Map openvibe-publishing errors and plain TypeErrors (Blog/Trade asApiError). */
    publishing?: boolean;
    /** The class `publishing` builds. Default ServiceError. */
    ServiceError?: ServiceErrorClass;
    /** The service's own refusals → a ServiceError (or null). */
    map?: (err: unknown) => ServiceErrorInstance | null | undefined;
    /** run(): Cache-Control: private, no-store on the answer. */
    noStore?: boolean;
}

const ServiceError

export declare const ServiceError: ServiceErrorClass;

function createServiceError

export declare function createServiceError(name?: string): ServiceErrorClass;

function asServiceError

export declare function asServiceError(err: unknown, options?: ServiceErrorOptions): ServiceErrorInstance | null;

function sendError

Any error → problem+json. Returns the body sent, or null when the headers were already out.

export declare function sendError(res: Res, req: Req, err: unknown, log?: Pick<Console, 'error'> | ServiceErrorOptions, options?: ServiceErrorOptions): Record<string, unknown> | null;

function run

export declare function run<T>(fn: (req: Req, res: Res) => T | Promise<T>, status?: number | ((out: T) => number), options?: ServiceErrorOptions | Pick<Console, 'error'>): (req: Req, res: Res) => Promise<void>;

function wrap

export declare function wrap(fn: Handler, options?: ServiceErrorOptions): (req: Req, res: Res, next?: Next) => Promise<void>;

interface JsonBodyOptions

export interface JsonBodyOptions {
    /** '512kb' (default), '1mb', or bytes. */
    limit?: string | number;
    /** Use this parser (express.json({ limit })) and map its errors. */
    parser?: (req: Req, res: Res, next: Next) => void;
}

function jsonBody

export declare function jsonBody(options?: JsonBodyOptions): (req: Req, res: Res, next: Next) => void;

function privateNoStore

export declare function privateNoStore<R extends Res>(res: R): R;

interface JsonErrorsOptions

export interface JsonErrorsOptions extends ServiceErrorOptions {
    /** Default ['/api/', '/internal/']. */
    apiPrefix?: string | string[];
    /** false: no 404 handler. */
    notFound?: boolean;
    notFoundText?: string;
    errorText?: string;
}

type JsonErrors

export type JsonErrors = [(req: Req, res: Res) => unknown, (err: unknown, req: Req, res: Res, next: Next) => unknown] & {
    notFound: (req: Req, res: Res) => unknown;
    errorHandler: (err: unknown, req: Req, res: Res, next: Next) => unknown;
};

function jsonErrors

export declare function jsonErrors(options?: JsonErrorsOptions): JsonErrors;

interface TelemetrySample

A platform.telemetry-sample@1 record. The schema allows only these fields; `extra` holds scalars.

export interface TelemetrySample {
    service?: string;
    project?: string;
    subject?: string;
    resource?: string;
    provider?: string;
    node?: string;
    cell?: string;
    region?: string;
    operation?: string;
    at?: string;
    latency_ms?: number;
    queue_delay_ms?: number;
    ttfb_ms?: number;
    throughput_per_second?: number;
    bytes?: number;
    status?: string;
    cache_status?: string;
    cost_estimate?: number;
    route_epoch?: number;
    trace_id?: string;
    extra?: Record<string, string | number | boolean>;
}

function telemetrySample

Build a record in the schema's field order; `at` defaults to now (ISO) and null/undefined are stripped.

export declare function telemetrySample(fields: Partial<TelemetrySample>): TelemetrySample;

function validateTelemetrySample

`{ ok, errors }` against platform.telemetry-sample@1 (openvibe-contracts, required lazily; a missing package is never a claim of validity: `ok: false`, `errors: []`).

export declare function validateTelemetrySample(record: unknown): { ok: boolean; errors: unknown[] };

interface TelemetrySignals

start/stop/lag; the defaults are the SDK's event-loop monitor (started by init, stopped by stop).

export interface TelemetrySignals {
    start(): void;
    stop(): void;
    lag(): number | null;
}

interface HttpTelemetryOptions

export interface HttpTelemetryOptions {
    /** The schema's `service` — the only process identity (there is no `instance` field). */
    service: string;
    /** Receives one batch per flush: `await sink(samples)`. */
    sink: (samples: TelemetrySample[]) => unknown;
    /** The flush interval; also the rolling p95 window. Default 15000. */
    intervalMs?: number;
    now?: () => number;
    log?: Logger;
    maxBuffered?: number;
    /** The route template for a request. Default: Express's `req.route.path` under `req.baseUrl`, else `'unmatched'`
     *  (a raw path is never used as a label). */
    routeLabel?: (req: Req) => string;
    /** Replaces telemetrySkipped entirely. */
    skipped?: (req: Req) => boolean;
    /** Paths never observed. Default: /api/health, /ready, /api/ready, /metrics. */
    skipExact?: Set<string> | string[];
    /** Prefixes never observed (a path segment). Default `['/shared']`; OpenVibe.Network passes
     *  `['/shared', '/api/chrome']`. Pass `[]` to disable. */
    skipPrefixes?: string[];
    /** An extra always-skip predicate. */
    skip?: (req: Req) => boolean;
    /** Distinct route|method|status_class keys kept per flush; further keys fold into the `'other'` route label.
     *  Default 500. */
    maxRouteKeys?: number;
    /** Override the module's signals for this collector (tests; a service with its own monitor). */
    signals?: Partial<TelemetrySignals>;
}

interface RequestObservation

export interface RequestObservation {
    route?: string;
    method?: string;
    httpStatus?: number;
    latencyMs?: number;
}

interface HttpTelemetry

export interface HttpTelemetry {
    /** A number becomes `latency_ms`; any other value becomes `extra[name]` (a scalar dimension). */
    record(name: string, value: unknown, labels?: Record<string, unknown>): TelemetrySample;
    gauge(name: string, value: number, labels?: Record<string, unknown>): TelemetrySample;
    count(name: string, labels?: Record<string, unknown>): TelemetrySample;
    /** Emit the interval's aggregation, then hand the SDK everything buffered. */
    flush(): Promise<void>;
    /** Emit once, clear the timer and flush (idempotent; a gracefulStop stop step). */
    stop(): Promise<void>;
    /** A request began: the in-flight peak is sampled here. */
    requestStarted(): void;
    /** A request ended: free the in-flight slot and fold it by route|method|status_class. */
    requestFinished(info: RequestObservation): void;
    observeRequest(info?: RequestObservation): void;
    /** The live buffer sizes (diagnostics/tests): aggregation keys and sampled latencies held per flush. */
    bufferStats(): { keys: number; latencies: number; maxKeyLatencies: number };
    routeLabel(req: Req): string;
    skipped(req: Req): boolean;
    /** The per-request middleware for this collector. */
    middleware(options?: { routeLabel?: (req: Req) => string; skipped?: (req: Req) => boolean }): (req: Req, res: Res, next: Next) => void;
}

function createHttpTelemetry

export declare function createHttpTelemetry(options: HttpTelemetryOptions): HttpTelemetry;

function createTelemetryMiddleware

The middleware for a collector; telemetry never breaks a request and next() runs exactly once.

export declare function createTelemetryMiddleware(collector: HttpTelemetry, options?: { routeLabel?: (req: Req) => string; skipped?: (req: Req) => boolean }): (req: Req, res: Res, next: Next) => void;

function telemetrySkipped

Whether a request carries no product signal (probe paths, configured prefixes, static assets).

export declare function telemetrySkipped(req: Req, options?: { exact?: Set<string> | string[]; prefixes?: string[]; skip?: (req: Req) => boolean }): boolean;

function defaultRouteLabel

The route label without openvibe-shared/metrics: the matched route template, else `'unmatched'`.

export declare function defaultRouteLabel(req: Req): string;

function registerSignals

Merge signals over the current defaults (a service or test injecting start/stop/lag).

export declare function registerSignals(injected?: Partial<TelemetrySignals>): void;

function startEventLoopMonitor

export declare function startEventLoopMonitor(): void;

function stopEventLoopMonitor

export declare function stopEventLoopMonitor(): void;

function eventLoopMonitorEnabled

Whether the monitor is running; requiring the kit starts nothing.

export declare function eventLoopMonitorEnabled(): boolean;

function eventLoopLagMs

The event-loop lag since the last read, ms (the monitor resets per read); null before a sample.

export declare function eventLoopLagMs(): number | null;

const telemetryMiddleware

The singleton's middleware; a no-op until `telemetry.init()`.

export declare const telemetryMiddleware: (req: Req, res: Res, next: Next) => void;

const telemetry

The process-wide collector: init at boot, stop on shutdown, nothing at require time.

export declare const telemetry: {
    init(options: HttpTelemetryOptions): HttpTelemetry;
    record: HttpTelemetry['record'];
    gauge: HttpTelemetry['gauge'];
    count: HttpTelemetry['count'];
    requestStarted: HttpTelemetry['requestStarted'];
    requestFinished: HttpTelemetry['requestFinished'];
    flush: HttpTelemetry['flush'];
    stop: HttpTelemetry['stop'];
    middleware: (req: Req, res: Res, next: Next) => void;
};

const DEFAULT_INTERVAL_MS

export declare const DEFAULT_INTERVAL_MS: 15000;

const DEFAULT_MAX_ROUTE_KEYS

export declare const DEFAULT_MAX_ROUTE_KEYS: 500;

const LATENCY_SAMPLE_CAP

export declare const LATENCY_SAMPLE_CAP: 10000;

const DEFAULT_SKIP_PREFIXES

export declare const DEFAULT_SKIP_PREFIXES: string[];

const HTTP_METHODS

export declare const HTTP_METHODS: Set<string>;

const createReadiness

openvibe-shared/ready

export declare const createReadiness: Fn;

const skip

export declare const skip: Fn;

const safeReason

export declare const safeReason: Fn;

const createRegistry

openvibe-shared/metrics

export declare const createRegistry: Fn;

const instrument

export declare const instrument: Fn;

const metricsHandler

export declare const metricsHandler: Fn;

const isLoopbackDirect

export declare const isLoopbackDirect: (req: Req) => boolean;

const releaseInfo

export declare const releaseInfo: Fn;

const createRelease

openvibe-shared/release

export declare const createRelease: Fn;

interface ProblemOptions

export interface ProblemOptions {
    title?: string;
    detail?: string;
    type?: string;
    instance?: string;
    ctx?: { requestId?: string; traceId?: string } | null;
    errors?: unknown[];
    extra?: Record<string, unknown>;
}

function problem

openvibe-contracts http.problem

export declare function problem(status: number, code: string, options?: ProblemOptions): Record<string, unknown>;

function sendProblem

openvibe-contracts http.sendProblem

export declare function sendProblem(res: Res, status: number, code: string, options?: ProblemOptions): Record<string, unknown>;