import * as cordis from 'cordis'; import Schema from 'schemastery'; import { GeoIP, ModuleInterfaces } from './interface'; import { inject } from './lib/ui'; import { Loader } from './loader'; import { EventMap } from './service/bus'; import type { CheckService } from './service/check'; export interface Events extends cordis.Events, EventMap { } function addScript(name: string, description: string, validate: Schema, run: (args: K, report: any) => boolean | Promise) { if (global.Hydro.script[name]) throw new Error(`duplicate script ${name} registered.`); global.Hydro.script[name] = { description, validate, run }; return () => delete global.Hydro.script[name]; } function provideModule(type: T, id: string, module: ModuleInterfaces[T]) { if (global.Hydro.module[type][id]) throw new Error(`duplicate script ${type}/${id} registered.`); global.Hydro.module[type as any][id] = module; return () => delete global.Hydro.module[type][id]; } export interface Context { [Context.events]: Events; loader: Loader; Route: typeof import('./service/server').Route; Connection: typeof import('./service/server').Connection; withHandlerClass: import('./service/server').RouteService['withHandlerClass']; check: CheckService; setTimeout: typeof setTimeout; setInterval: typeof setInterval; setImmediate: typeof setImmediate; addScript: typeof addScript; provideModule: typeof provideModule; inject: typeof inject; api: ApiMixin; broadcast: Context['emit']; geoip?: GeoIP; } export class Context extends cordis.Context { static readonly session = Symbol('session'); } export namespace Context { export interface Config extends cordis.Context.Config { } } export type MainScope = cordis.MainScope; export type EffectScope = cordis.EffectScope; export type ForkScope = cordis.ForkScope; export type Plugin = cordis.Plugin; export const Service = cordis.Service; export namespace Plugin { export type Function = cordis.Plugin.Function; export type Constructor = cordis.Plugin.Constructor; export type Object = cordis.Plugin.Object; } const T = any>(origFunc: F, disposeFunc?) => function method(this: cordis.Service, ...args: Parameters) { const res = origFunc(...args); this.caller?.on('dispose', () => (disposeFunc ? disposeFunc(res) : res())); }; export class ApiMixin extends Service { static readonly methods = ['addScript', 'setInterval', 'setTimeout', 'setImmediate', 'provideModule', 'inject', 'broadcast']; addScript = T(addScript); setInterval = T(setInterval, clearInterval); setTimeout = T(setTimeout, clearTimeout); setImmediate = T(setImmediate, clearImmediate); provideModule = T(provideModule); inject = T(inject); broadcast = (event: keyof EventMap, ...payload) => this.ctx.emit('bus/broadcast', event, payload); constructor(ctx) { super(ctx, 'api', true); } } Context.service('api', ApiMixin);