import { ClientMessage, RemoteMessage } from './contract.js'; import { MetaScope, EventPathArgs, EventPath } from './type-utils.js'; import { default as RPCSource } from './RPCSource.js'; export type RPCChannelConnection = (onMessage: (...messages: RemoteMessage) => void, onClose: (reason?: any) => void) => (...messages: ClientMessage) => void; interface MetaDesc { methods?: M; events?: E; state?: S; } interface MetaType { methods: M; events: E; state: S; } type MetaScopeToDesc = T extends MetaScope ? MetaType : never; type ExtraKeys = "on" | "once" | "off" | "notify" | "then"; type ExtractMetaType = ((T extends MetaScope ? MetaScopeToDesc : T) extends infer D ? { methods: D extends { methods: infer M; } ? M : any; events: D extends { events: infer E; } ? E : any; state: D extends { state: infer S; } ? S : any; } : never); type RPCMethodsAny = { [key: string]: RPCMethodsAny & RPCMethod & RPCConstructor; }; type RPCMethodsPart = 0 extends (1 & T) ? RPCMethodsAny : (T extends ((...args: any) => any) | { new (...args: any): any; } | MetaScope ? unknown : { [K in Exclude]: RPCMethodsPart; }) & (T extends (...args: infer A) => infer R ? ([ R ] extends [never] ? RPCMethod : Exclude, MetaScope> extends infer RC ? ([RC] extends [never] ? unknown : RPCMethod) : unknown) & ([ R ] extends [never] ? unknown : Extract, MetaScope> extends infer RC extends MetaScope ? RPCConstructor : unknown) : unknown) & (T extends (new (...args: infer A) => infer R extends MetaScope) ? RPCConstructor : unknown) & (T extends PromiseLike ? RPCConstructor<[], R> : unknown) & (T extends MetaScope ? RPCConstructor<[], T> : unknown); type RPCMethod = { (...args: A): Promise>; notify(...args: A): void; call: never; bind: never; apply: never; name: never; length: never; }; type RPCConstructor = { new (...args: A): RPCChannel; call: never; bind: never; apply: never; name: never; length: never; }; interface EventHandler { on, SPECIAL_EVENTS>>(this: this, eventName: E, handler: (...args: EventPathArgs) => void): this; once, SPECIAL_EVENTS>>(this: this, eventName: E, handler: (...args: EventPathArgs) => void): this; off, SPECIAL_EVENTS>>(this: this, eventName: E, handler: (...args: EventPathArgs) => void): this; } interface BaseEventHandler { on>(this: this, eventName: E, handler: (...args: RPCChannelEvents[E]) => void): this; once>(this: this, eventName: E, handler: (...args: RPCChannelEvents[E]) => void): this; off>(this: this, eventName: E, handler: (...args: RPCChannelEvents[E]) => void): this; } type EventsOfAny = EventHandlerAny & { [key: string]: EventsOfAny; }; interface EventHandlerAny { on(this: this, eventName: T extends SPECIAL_EVENTS ? never : T, handler: (...args: any) => void): this; once(this: this, eventName: T extends SPECIAL_EVENTS ? never : T, handler: (...args: any) => void): this; off(this: this, eventName: T extends SPECIAL_EVENTS ? never : T, handler: (...args: any) => void): this; } interface EventHandlerEmptyArray { on(eventName: [], handler: (this: this, ...args: E) => void): this; once(eventName: [], handler: (this: this, ...args: E) => void): this; off(eventName: [], handler: (this: this, ...args: E) => void): this; } type HasAnyValue = T[keyof T] extends infer V ? ([V] extends [never] ? N : Y) : N; type RPCEventsPart = [T] extends [never] ? unknown : (0 extends (1 & T) ? EventsOfAny : (Extract extends infer F extends any[] ? [F] extends [never] ? unknown : EventHandlerEmptyArray : never) & (Exclude extends infer F ? (HasAnyValue as F[K] extends any[] ? never : K]: RPCEventsPart; } & EventHandler, unknown>) : never)); interface RPCChannelInstance extends BaseEventHandler { get state(): S; close(reason?: any): void; get closed(): boolean; get ready(): boolean; then: void; promise: Promise; } type RPCChannel = ExtractMetaType extends { methods: infer M; events: infer E; state: infer S; } ? (Disposable & MetaScope & RPCChannelInstance & RPCEventsPart> & RPCMethodsPart>) : never; export type RPCChannelEvents = { state: [newState: S, oldState?: S]; close: [reason: any]; ready: []; error: [error: any]; }; declare const RPCChannel: ({ new (connection: RPCChannelConnection, options?: { getNextChannelId?: () => string | number; connectionTimeout?: number | AbortSignal; }): RPCChannel; new >(source: R, options?: { getNextChannelId?: () => string | number; connectionTimeout?: number | AbortSignal; }): RPCChannel; }); export default RPCChannel;