import type { AuthProvider, MirrorSync, SetResult, SolanaWriteRpc } from '../types'; import { type ClientConfig } from './config'; import type { PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js'; /** Internal overrides for per-request auth and headers. */ export type RequestOverrides = { headers?: Record; authProvider?: AuthProvider; _getAuthHeaders?: () => Promise>; _clearAuth?: () => Promise; _walletAddress?: string; timeout?: number; /** Cancel the underlying HTTP request when the caller no longer needs it. */ signal?: AbortSignal; /** * @internal Fully-resolved config for a scoped `createClient()` instance. When * present, the request targets THIS config's endpoints + appId instead of the * module-global `init()` config. Threaded internally by the scoped client; * app code never sets it. */ _config?: ClientConfig; /** * @internal Read-only scoped instance marker. The request omits auth entirely, * never reads or refreshes the ambient global session, and never populates the * shared read cache. Threaded internally by the scoped read-only client. */ _readOnly?: boolean; /** * @internal Solana RPC seam for the write + reconciliation lanes. Supplied by * tests so send-loss, confirmation-timeout and expiry paths are exercised * deterministically; production builds a `Connection` from `config.rpcUrl`. */ _solanaRpc?: SolanaWriteRpc; }; export type SetOptions = { shouldSubmitTx?: boolean; _overrides?: RequestOverrides; }; /** * Thrown when a user's wallet doesn't have enough SOL to cover the transaction. * Apps can catch this to trigger an onramp/funding flow. */ export declare class InsufficientBalanceError extends Error { address: string; balanceLamports: number; estimatedCostLamports: number; deficitLamports: number; deficitSol: number; constructor(address: string, balanceLamports: number, estimatedCostLamports: number, deficitLamports: number, deficitSol: number); } /** * Return the leaf document key (last path segment) for a document path. * * Bounded rows carry `_id` (and `pathId`) set to the FULL document path * (e.g. `"rooms/r1/prompts/8rd49se3sg"`). Apps that build a child path from a * row naturally want the bare doc key, not the whole path — using the full path * doubles it (`rooms/r1/prompts/rooms/r1/prompts/8rd.../votes/...`) → 403/404. * `docId` extracts that leaf key. Tolerates leading slashes and a trailing `*`. * * @example docId("rooms/r1/prompts/8rd49se3sg") // "8rd49se3sg" */ export declare function docId(path: string): string; /** * Options for the get function. */ export type GetOptions = { /** * Structured MongoDB-style filter for collection reads, e.g. * `{ status: "open", amount: { $gt: 10 } }`. Deterministic (no AI). Supported * operators: $gt $gte $lt $lte $ne $in $nin $exists $regex ($options) $and $or * $nor; a bare value means equality. Read rules still apply on top. */ filter?: Record; /** Sort spec for collection reads, e.g. `{ createdAt: -1 }` (1 = asc, -1 = desc). */ sort?: Record; /** Natural language prompt for AI-powered queries (collections only) */ prompt?: string | undefined; /** * Opt into the short-lived local read cache. Cache entries are scoped to the * opaque authenticated principal. Reads without auth material are never cached. */ cache?: boolean; /** Force a fresh read even when `cache: true` is set */ bypassCache?: boolean; /** Include documents from sub-paths (nested collections) */ includeSubPaths?: boolean; /** Shape object for relationship resolution - specifies which related documents to include */ shape?: Record; /** Maximum number of items to return (opt-in pagination) */ limit?: number; /** Opaque cursor for cursor-based pagination (used with limit) */ cursor?: string; _overrides?: RequestOverrides; }; export type RunQueryOptions = { _overrides?: RequestOverrides; }; /** * Supported aggregate operations for count/aggregate queries. */ export type AggregateOperation = 'count' | 'uniqueCount' | 'sum' | 'avg' | 'min' | 'max'; /** * Result of a count or aggregate query — always a single numeric value. */ export type AggregateResult = { value: number; }; /** * Options for the count function. */ export type CountOptions = { /** Natural language filter prompt (e.g., "posts created in the last 7 days"). Legacy backend only. */ prompt?: string; /** Structured filter (same shape as `get`/`queryAggregate`). Preferred on Bounded. */ filter?: Record; _overrides?: RequestOverrides; }; /** * Options for the aggregate function. */ export type AggregateOptions = { /** Natural language filter prompt. Legacy backend only. */ prompt?: string; /** Structured filter (same shape as `get`/`queryAggregate`). Preferred on Bounded. */ filter?: Record; /** Field name to aggregate on (required for sum, avg, min, max) */ field?: string; _overrides?: RequestOverrides; }; export declare function count(path: string, opts?: CountOptions): Promise; /** * Run an aggregate operation on a collection path. Returns a numeric result. * * Supported operations: * - count: Total number of documents * - uniqueCount: Number of distinct values for a field * - sum: Sum of a numeric field * - avg: Average of a numeric field * - min: Minimum value of a numeric field * - max: Maximum value of a numeric field * * IMPORTANT: This only works for collections where the read policy is "true". * If the read policy requires per-document checks, the server will return * an error because aggregate operations cannot be performed without pulling * all documents for access control evaluation. * * @param path - Collection path (e.g., "posts", "users/abc/comments") * @param operation - The aggregate operation to perform * @param opts - Options including optional filter prompt and field name * @returns AggregateResult with the computed numeric value */ export declare function aggregate(path: string, operation: AggregateOperation, opts?: AggregateOptions): Promise; /** * Structured aggregation spec — group rows and compute count/sum/avg/min/max. * Unlike `aggregate` (a single scalar via AI prompt), this runs deterministically * server-side and can return MULTIPLE grouped rows. */ export type AggregateSpec = { /** Group rows by these field values (omit for a single overall row). */ groupBy?: string[]; /** Include the document count per group. */ count?: boolean; /** Sum these numeric fields per group. */ sum?: string[]; /** Average these numeric fields per group. */ avg?: string[]; /** Minimum of these fields per group. */ min?: string[]; /** Maximum of these fields per group. */ max?: string[]; }; /** One row of a `queryAggregate` result. */ export type AggregateRow = { group?: Record; count?: number; sum?: Record; avg?: Record; min?: Record; max?: Record; }; /** Options for `queryAggregate`. */ export type QueryAggregateOptions = { /** Structured MongoDB-style filter applied before grouping (same shape as GetOptions.filter). */ filter?: Record; _overrides?: RequestOverrides; }; /** * Structured, grouped aggregation over a collection. Returns one row per group * (or a single row when `spec.groupBy` is omitted). Read rules are enforced — the * aggregation only sees documents the caller can read. * * ```ts * const byCat = await queryAggregate("spend", { groupBy: ["category"], count: true, sum: ["amount"] }); * // [{ group: { category: "food" }, count: 2, sum: { amount: 70 } }, ...] * ``` */ export declare function queryAggregate(path: string, spec: AggregateSpec, opts?: QueryAggregateOptions): Promise; /** * Options for the full-text `search` function. */ export type SearchOptions = { /** Restrict the match to these declared search fields (default: all indexed fields). */ fields?: string[]; /** Maximum number of matches to return. */ limit?: number; /** Opaque pagination cursor from a prior page. */ cursor?: string; _overrides?: RequestOverrides; }; /** * Full-text search a collection declared with `search: { fields: [...] }`. * * The match runs over the collection's indexed fields (or the subset passed in * `opts.fields`) and respects each document's `read` rule — results the caller * cannot read are omitted. Returns the matching documents (optionally paged via * `opts.limit`/`opts.cursor`). * * @param path Collection path, e.g. "orgs/o1/docs" * @param query Free-text query string (non-empty) */ export declare function search(path: string, query: string, opts?: SearchOptions): Promise; export declare function get(path: string, opts?: GetOptions): Promise; export type GetManyResult = { path: string; data: any | null; error?: { code: 'NOT_FOUND' | 'UNAUTHORIZED' | 'INVALID_PATH' | 'REQUEST_FAILED'; message: string; }; }; export declare function getMany(paths: string[], opts?: { cache?: boolean; bypassCache?: boolean; _overrides?: RequestOverrides; }): Promise; export type RunExpressionOptions = { returnType?: 'Bool' | 'String' | 'Int' | 'UInt'; _overrides?: RequestOverrides; }; export type RunExpressionResult = { result: any; trace?: { variable: string; resolvedValue: any; operation?: string; result?: any; }[]; /** Server-reported failure for this row (e.g. undeclared query, execution error). */ error?: string; }; export declare function runQuery(absolutePath: string, queryName: string, queryArgs: any, opts?: RunQueryOptions): Promise; export declare function runQueryMany(many: { absolutePath: string; queryName: string; queryArgs: any; }[], opts?: RunQueryOptions): Promise; export declare function runExpression(expression: string, queryArgs: any, options?: RunExpressionOptions): Promise; export declare function runExpressionMany(many: { expression: string; queryArgs: any; returnType?: 'Bool' | 'String' | 'Int' | 'UInt'; _overrides?: RequestOverrides; }[]): Promise; /** * Best-effort mirror read. A confirmed transaction must NEVER be lost to a * synchronization failure, so this reports its outcome in `mirrorSync` and * never rejects. It reads the CONCRETE destination paths, so a collection * insert with a generated id syncs the path that actually exists. */ export declare function attemptMirrorSync(paths: string[], options?: SetOptions, settleMs?: number): Promise; /** * Write a document at `path`. Sugar for a one-element {@link setMany}. * * **Delete:** pass `null` as the document to delete it — `set(path, null)` is * the delete (there is no separate `del`/`remove`). It is routed through the * collection's policy `delete` rule and broadcasts a delete to subscribers, and * the deleted entry surfaces as a `null` document under its path. * * Resolves to a discriminated {@link SetResult}; discriminate on `status`. */ export declare function set(path: string, document: any, options?: SetOptions): Promise; /** * Atomically write (or delete, with a `null` document) a batch of documents. * * Resolves to a discriminated {@link SetResult}: * - `committed` — the worker applied the batch directly. * - `confirmed` — a client-signed chain transaction landed successfully. * - `submitted` — broadcast happened but the outcome is unknown. NEVER * resubmit; call `reconcileSetResult`/`waitForSetResult` on the receipt. * - `expired_not_landed` — Solana only, and the one retry-safe terminal state. * - `signed` — `shouldSubmitTx: false`; signed and deliberately not sent. * * `requestedDocuments` is always the caller's own echo; authoritative server * state appears only under `observation`/`mirrorSync` once actually observed. */ export declare function setMany(many: { path: string; document: any; }[], options?: SetOptions): Promise; export declare function clearCache(path?: string, opts?: { prompt?: string; }): void; /** Register a callback invoked after `clearReadCacheForAuthChange`. Returns an unregister fn. */ export declare function onReadCacheAuthChange(listener: () => void): () => void; /** * SECURITY (H1): Wipe ALL HTTP read caches + in-flight reads. Call this whenever * the logged-in identity changes (login / logout / switch identity) so a freshly * authenticated principal can never observe data cached for the previous one. * This is invoked from the WS auth-change path (reconnectWithNewAuthV2). */ export declare function clearReadCacheForAuthChange(): void; export declare function getFiles(path: string, options?: { _overrides?: RequestOverrides; }): Promise; /** * The result of a `setFile` UPLOAD. * * The two uncertain states are deliberately different words, because they have * opposite consequences: * - `visibility: 'unknown'` — the object DEFINITELY committed; only the * anonymous-read evaluation failed. Never re-upload it. * - `status: 'unknown'` — the PUT's transport outcome is ambiguous, so the * object may or may not exist. It carries the concrete path retained from * `/storage/url` and is explicitly NOT retry-safe: the one-time upload nonce * is consumed before staging, and re-calling `setFile` on a COLLECTION path * would mint a second path and orphan the first object while still billing * for it. Resolve it out of band rather than by re-uploading. */ export type FileUploadResult = { status: 'uploaded'; /** The worker's concrete path (a collection upload's id is generated server-side). */ path: string; /** * Durable public URL, or `null` when the collection's read rule does not * admit anonymous readers. A non-null URL stays valid only while that read * rule keeps admitting anonymous readers — the URL is re-evaluated on every * GET, so tightening the rule revokes it. */ url: string | null; visibility: 'public' | 'private' | 'unknown'; } | { status: 'unknown'; path: string; reason: string; retrySafe: false; }; /** * The result of a `setFile` DELETION — a distinct shape, because a delete has * no URL and no visibility. The worker answers 404 when no file exists at the * path and the shared request layer normalizes that into a non-throwing * response, so an unconditional `deleted: true` would report a deletion that * never happened. */ export type FileDeleteResult = { path: string; deleted: true; } | { path: string; deleted: false; alreadyAbsent: true; }; export declare function setFile(path: string, file: File, options?: { _overrides?: RequestOverrides; metadata?: Record; }): Promise; export declare function setFile(path: string, file: null, options?: { _overrides?: RequestOverrides; metadata?: Record; }): Promise; export declare function setFile(path: string, file: File | null, options?: { _overrides?: RequestOverrides; metadata?: Record; }): Promise; export declare function signMessage(message: string): Promise; export declare function signTransaction(transaction: Transaction | VersionedTransaction): Promise; export declare function signAndSubmitTransaction(transaction: Transaction | VersionedTransaction, feePayer?: PublicKey): Promise; export declare function syncItems(paths: string[], options?: SetOptions): Promise;