/** * One tenant model for every store. * * Each function returns one tenant's view of a shared store, implementing the same contract as the * store itself, so a tenant's code takes a `TraceStore`, a `PromptStore`, or a `VectorStore` as it * always did and cannot reach past its tenant. Names and keys are placed under the tenant's prefix * (`tenant//`) and records carry `tenantId`, so the views work over the memory, Redis, Postgres, * SQLite, and file stores alike, with no schema change. A tenant id is letters, digits, `_`, and `-`, * so no tenant's prefix is the start of another's. */ import type { CacheAdapter } from '../cache/adapters.js'; import type { VectorStore } from '../hallucination/retrieval.js'; import type { AssetPutOptions, AssetSignOptions, AssetStore } from '../images/asset-support.js'; import type { RollupStore } from '../tracing/rollups.js'; import type { DatasetStore, ExperimentStore } from '../types/evaluate.js'; import type { OperationStore } from '../types/operations.js'; import type { PromptStore } from '../types/prompts.js'; import type { Store } from '../types/store.js'; import type { TraceStore } from '../types/tracing.js'; export { TENANT_NAMESPACE, tenantStore } from '../store/tenant.js'; export { assertTenantId, TenantIdError } from '../utils/tenant.js'; /** * One tenant's traces. Every run saved through it is stamped `metadata.tenantId`, the field rollups, * the studio, and the Postgres tenant index read; `get()`, `query()`, and `tree()` return only runs so * stamped, and feedback reaches only the tenant's own runs. `prune()` is left out, since it would * remove every tenant's old runs. */ export declare function tenantTraceStore(store: TraceStore, tenantId: string): TraceStore; /** * One tenant's operations. Records it creates carry `tenantId`, and their idempotency keys are * placed under the tenant's prefix, so two tenants using the same key never collide. Reads, updates, * deletes, recovery, and queue listings see only the tenant's records; `listQueued()` and `stats()` * pass the tenant to the store as a filter, which Postgres and SQLite answer from an index. */ export declare function tenantOperationStore(store: OperationStore, tenantId: string): OperationStore; /** * One tenant's prompts. Every prompt name is placed under the tenant's prefix on the way in and * taken off on the way out, so the tenant sees its own names and `listNames()` lists only them. A * `ContextHub` given this store keeps the tenant's context bundles apart the same way. */ export declare function tenantPromptStore(store: PromptStore, tenantId: string): PromptStore; /** One tenant's datasets: names placed under the tenant's prefix, and `list()` showing only its own. */ export declare function tenantDatasetStore(store: DatasetStore, tenantId: string): DatasetStore; /** * One tenant's experiments. Ids, names, and dataset names are placed under the tenant's prefix, so * `get()` of another tenant's experiment id finds nothing and `list()` returns only the tenant's. */ export declare function tenantExperimentStore(store: ExperimentStore, tenantId: string): ExperimentStore; /** * One tenant's retrieval chunks. Each chunk's id is placed under the tenant's prefix and its metadata * stamped `tenantId`, and every search adds `tenantId` to its filter, which every vector store applies * natively. A search never ranks another tenant's chunks, and `delete()` reaches only the tenant's. */ export declare function tenantVectorStore(store: VectorStore, tenantId: string): VectorStore; /** * One tenant's cache: every key placed under the tenant's prefix, so a tenant can never read what * another cached. `clear()` is left out, since it would clear every tenant's entries. */ export declare function tenantCache(cache: CacheAdapter, tenantId: string): CacheAdapter; /** An asset store with the tenant bound, so no call can name another. Returned by `tenantAssetStore()`. */ export interface TenantAssetStore { /** The tenant every call acts for. */ readonly tenantId: string; /** Stores an asset for the tenant. */ put(input: Parameters[0], options: Omit): ReturnType; /** Reads one of the tenant's assets with its bytes. */ get(assetId: string): ReturnType; /** Describes one of the tenant's assets. */ stat(assetId: string): ReturnType; /** Deletes one of the tenant's assets. */ delete(assetId: string): ReturnType; /** Signs a URL for one of the tenant's assets. */ sign(assetId: string, options?: AssetSignOptions): ReturnType; } /** * One tenant's assets. Asset stores already treat another tenant's asset as missing; this binds the * tenant once, so code handed the view cannot pass a different one. */ export declare function tenantAssetStore(store: AssetStore, tenantId: string): TenantAssetStore; /** One tenant's rollups: rows it adds are counted for the tenant, and queries read only the tenant's rows. */ export declare function tenantRollupStore(store: RollupStore, tenantId: string): RollupStore; /** The stores `tenantScope()` can scope. Each is optional. */ export interface TenantStores { /** Long-term memory. */ store?: Store; /** Traces. */ traces?: TraceStore; /** Operation records. */ operations?: OperationStore; /** Prompt versions and labels, and the context hub's bundles. */ prompts?: PromptStore; /** Datasets. */ datasets?: DatasetStore; /** Experiments. */ experiments?: ExperimentStore; /** Retrieval chunks. */ vectors?: VectorStore; /** A cache. */ cache?: CacheAdapter; /** Dashboard rollups. */ rollups?: RollupStore; } /** * Scopes every given store to one tenant at once, keeping each one's type, so a request handler * builds its tenant's view in one line. * * ```ts * const scoped = tenantScope(principal.tenantId, { store, traces, prompts, vectors }); * ``` */ export declare function tenantScope(tenantId: string, stores: T): T & { readonly tenantId: string; };