/** * Describes a named storage backend — a place files live. * * Declared once and shared front + back: the frontend uses it to decide * transport (HTTP proxy vs direct SDK), the backend uses the same `key` * to resolve a StorageController, and collection properties reference * a definition by its `key` via `StorageConfig.storageSource`. * * This mirrors the {@link DataSourceDefinition} pattern used for databases. * * @group Models */ /** * The default storage source key, used when a property does not specify * a `storageSource`. Shared by the frontend and backend registries so * both agree on "the default storage backend". * @group Models */ export declare const DEFAULT_STORAGE_SOURCE_KEY = "(default)"; /** * How the *frontend* reaches a storage backend. * * - `"server"` — through the Rebase backend REST API (`/api/storage`). * The backend holds the actual `StorageController` and routes by * storage-source key. This is the default and covers Local, S3, GCS, * and any other server-mediated engine. * - `"direct"` — straight from the client to the external backend via * its own SDK (e.g. Firebase Storage via `@firebase/storage`). * The Rebase backend is **not** in the upload/download path. * * @group Models */ export type StorageSourceTransport = "server" | "direct"; /** * Declarative definition of a storage source — a named place files live. * * Declared once and shared front and back: the frontend uses it to decide * transport (client HTTP proxy vs direct provider SDK), the backend uses * the same `key` to resolve a `StorageController`, and collection * properties reference a definition by its `key` via * `StorageConfig.storageSource`. * * @group Models */ export interface StorageSourceDefinition { /** * Unique identifier for this storage source. Collection properties * point at it via `StorageConfig.storageSource`. * Defaults to {@link DEFAULT_STORAGE_SOURCE_KEY}. */ key: string; /** * The engine backing this storage source (e.g. `"local"`, `"s3"`, * `"gcs"`, `"firebase"`, `"azure"`, or a custom id). */ engine: string; /** * How the frontend reaches this storage. Defaults to `"server"`. * * When `"direct"`, the client uses a provider-specific SDK * (e.g. `@firebase/storage`) and the backend does not proxy * upload/download traffic for this source. */ transport: StorageSourceTransport; /** Human-readable label for the UI (e.g. "Firebase Storage", "S3 Media"). */ label?: string; } /** * A resolved storage source: the single source of truth that the frontend * router and backend registry both derive from. * * @group Models */ export interface ResolvedStorageSource { /** Storage source key (routing key, shared front + back). */ key: string; /** Engine backing the source. */ engine: string; /** Frontend transport. */ transport: StorageSourceTransport; /** Human-readable label. */ label?: string; } /** * The environment-variable suffix for a storage or data source key. * * `""` for the default source — so a single-bucket project keeps configuring * plain `S3_BUCKET` — and `__` for every named one, uppercased with * non-alphanumerics collapsed to underscores: `media-cdn` → `S3_BUCKET__MEDIA_CDN`. * * The rule derives the variable name from the declared key rather than * discovering keys by scanning the environment. Scanning would have to guess how * `S3_BUCKET__MEDIA_CDN` splits into a key; deriving cannot be ambiguous, and a * typo surfaces as a missing source at boot instead of a silently ignored * variable. * * It lives in this package, with no dependencies, because four things must agree * on it exactly: the CLI (validating a build), the runtime (reading its own * environment), the control plane (writing a tenant's Secret), and the docs. A * second implementation of a naming convention is a second chance to disagree. * * @group Models */ export declare function storageEnvSuffix(key: string, defaultKey?: string): string; /** * Two distinct keys that collapse onto the same variable name, or `null`. * * `media-cdn` and `media_cdn` are different source keys but the same suffix, so * without this one of them silently reads the other's configuration. Returns the * offending pair rather than throwing, so each caller can raise it in its own * idiom — a `BundleError` at boot, a build failure in the CLI, a rejected deploy * in a control plane. * * @group Models */ export declare function findStorageSuffixCollision(keys: string[], defaultKey?: string): { a: string; b: string; suffix: string; } | null; /** The `storage` block of `rebase.json`, structurally. */ export type DeclaredStorageSources = Record; /** * Merge the two places a project may declare storage sources into one list. * * `rebase.json` is authoritative for every field it states. Config code may add * sources it does not mention and fill in fields it left out, but may not * contradict it: the manifest is what a host reads to decide which buckets need * configuring, and a runtime that quietly disagreed with it would put the * console back to describing a topology the tenant does not have — the exact * failure this whole mechanism exists to end. * * Note what is *not* here: no default source is invented when both inputs are * empty. That decision belongs to the resolver, which knows whether declaring * nothing means "one plain bucket" (it does) or "no storage at all". * * @group Models */ export declare function normalizeStorageSources(declared: DeclaredStorageSources | StorageSourceDefinition[] | undefined, exported: StorageSourceDefinition[] | undefined): StorageSourceDefinition[];