/** * Scoped multi-app client factory. * * `createClient()` returns an isolated, READ-ONLY client bound to one Bounded * app, independent of the module-global `init()` client. It exists so a single * frontend can hold its normal authenticated client for its own app AND a * read-only client for a SECOND Bounded app (e.g. a shared steward/runtime app), * with live subscriptions on both and zero interference between them. * * Each instance carries its OWN fully-resolved config (endpoints + appId) and * routes through the SAME shared transport/subscription implementation as the * global path - it never forks that code. Isolation comes from threading the * instance config (and a read-only marker) through the existing per-request / * per-subscription override channel, plus the websocket layer already keying * connections by appId. * * ## v1 scope: read-only, unauthenticated * * A scoped instance is UNAUTHENTICATED. It sends no auth, never reads or * refreshes the global session, and connects to its app's realtime endpoint * anonymously. It is therefore only useful against collections a Bounded app * exposes with a public read rule (`read: true`) - private/per-user reads will * be denied by the target app's policy, exactly as an anonymous caller would be. * * Writes and any auth-requiring surface are NOT supported on a scoped instance * and throw a clear error. Per-instance authentication is a planned follow-up. */ import { type GetOptions, type SearchOptions, type CountOptions, type AggregateOptions, type QueryAggregateOptions, type RunQueryOptions, type AggregateOperation, type AggregateResult, type AggregateRow, type AggregateSpec, type GetManyResult, type RequestOverrides } from './operations'; import { type ClientConfig } from './config'; import type { SubscriptionOptions } from '../types'; /** Config accepted by {@link createClient}. Only `appId` is required; `network` * (or explicit endpoint fields) selects the target Bounded backend. */ export type CreateClientConfig = Partial & { appId: string; }; /** * A read-only client scoped to a single Bounded app, isolated from the global * `init()` client. Read methods mirror the global surface; writes and auth throw. */ export interface BoundedClient { /** The app id this instance is bound to. */ readonly appId: string; /** A snapshot of this instance's fully-resolved config (endpoints + appId). */ getConfig(): ClientConfig; /** Read a document or collection. See the global `get`. */ get(path: string, opts?: GetOptions): Promise; /** Batch-read up to 30 documents. See the global `getMany`. */ getMany(paths: string[], opts?: { cache?: boolean; bypassCache?: boolean; _overrides?: RequestOverrides; }): Promise; /** Full-text search a collection declared with `search`. */ search(path: string, query: string, opts?: SearchOptions): Promise; /** Structured, grouped aggregation over a collection. */ queryAggregate(path: string, spec: AggregateSpec, opts?: QueryAggregateOptions): Promise; /** Count matching documents (deterministic on Bounded). */ count(path: string, opts?: CountOptions): Promise; /** Single-scalar aggregate (count/sum/avg/min/max/uniqueCount). */ aggregate(path: string, operation: AggregateOperation, opts?: AggregateOptions): Promise; /** Run a named/computed query defined by the app's policy. */ runQuery(absolutePath: string, queryName: string, queryArgs: any, opts?: RunQueryOptions): Promise; /** Batch variant of {@link runQuery}. */ runQueryMany(many: { absolutePath: string; queryName: string; queryArgs: any; }[], opts?: RunQueryOptions): Promise; /** * Subscribe to realtime updates for a path on THIS app's realtime endpoint. * Anonymous (read-only): the collection must be publicly readable. Returns an * unsubscribe function. Subscriptions on this instance are fully independent * of the global client and of any other scoped instance. */ subscribe(path: string, options: SubscriptionOptions | ((data: any) => void)): Promise<() => Promise>; /** Not supported on a read-only scoped instance - always throws {@link ScopedClientReadOnlyError}. */ set(path: string, document: any): Promise; /** Not supported on a read-only scoped instance - always throws {@link ScopedClientReadOnlyError}. */ setMany(many: { path: string; document: any; }[]): Promise; } /** Error thrown when an unsupported (write / auth-requiring) call is made on a * read-only scoped client. */ export declare class ScopedClientReadOnlyError extends Error { constructor(operation: string); } /** * Create a read-only client scoped to a single Bounded app. * * @example * ```ts * // Global client stays the venue's own authenticated app: * await init({ appId: VENUE_APP, network: 'bounded-production', authMethod: 'email' }); * * // A second, read-only client for the steward runtime app: * const steward = createClient({ appId: STEWARD_APP, network: 'bounded-production' }); * const state = await steward.get('runtime/current'); * const stop = await steward.subscribe('runtime/current', (d) => render(d)); * ``` */ export declare function createClient(config: CreateClientConfig): BoundedClient;