/* eslint-disable @typescript-eslint/no-namespace */ import type { DatabaseAdapter } from "@nodecg/database-adapter-types"; import type express from "express"; import type * as ExpressCore from "express-serve-static-core"; import type { NodeCGConfig } from "./nodecg-config-schema"; import type { ClientToServerEvents, ServerToClientEvents, } from "./socket-protocol"; type Person = | { name: string; email?: string; url?: string; } | string; export namespace NodeCG { /** * A collection of types that represent the raw data from the `nodecg` stanza in a bundle's `package.json`. */ export namespace Manifest { /** * An unparsed `assetCategory` from a bundle's `package.json`. */ export interface UnparsedAssetCategory { name: string; title: string; allowedTypes?: string[]; } /** * An unparsed `panel` from a bundle's `package.json`. */ export interface UnparsedPanel { name: string; title: string; file: string; headerColor?: string; fullbleed?: boolean; workspace?: string; dialog?: boolean; dialogButtons?: { name: string; type: "dismiss" | "confirm" }[]; width?: number; } /** * An unparsed `graphic` from a bundle's `package.json`. */ export interface UnparsedGraphic { file: string; width: number; height: number; singleInstance?: boolean; } /** * An unparsed `mount` configuration from a bundle's `package.json`. */ export interface UnparsedMount { directory: string; endpoint: string; } /** * An unparsed `soundCue` from a bundle's `package.json`. */ export interface UnparsedSoundCue { name: string; assignable?: boolean; defaultVolume?: number; defaultFile?: string; } /** * An unparsed record of `bundleDependencies` from a bundle's `package.json`. */ export type UnparsedBundleDependencies = Record; /** * The actual structure of a bundle's `nodecg` stanza from it's `package.json`. */ export interface UnparsedManifest { compatibleRange?: string; transformBareModuleSpecifiers?: boolean; dashboardPanels?: UnparsedPanel[]; graphics?: UnparsedGraphic[]; assetCategories?: UnparsedAssetCategory[]; mount?: UnparsedMount[]; soundCues?: UnparsedSoundCue[]; bundleDependencies?: UnparsedBundleDependencies; } } /** * The rough structure of a bundle's `package.json`. * Only includes types that NodeCG cares about. */ export interface PackageJSON { name: string; version: string; license?: string; description?: string; homepage?: string; author?: Person; contributors?: Person[]; nodecg?: Manifest.UnparsedManifest; } /** * A _parsed_ bundle manifest as used internally by NodeCG. */ export type Manifest = Omit & Manifest.UnparsedManifest & { transformBareModuleSpecifiers: boolean }; /** * A collection of types that comprise a `bundle`. */ export namespace Bundle { export type GitData = | undefined | { branch: string; hash: string; shortHash: string; } | { branch: string; hash: string; shortHash: string; date: string; message: string; }; export type Graphic = { url: string; } & Required; export type Panel = Manifest.UnparsedPanel & { path: string; headerColor: string; bundleName: string; html: string; } & ( | { dialog: false; workspace: string; } | { dialog: true; } ) & ( | { fullbleed: false; width: number; } | { fullbleed: true; } ); export type Mount = Manifest.UnparsedMount; export type SoundCue = Manifest.UnparsedSoundCue; export type AssetCategory = Manifest.UnparsedAssetCategory; export type BundleDependencies = Manifest.UnparsedBundleDependencies; export type UnknownConfig = Record; } export interface NodecgBundleConfig { databaseAdapter?: DatabaseAdapter; } /** * The actual type of a `bundle`. */ export interface Bundle { name: string; version: string; license?: string; description?: string; homepage?: string; author?: Person; contributors?: Person[]; dir: string; git: Bundle.GitData; transformBareModuleSpecifiers: boolean; hasAssignableSoundCues: boolean; hasExtension: boolean; config: Bundle.UnknownConfig; dashboard: { dir: string; panels: Bundle.Panel[]; }; graphics: Bundle.Graphic[]; assetCategories: Bundle.AssetCategory[]; mount: Bundle.Mount[]; soundCues: Bundle.SoundCue[]; compatibleRange?: string; bundleDependencies?: Bundle.BundleDependencies; nodecgBundleConfig: NodecgBundleConfig; } /** * NodeCG's socket protocol. * It is unikely that you will need to use this directly. * Does not include builtin Socket.IO events such as `connect`, `disconnect`, etc. */ export interface SocketProtocol { serverToClient: ServerToClientEvents; clientToServer: ClientToServerEvents; } /** * The full, parsed NodeCG config (i.e `cfg/nodecg.{json,yaml,js}`). * Contains sensitive secrets! * Available to server-side code (extensions) only. */ export type Config = NodeCGConfig; /** * The filtered, minimal, parsed NodeCG config (i.e `cfg/nodecg.{json,yaml,js}`). * Does not contain any sensitive secrets. * Available to client-side code (dashboard, graphics) only. */ export interface FilteredConfig { host: string; port: number; baseURL: string; logging: { console: { enabled: boolean; level: string; timestamps: boolean; replicants: boolean; }; file: { enabled: boolean; level: string; timestamps: boolean; replicants: boolean; }; }; sentry: { enabled: boolean; dsn?: string; }; login: { enabled: boolean; steam?: { enabled: boolean; }; twitch?: { enabled: boolean; clientID?: string; scope?: string; }; local?: { enabled: boolean; }; discord?: { enabled: boolean; clientID?: string; scope?: string; }; }; ssl?: { enabled: boolean; }; } /** * A sound cue `file`, as used in sound cue Replicants. */ export interface CueFile { sum: string; base: string; ext: string; name: string; url: string; default: boolean; } /** * A sound cue definition, as used in sound cue Replicants. */ export interface SoundCue { name: string; volume: number; file?: CueFile; assignable: boolean; channels?: number; bundleName?: TemplateStringsArray; defaultVolume?: number | undefined; defaultFile?: CueFile; } /** * An asset file, as used in assets Replicants. */ export interface AssetFile { sum: string; base: string; ext: string; name: string; namespace: string; category: string; url: string; } /** * A namespace containing various types used in the Replicant system. * It should be unlikely that you need to use these directly. */ export namespace Replicant { export type Options = OptionsNoDefault | OptionsWithDefault; export interface OptionsNoDefault { persistent?: boolean; persistenceInterval?: number; schemaPath?: string; } export interface OptionsWithDefault { persistent?: boolean; persistenceInterval?: number; schemaPath?: string; defaultValue: D; } export type Operation = { path: string; } & ( // Objects and arrays | { method: "overwrite"; args: { newValue: T | undefined } } | { method: "delete"; args: { prop: string | number | symbol } } | { method: "add"; args: { prop: string; newValue: any } } | { method: "update"; args: { prop: string; newValue: any } } // Array mutator methods // This whole thing is gross and needs to be removed in v3 // It is rife with unsupported cases, very easy to make bugs here | { method: "copyWithin"; args: { mutatorArgs: Parameters }; } | { method: "fill"; args: { mutatorArgs: Parameters } } | { method: "pop" } | { method: "push"; args: { mutatorArgs: Parameters } } | { method: "reverse" } | { method: "shift" } | { method: "sort"; args: { mutatorArgs: Parameters } } | { method: "splice"; args: { mutatorArgs: Parameters } } | { method: "unshift"; args: { mutatorArgs: Parameters }; } ); } /** * Express middleware that can be mounted to NodeCG's webserver via `nodecg.mount`. */ export type Middleware = ExpressCore.ApplicationRequestHandler; /** * A description of an instance of a currently-open graphic. * It is unlikely that you will need to use this type directly. */ export interface GraphicsInstance { ipv4: string; timestamp: number; bundleName: string; bundleVersion?: string; bundleGit: Bundle.GitData; pathName: string; singleInstance: boolean; socketId: string; open: boolean; potentiallyOutOfDate: boolean; } /** * A description of a dashboard workspace. * It is unlikely that you will need to use this type directly. */ export interface Workspace { name: string; label: string; route: string; fullbleed?: boolean; } /** * A handled `listenFor` acknowledgement. * Attempting to call/invoke a handled acknowledgement will throw an error. */ export interface HandledAcknowledgement { handled: true; } /** * An unhandled `listenFor` acknowledgement. * It can safely be called/invoked. */ export interface UnhandledAcknowledgement { handled: false; (err?: any, response?: unknown): void; } /** * A `listenFor` acknowledgement, sent from client to server. */ export type Acknowledgement = | HandledAcknowledgement | UnhandledAcknowledgement; /** * A `listenFor` handler function/callback. */ export type ListenHandler = (data: any, ack?: Acknowledgement) => void; /** * A description of NodeCG's logger interface. */ export interface Logger { name: string; trace: (...args: any[]) => void; debug: (...args: any[]) => void; info: (...args: any[]) => void; warn: (...args: any[]) => void; error: (...args: any[]) => void; replicants: (...args: any[]) => void; } /** * The logging levels available to NodeCG. */ export enum LogLevel { Trace = "verbose", Debug = "debug", Info = "info", Warn = "warn", Error = "error", Silent = "silent", } /** * A description of which platform/environment an instance of the NodeCG API is being used in. * It should not be necessary to ever use this type directly in your bundle's code. */ export type Platform = "server" | "client"; }