UNPKG

@bsv/overlay-express

Version:
420 lines 16.6 kB
import express from 'express'; import { Engine, LookupService, TopicManager, Advertiser } from '@bsv/overlay'; import { ChainTracker, Broadcaster, OverlayBroadcastFacilitator, WalletInterface } from '@bsv/sdk'; import Knex from 'knex'; import { MongoClient, Db } from 'mongodb'; import { type UIConfig } from './makeUserInterface.js'; import { BanService } from './BanService.js'; /** * Knex database migration. */ interface Migration { name?: string; up: (knex: Knex.Knex) => Promise<void>; down?: (knex: Knex.Knex) => Promise<void>; } /** * Configuration options that map to Engine constructor parameters. */ export interface EngineConfig { chainTracker?: ChainTracker | 'scripts only'; shipTrackers?: string[]; slapTrackers?: string[]; broadcaster?: Broadcaster; advertiser?: Advertiser; syncConfiguration?: Record<string, string[] | 'SHIP' | false>; logTime?: boolean; logPrefix?: string; throwOnBroadcastFailure?: boolean; overlayBroadcastFacilitator?: OverlayBroadcastFacilitator; suppressDefaultSyncAdvertisements?: boolean; topicAnchorHeaderResolver?: TopicAnchorHeaderResolver; enableBASMSync?: boolean; unprovenEvictionBlocks?: number; reorgStreamUrl?: string; reorgScanDepth?: number; unprovenMaintenanceIntervalMs?: number; } export type HealthStatus = 'ok' | 'degraded' | 'error'; export interface HealthCheckResult { name: string; scope: 'live' | 'ready'; status: HealthStatus; critical: boolean; message?: string; details?: Record<string, any>; durationMs: number; } export type HealthCheckHandler = () => Promise<Omit<HealthCheckResult, 'name' | 'scope' | 'critical' | 'durationMs'> | void> | Omit<HealthCheckResult, 'name' | 'scope' | 'critical' | 'durationMs'> | void; export interface HealthCheckDefinition { name: string; scope?: 'live' | 'ready'; critical?: boolean; handler: HealthCheckHandler; } export interface HealthConfig { includeDetails: boolean; timeoutMs: number; contextProvider?: () => Promise<Record<string, any> | undefined> | Record<string, any> | undefined; } export interface HealthReport { status: HealthStatus; live: boolean; ready: boolean; service: { name: string; advertisableFQDN: string; port: number; network: 'main' | 'test'; startedAt?: string; uptimeMs: number; topicManagerCount: number; lookupServiceCount: number; }; checks: HealthCheckResult[]; context?: Record<string, any>; } export type TopicAnchorHeaderResolver = (blockHeight: number) => Promise<{ blockHeight: number; blockHash: string; merkleRoot?: string; } | undefined>; /** * OverlayExpress class provides an Express-based server for hosting Overlay Services. * It allows configuration of various components like databases, topic managers, and lookup services. * It encapsulates an Express application and provides methods to start the server. */ export default class OverlayExpress { name: string; privateKey: string; advertisableFQDN: string; app: express.Application; port: number; logger: typeof console; knex?: Knex.Knex; migrationsToRun: Migration[]; mongoDb?: Db; mongoClient?: MongoClient; network: 'main' | 'test'; chainTracker: ChainTracker | 'scripts only'; engine?: Engine; managers: Record<string, TopicManager>; services: Record<string, LookupService>; enableGASPSync: boolean; enableBASMSync: boolean; unprovenEvictionBlocks: number; basmBlockPollIntervalMs: number; private basmBlockPollTimer?; unprovenMaintenanceIntervalMs: number; private unprovenMaintenanceTimer?; reorgStreamUrl?: string; reorgScanDepth: number; private reorgAdapter?; topicAnchorHeaderResolver?: TopicAnchorHeaderResolver; arcApiKey: string | undefined; arcCallbackToken: string | undefined; arcadeUrl: string | undefined; arcadeApiKey: string | undefined; arcadeDeploymentId: string | undefined; arcadeChaintracksApiPrefix: string; private arcadeProvider?; verboseRequestLogging: boolean; webUIConfig: UIConfig; engineConfig: EngineConfig; private readonly adminToken; janitorConfig: { requestTimeoutMs: number; hostDownRevokeScore: number; autoBanOnRemoval: boolean; }; banService?: BanService; adminIdentityKey?: string; serverWallet?: WalletInterface; private startTime?; healthConfig: HealthConfig; healthChecks: HealthCheckDefinition[]; isListening: boolean; /** * Constructs an instance of OverlayExpress. * @param name - The name of the service * @param privateKey - Private key used for signing advertisements * @param advertisableFQDN - The fully qualified domain name where this service is available. Does not include "https://". * @param adminToken - Optional. An administrative Bearer token used to protect admin routes. * If not provided, a random token will be generated at runtime. */ constructor(name: string, privateKey: string, advertisableFQDN: string, adminToken?: string); /** * Returns the current admin token in case you need to programmatically retrieve or display it. */ getAdminToken(): string; /** * Configures the port on which the server will listen. * @param port - The port number */ configurePort(port: number): void; /** * Configures the web user interface * @param config - Web UI configuration options */ configureWebUI(config: UIConfig): void; /** * Configures the janitor service parameters * @param config - Janitor configuration options * - requestTimeoutMs: Timeout for health check requests (default: 10000ms) * - hostDownRevokeScore: Number of consecutive failures before deleting output (default: 3) * - autoBanOnRemoval: Whether to auto-ban domains when removed by janitor (default: true) */ configureJanitor(config: Partial<typeof this.janitorConfig>): void; /** * Configures health-report behavior. */ configureHealth(config: Partial<HealthConfig>): void; /** * Registers an application-specific health check. */ registerHealthCheck(definition: HealthCheckDefinition): void; /** * Configures the admin identity key for wallet-based admin detection. * When set, the frontend can compare the user's wallet identity key against this * to determine whether to show the admin dashboard. * * @param identityKey - The hex-encoded public key of the admin */ configureAdminIdentityKey(identityKey: string): void; /** * Configures the logger to be used by the server. * @param logger - A logger object (e.g., console) */ configureLogger(logger: typeof console): void; /** * Configures the BSV Blockchain network to be used ('main' or 'test'). * By default, it re-initializes chainTracker as a WhatsOnChain for that network. * @param network - The network ('main' or 'test') */ configureNetwork(network: 'main' | 'test'): void; /** * Configures the ChainTracker to be used. * If 'scripts only' is used, it implies no full SPV chain tracking in the Engine. * @param chainTracker - An instance of ChainTracker or 'scripts only' */ configureChainTracker(chainTracker?: ChainTracker | 'scripts only'): void; /** * Configures the ARC API key. * @param apiKey - The ARC API key */ configureArcApiKey(apiKey: string): void; /** * Configures the ARC callback token expected by /arc-ingest. * @param token - The token ARC should present when posting callback notifications. */ configureArcCallbackToken(token: string): void; /** * Configures Arcade for first-choice transaction propagation and proof lookup. */ configureArcade(url: string, config?: { apiKey?: string; deploymentId?: string; chaintracksApiPrefix?: string; }): void; /** * Configures a go-chaintracks compatible service for header validation and * BASM reorg streaming. Arcade exposes this at `/chaintracks/v2`. */ configureChaintracks(url: string, config?: { apiPrefix?: string; reorgStream?: boolean; scanDepth?: number; }): void; /** * Enables or disables GASP synchronization (high-level setting). * This is a broad toggle that can be overridden or customized through syncConfiguration. * @param enable - true to enable, false to disable */ configureEnableGASPSync(enable: boolean): void; /** * Enables or disables BRC-136 BASM synchronization. * BASM is opt-in because it requires direct proofs and block hash resolution. */ configureEnableBASMSync(enable: boolean): void; /** * Configures the block header resolver used to derive BASM block hashes. */ configureTopicAnchorHeaderResolver(resolver: TopicAnchorHeaderResolver): void; /** * Configures the go-chaintracks (Arcade) reorg SSE stream used to reconcile * BASM anchors with blockchain reorganizations in real time. * @param url - The reorg stream URL, e.g. `https://arcade.example/v2/reorg/stream`. * @param scanDepth - Optional revalidation-sweep depth in blocks (default 3). */ configureReorgStream(url: string, scanDepth?: number): void; /** * Configures the opt-in unproven state eviction threshold. */ configureUnprovenEviction(config: { thresholdBlocks?: number; }): void; /** * Configures periodic unproven maintenance. Each run first tries configured * proof providers, then evicts rows that are still unproven past the threshold. */ configureUnprovenMaintenance(config: { intervalMs?: number; thresholdBlocks?: number; }): void; /** * Configures how often the BASM anchor chain is extended with empty anchors to * follow the chain tip. Set to 0 to disable periodic polling. */ configureBASMBlockPollInterval(intervalMs: number): void; /** * Enables or disables verbose request logging. * @param enable - true to enable, false to disable */ configureVerboseRequestLogging(enable: boolean): void; /** * Configure Knex (SQL) database connection. * @param config - Knex configuration object, or a MySQL connection string loaded from configuration. */ configureKnex(config: Knex.Knex.Config | string): Promise<void>; /** * Configures the MongoDB database connection. * Also initializes the BanService for persistent ban tracking. * @param connectionString - MongoDB connection string */ configureMongo(connectionString: string): Promise<void>; /** * Configures a Topic Manager. * @param name - The name of the Topic Manager * @param manager - An instance of TopicManager */ configureTopicManager(name: string, manager: TopicManager): void; /** * Configures a Lookup Service. * @param name - The name of the Lookup Service * @param service - An instance of LookupService */ configureLookupService(name: string, service: LookupService): void; /** * Configures a Lookup Service using Knex (SQL) database. * @param name - The name of the Lookup Service * @param serviceFactory - A factory function that creates a LookupService instance using Knex */ configureLookupServiceWithKnex(name: string, serviceFactory: (knex: Knex.Knex) => { service: LookupService; migrations: Migration[]; }): void; /** * Configures a Lookup Service using MongoDB. * @param name - The name of the Lookup Service * @param serviceFactory - A factory function that creates a LookupService instance using MongoDB */ configureLookupServiceWithMongo(name: string, serviceFactory: (mongoDb: Db) => LookupService): void; /** * Advanced configuration method for setting or overriding any * Engine constructor parameters via an EngineConfig object. * * Example usage: * configureEngineParams({ * logTime: true, * throwOnBroadcastFailure: true, * overlayBroadcastFacilitator: new MyCustomFacilitator() * }) * * These fields will be respected when we finally build/configure the Engine * in the `configureEngine()` method below. */ configureEngineParams(params: EngineConfig): void; /** * Configures the Overlay Engine itself. * By default, auto-configures SHIP and SLAP unless autoConfigureShipSlap = false * Then it merges in any advanced engine config from `this.engineConfig`. * * When a BanService is available (from configureMongo), auto-configured SHIP * and SLAP managers, discovery storage, and lookup services are wrapped so * banned outputs are not admitted or indexed. * * @param autoConfigureShipSlap - Whether to auto-configure SHIP and SLAP services (default: true) */ configureEngine(autoConfigureShipSlap?: boolean): Promise<void>; /** Wrap SHIP/SLAP managers and services with ban-aware filters if BanService is configured. */ private wrapBanAwareServices; /** Build the sync config based on enableGASPSync and engineConfig. */ private buildSyncConfig; /** Build the configured transaction propagation provider chain. */ private buildBroadcaster; private ensureArcadeProvider; private fetchArcadeProof; private fetchConfiguredMerkleProof; /** Build the BASM block header resolver. */ private buildTopicAnchorHeaderResolver; /** Resolve the SLAP trackers from config or network defaults. */ private resolveSlapTrackers; /** Build the WalletAdvertiser (or use user-provided one). */ private buildAdvertiser; /** Initialize the server wallet for BSV mutual authentication. */ private initServerWallet; /** * Ensures that Knex is configured and returns it. * @throws Error if Knex is not configured */ private ensureKnex; /** * Ensures that MongoDB is configured and returns it. * @throws Error if MongoDB is not configured */ private ensureMongo; /** * Ensures that the Overlay Engine is configured and returns it. * @throws Error if the Engine is not configured */ private ensureEngine; /** * Creates a JanitorService instance with current configuration. */ private createJanitor; /** Ban a domain and remove all its SHIP/SLAP records from MongoDB. */ private handleBanDomain; /** Parse outpoint string, ban it, and evict it from all lookup services. */ private handleBanOutpoint; /** Evict an output from a specific service or all services (silent per-service errors). */ private evictFromServices; /** Look up the domain of an outpoint from SHIP or SLAP records. */ private lookupDomainForOutpoint; /** Ban a domain and delete all SHIP/SLAP records for it. */ private banDomainAndRemoveRecords; private runHealthCheck; private collectHealthReport; /** * Renders a request or response body for verbose logging, truncating overly long payloads. */ private formatBodyForLog; /** * Installs middleware that verbosely logs incoming requests and outgoing responses. */ private setupVerboseRequestLogging; /** * Starts the Express server. * Sets up routes and begins listening on the configured port. */ start(): Promise<void>; /** * Runs the post-listen startup work: advertiser init, advertisement sync, * and the optional GASP/BASM background syncs. */ private runStartupSync; /** Attempt a GASP sync at startup when enabled. */ private runGaspStartupSync; /** Attempt a BASM sync at startup when enabled, then begin tip-following. */ private runBasmStartupSync; /** Poll for new blocks to advance anchor chains and detect reorgs. */ private startBASMBlockPolling; /** Real-time reorg reconciliation via the go-chaintracks (Arcade) reorg SSE. */ private startBASMReorgStream; /** Extend every topic's BASM anchor chain to the current chain tip. */ private advanceBASMAnchorChains; /** Revalidate recent BASM anchors against the chain tracker, reconciling any reorg. */ private revalidateBASMAnchors; private startUnprovenMaintenance; } export {}; //# sourceMappingURL=OverlayExpress.d.ts.map