import { type BlobStoreHandle, type BlobStoreNeed, type PlatformActorId, type TenantId, type TenantStoreHandle, type TenantStoreNeed } from '@substrat-run/contracts'; import type { BlobStoreRecord, HostAdmin, ScopeHost, TenantStoreRecord } from '@substrat-run/kernel'; import type { ScriptBindingSpec, PatchScriptBindingsFn } from './wfp.js'; /** * What a vertical DECLARES its tenants must be given, and where that declaration is * being served from — the one resolution every store path shares (mint, backfill, and * the health check that reports a store as missing). * * The version whose declaration governs is the one that will SERVE a provisioned scope: * the serving script's version (#286) when one exists, else the prod channel — the same * ladder provisioning itself resolves the `VerticalClient` through. A vertical with no * retained manifest (a pre-#286 push, or a statically-bound one) declares nothing, which * is what keeps every existing vertical untouched by all of this. */ export interface StoreDeclaration { /** The version the declaration was read from — null when nothing is deployed. */ versionId: string | null; /** The script a binding must be attached to: the serving script, else the version's own. */ scriptRef: string | null; tenantStores: TenantStoreNeed[]; blobStores: BlobStoreNeed[]; } /** Resolve {@link StoreDeclaration} for a vertical — see its doc for the version ladder. */ export declare function resolveStoreDeclaration(admin: HostAdmin, actor: PlatformActorId, slug: string): Promise; /** One store a vertical declared that a tenant has no ledger row for (#825). */ export interface MissingStore { binding: string; kind: 'relational' | 'blob'; } /** A store minted by the promote-time backfill, for the report it returns (#825). */ export interface MintedStore extends MissingStore { tenantId: TenantId; } /** * Stores a vertical DECLARES that this tenant was never minted (#825) — the check that * turns "the vertical throws at first upload, in production" into a condition the fleet * can see. Per-tenant stores are minted in the tenant-creation lifecycle, so a tenant * that predates a newly declared need passes that gate once, before the need existed, * and never passes it again: nothing about its scope looks unhealthy, and the first * signal is a runtime refusal arbitrarily long after the deploy that introduced the need. * * Reported by `/scopes/:id/health` and repaired by re-provisioning the scope, which mints * whatever this returns (`collectTenantStoreHandles` / `collectBlobStoreHandles`). */ export declare function missingStoresForTenant(opts: { host: ScopeHost; actor: PlatformActorId; slug: string; tenantId: TenantId; }): Promise; /** * Mint every declared store the named tenants are missing, in ONE pass (#825) — the * deploy-time backfill, called on promote once the new version is the serving one. * * This is what keeps a newly declared store from being an ops runbook. Minting used to * happen only in the tenant-creation lifecycle, which is a gate every existing tenant has * already passed: declaring a store in version N+1 gave it to nobody, and the operator had * to know to re-provision each install by hand. Promote is where the declaration becomes * real for everyone else (the serving script is uploaded, its bindings re-derived), so it * is where the fleet's stores are reconciled to it too. * * Reads both ledgers ONCE and diffs in memory, so the common case — every tenant already * holds what the version declares, or the version declares nothing — costs two reads and * mints nothing. The binding attach is a single ledger-derived PATCH after the mints, not * one per tenant, and runs only if something was actually minted (the serving upload that * just happened already carried every pre-existing binding). */ export declare function backfillDeclaredStores(opts: { host: ScopeHost; actor: PlatformActorId; slug: string; /** The tenants installed on this vertical, from the directory's own inventory. */ tenantIds: TenantId[]; patchBindings?: PatchScriptBindingsFn; }): Promise; /** * The provision-time half of per-tenant relational stores (#301, PR-2): resolve what a * vertical DECLARED (its bound version's stored manifest, `tenantStores`), have the host * MINT each store for this tenant (idempotent — a retried provision re-resolves the same * handles), make the stores REACHABLE at request time (attach the D1 bindings to the * script that serves this vertical), and return the handles the K-31 provision callback * hands over so the vertical runs its own migrations inside the existing fail-closed / * retryable ready-gate. * * Substrate-agnostic by construction: a vertical with no retained manifest or no declared * `tenantStores` yields `[]` (nothing changes for every existing vertical), and the * binding attach only runs where a patcher is configured (Cloudflare) — the pure adapter * has no script to patch and needs none, its handle refs open directly. */ export declare function collectTenantStoreHandles(opts: { host: ScopeHost; actor: PlatformActorId; /** The vertical's registry slug — the id its ledger rows and manifest live under. */ slug: string; tenantId: TenantId; /** Attach bindings on the dispatch script (Cloudflare); absent = no attach step. */ patchBindings?: PatchScriptBindingsFn; }): Promise; /** * The provision-time half of per-tenant blob stores (#473) — the byte-store twin of * {@link collectTenantStoreHandles}: mint one R2 bucket per declared `blobStoreNeed` for * this tenant (idempotent) and attach its `r2_bucket` binding to the serving script. * Unlike tenant stores, blob stores need no migration ready-gate (there is no schema), so * this returns nothing for the provision callback — the effect is the ledger + bindings. */ export declare function collectBlobStoreHandles(opts: { host: ScopeHost; actor: PlatformActorId; slug: string; tenantId: TenantId; patchBindings?: PatchScriptBindingsFn; }): Promise; /** Ledger rows → the D1 bindings a script serving this vertical must carry (#301). */ export declare function tenantStoreBindings(ledger: TenantStoreRecord[]): ScriptBindingSpec[]; /** Ledger rows → the R2 bindings a script serving this vertical must carry (#473). */ export declare function blobStoreBindings(ledger: BlobStoreRecord[]): ScriptBindingSpec[]; //# sourceMappingURL=tenant-stores.d.ts.map