import * as E from "edinburgh"; import * as realWarpsocket from 'warpsocket'; export declare const logLevel: number; /** @internal Warpsocket implementation; swapped to FakeWarpSocket in test mode. */ export declare let warpsocket: typeof realWarpsocket; /** @internal Used by the dashboard module to inspect registered stream types. */ export declare function getStreamTypesForModel(Model: E.AnyModelClass): readonly (typeof StreamTypeBase)[]; /** * Base class for stream types created by {@link createStreamType}. * @typeParam T - The projected model type * @internal */ export declare abstract class StreamTypeBase { _instance: E.Model & T; /** @internal `true`=plain field, number=sub-stream id, `false`=virtual getter */ static fields: { [key: string]: boolean | number; }; /** @internal */ static id: number; /** @internal */ static cache: number | undefined; constructor(_instance: E.Model & T); toString(): string; } /** * Type-safe selector for specifying which model fields to stream to clients. * Use `true` to include a field, or an object to select nested fields in linked models. * Set and Record fields take a selection for U (applied to every element). * * @typeParam T - The model type */ type FieldSelection = T extends ReadonlyArray ? true | FieldSelection : T extends Array ? true | FieldSelection : T extends ReadonlySet ? true | FieldSelection : string extends keyof T ? T extends Record ? true | FieldSelection : true : T extends object ? true | { [K in keyof T]?: FieldSelection; } : true; /** * Validates field selection compatibility at compile time. * @internal */ type ValidateSelection = T extends ReadonlyArray ? S extends true ? true : ValidateSelection : T extends Array ? S extends true ? true : ValidateSelection : T extends ReadonlySet ? S extends true ? true : ValidateSelection : string extends keyof T ? T extends Record ? S extends true ? true : ValidateSelection : never : T extends object ? S extends true ? true : S extends object ? { [K in keyof S]-?: K extends keyof T ? ValidateSelection : never; } : never : S extends true ? true : never; /** * Computes the resulting type after applying a field selection. * @internal */ type Project = S extends true ? T : T extends ReadonlyArray ? ReadonlyArray> : T extends Array ? Array> : T extends ReadonlySet ? Project[] : string extends keyof T ? T extends Record ? Record> : T : T extends object ? { [K in Extract]: Project; } : T; /** * Creates a stream type for reactive model streaming to clients with automatic updates. * * Specify which fields to include; when they change, updates are pushed to subscribed clients. * Supports nested linked models and type-safe field selection. * * @typeParam T - The model type * @typeParam S - The field selection * * @param Model - The Edinburgh model class * @param selection - Field selection: `true` for simple fields, nested object for linked models * @param options - Optional settings * @param options.cache - Seconds the client should linger the stream after out-of-scope, enabling instant reuse and dedup on repeat calls * @returns Stream type class to instantiate in API functions * * @example * ```ts * const Person = E.defineModel('Person', class { * name = E.field(E.string); * age = E.field(E.number); * password = E.field(E.string); * friends = E.field(E.array(E.link(() => Person))); * }, { pk: 'name' }); * * // Exclude password, include friends' names; cache 30s * const PersonStream = createStreamType(Person, { * name: true, * age: true, * friends: { name: true } * }, { cache: 30 }); * * export function streamPerson() { * const person = Person.get('Alice')!; * return new PersonStream(person); * } * ``` */ export declare function createStreamType>(Model: E.AnyModelClass & (new (...args: any[]) => T), selection: S & ValidateSelection, options?: { cache?: number; }): { new (instance: T): StreamTypeBase>; id: number; fields: Record; cache?: number; }; /** * Sends (updated) data for `model` to `target`. * `target` is a virtual socket with a requestId+'d' user prefix, or a channel that subscribes such virtual sockets. */ export declare function sendModel(target: Uint8Array | number | number[], model: E.Model, commitId: number, StreamType: typeof StreamTypeBase, changed?: E.Change): void; /** * Subscribes `target` to this model, and sends initial data. * `target` is a virtual socket with a requestId+'d' user prefix, or a channel that subscribes such virtual sockets. */ export declare function pushModel(target: number | Uint8Array | number[], model: E.Model, commitId: number, SubStreamType: typeof StreamTypeBase, delta: number): void; /** * Wraps a server-side API object to create a stateful, type-safe proxy accessible from clients. * Use for authentication, sessions, or any stateful context that persists across RPC calls. * * If the API object has an `onDrop()` method, it is called when the proxy is dropped, either * because the client cancelled the request (scope cleanup) or the WebSocket disconnected. * Use this to clean up server-side state kept on behalf of the client. * * @typeParam API - The server-side API object type * @typeParam RETURN - The value type returned to the client * * @example * ```ts * export class UserAPI { * constructor(public user: User) {} * getSecret() { return this.user.secret; } * onDrop() { console.log('client gone'); } * } * * export async function authenticate(token: string) { * const user = await validateToken(token); * return new ServerProxy(new UserAPI(user), user.name); * } * * // Client: auth.value is user name, auth.serverProxy.getSecret() calls UserAPI method * ``` */ export declare class ServerProxy { api: API; value?: RETURN | undefined; /** * @param api - Server-side API object exposed to the client * @param value - Value returned immediately to the client */ constructor(api: API, value?: RETURN | undefined); toString(): string; } /** * Server-side socket for pushing data to a client. Server functions with `Socket` parameters * receive client callbacks on the client side. * * @typeParam T - Data type sent through the socket * * @example * ```ts * // Server * export function streamNumbers(socket: Socket) { * setInterval(() => { * if (!socket.send(Math.random())) clearInterval(interval); * }, 1000); * } * * // Client * api.streamNumbers(num => console.log(num)); * ``` */ export declare class Socket { virtualSocketId: number; /** @internal */ constructor(virtualSocketId: number); /** * Sends data to the client. * @param data - Data to send (automatically serialized) * @returns `true` if sent, `false` if socket is closed */ send(data: T): number; /** @internal */ subscribe(channel: Uint8Array, delta?: number): void; toString(): string; } /** * Starts the Lowlander WebSocket server. * * @param mainApiFile - Absolute path to the compiled API file exporting server functions * @param opts.bind - Address and port (default: '0.0.0.0:8080') * @param opts.threads - Worker thread count (default: auto) * @param opts.injectWarpSocket - For testing: inject a custom WarpSocket implementation (e.g. FakeWarpSocket) * * @example * ```ts * import { start } from 'lowlander/server'; * import { fileURLToPath } from 'url'; * import { resolve, dirname } from 'path'; * * const API_FILE = resolve(dirname(fileURLToPath(import.meta.url)), 'api.js'); * start(API_FILE, { bind: '0.0.0.0:8080' }); * ``` */ export declare function start(mainApiFile: string, opts?: { bind?: string; threads?: number; injectWarpSocket?: typeof realWarpsocket; }): Promise; export {}; //# sourceMappingURL=server.d.ts.map