@rebasepro/types 0.16.0 → 0.16.1-canary.g041c925

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/call_context.d.ts +5 -5
  2. package/dist/controllers/auth_state.d.ts +1 -1
  3. package/dist/controllers/client.d.ts +22 -9
  4. package/dist/controllers/collection_registry.d.ts +2 -2
  5. package/dist/controllers/data.d.ts +4 -12
  6. package/dist/controllers/data_driver.d.ts +7 -7
  7. package/dist/controllers/email.d.ts +54 -2
  8. package/dist/controllers/index.d.ts +8 -9
  9. package/dist/controllers/storage.d.ts +4 -4
  10. package/dist/index.d.ts +5 -5
  11. package/dist/index.es.js +429 -3
  12. package/dist/index.es.js.map +1 -1
  13. package/dist/types/admin_block.d.ts +1 -1
  14. package/dist/types/auth_adapter.d.ts +18 -9
  15. package/dist/types/backend.d.ts +23 -10
  16. package/dist/types/collection_contract.d.ts +1 -1
  17. package/dist/types/collections.d.ts +16 -9
  18. package/dist/types/component_ref.d.ts +3 -2
  19. package/dist/types/cron.d.ts +1 -25
  20. package/dist/types/data_source.d.ts +1 -1
  21. package/dist/types/database_adapter.d.ts +5 -5
  22. package/dist/types/entities.d.ts +1 -1
  23. package/dist/types/entity_callbacks.d.ts +4 -4
  24. package/dist/types/index.d.ts +32 -29
  25. package/dist/types/project_manifest.d.ts +132 -27
  26. package/dist/types/properties.d.ts +58 -6
  27. package/dist/types/relations.d.ts +1 -1
  28. package/dist/types/resource_kinds.d.ts +174 -0
  29. package/dist/types/resources.d.ts +197 -0
  30. package/dist/types/schema_editing.d.ts +127 -0
  31. package/dist/types/schema_version.d.ts +1 -1
  32. package/dist/types/security_rules.d.ts +1 -1
  33. package/dist/users/index.d.ts +1 -1
  34. package/package.json +2 -2
  35. package/src/controllers/client.ts +14 -1
  36. package/src/controllers/data.ts +0 -9
  37. package/src/controllers/email.ts +55 -2
  38. package/src/controllers/index.ts +0 -1
  39. package/src/controllers/storage.ts +4 -4
  40. package/src/types/admin_block.ts +1 -2
  41. package/src/types/auth_adapter.ts +18 -10
  42. package/src/types/backend.ts +18 -1
  43. package/src/types/collections.ts +9 -2
  44. package/src/types/component_ref.ts +3 -2
  45. package/src/types/cron.ts +0 -24
  46. package/src/types/index.ts +3 -0
  47. package/src/types/project_manifest.ts +139 -26
  48. package/src/types/properties.ts +54 -0
  49. package/src/types/resource_kinds.ts +309 -0
  50. package/src/types/resources.ts +368 -0
  51. package/src/types/schema_editing.ts +154 -0
  52. package/dist/controllers/database_admin.d.ts +0 -11
  53. package/src/controllers/database_admin.ts +0 -22
@@ -29,7 +29,7 @@
29
29
  *
30
30
  * @group Models
31
31
  */
32
- export declare const ADMIN_COLLECTION_KEYS: readonly ["Actions", "additionalFields", "alwaysApplyDefaultValues", "components", "customViews", "defaultEntityAction", "defaultFilter", "defaultSelectedView", "defaultSize", "defaultViewMode", "disableDefaultActions", "display", "enabledViews", "entityActions", "entityViews", "exportable", "filterPresets", "fixedFilter", "form", "formAutoSave", "formView", "group", "hideFromEntityViews", "hideFromNavigation", "hideIdFromCollection", "hideIdFromForm", "icon", "includeJsonView", "inlineEditing", "kanban", "listProperties", "localChangesBackup", "openEntityMode", "orderProperty", "pagination", "previewProperties", "propertiesOrder", "selectionController", "selectionEnabled", "sideDialogWidth", "sort", "titleProperty"];
32
+ export declare const ADMIN_COLLECTION_KEYS: readonly ["Actions", "additionalFields", "alwaysApplyDefaultValues", "components", "customViews", "defaultEntityAction", "defaultFilter", "defaultSelectedView", "defaultSize", "defaultViewMode", "disableDefaultActions", "display", "enabledViews", "entityActions", "entityViews", "exportable", "filterPresets", "fixedFilter", "form", "formAutoSave", "formView", "group", "hideFromEntityViews", "hideFromNavigation", "hideIdFromCollection", "hideIdFromForm", "icon", "includeJsonView", "inlineEditing", "kanban", "listProperties", "localChangesBackup", "openEntityMode", "orderProperty", "pagination", "previewProperties", "propertiesOrder", "selectionController", "selectionEnabled", "sideDialogWidth", "sort"];
33
33
  /** A key of a collection's `admin` block. @group Models */
34
34
  export type AdminCollectionKey = typeof ADMIN_COLLECTION_KEYS[number];
35
35
  /**
@@ -75,8 +75,16 @@ export interface AuthAdapterCapabilities {
75
75
  hasBuiltInAuthRoutes: boolean;
76
76
  /** Supports email/password login. */
77
77
  emailPasswordLogin: boolean;
78
- /** Supports new user registration. */
79
- registration: boolean;
78
+ /**
79
+ * Whether self-registration is open **right now**.
80
+ *
81
+ * A runtime answer, not a static feature list: the built-in adapter also
82
+ * reports `true` during the first-user bootstrap window (an empty user
83
+ * table) and `false` the moment `disableSelfRegistration` is set. Whatever
84
+ * this says, `POST /auth/register` does — both read the same predicate, so
85
+ * the UI can never be sent to a form that can only 403.
86
+ */
87
+ registrationEnabled: boolean;
80
88
  /**
81
89
  * Supports the end-user password reset flow (emailing a reset link).
82
90
  *
@@ -105,12 +113,15 @@ export interface AuthAdapterCapabilities {
105
113
  /** Supports passwordless magic link login. */
106
114
  magicLink: boolean;
107
115
  /**
108
- * Whether `POST /auth/anonymous` will mint a credential-less session.
116
+ * Supports passwordless sign-in with a six-digit code sent by email.
109
117
  *
110
- * Optional so an external adapter that predates the key keeps typechecking;
111
- * absent means "this adapter does not offer anonymous sign-in".
118
+ * Optional so that an external adapter written before this existed still
119
+ * satisfies the interface; absent reads as "no", which is what an adapter
120
+ * that has never heard of the flow means.
112
121
  */
113
- anonymousLogin?: boolean;
122
+ emailOtp?: boolean;
123
+ /** Whether `POST /auth/anonymous` will mint a credential-less session. */
124
+ anonymousLogin: boolean;
114
125
  /** List of enabled OAuth provider IDs (e.g. `["google", "github"]`). */
115
126
  enabledProviders: string[];
116
127
  /**
@@ -124,8 +135,6 @@ export interface AuthAdapterCapabilities {
124
135
  * Only applicable for built-in auth.
125
136
  */
126
137
  needsSetup?: boolean;
127
- /** Whether new user registration is enabled (may differ from `registration` capability at runtime). */
128
- registrationEnabled?: boolean;
129
138
  }
130
139
  /**
131
140
  * Options for paginated user listing.
@@ -284,7 +293,7 @@ export interface TransformAuthResponseContext {
284
293
  /** The authenticated user's ID. */
285
294
  uid: string;
286
295
  /** The auth method that triggered this response. */
287
- method: "login" | "register" | "oauth" | "refresh" | "anonymous" | "magic-link" | "mfa";
296
+ method: "login" | "register" | "oauth" | "refresh" | "anonymous" | "magic-link" | "otp" | "mfa";
288
297
  /** The raw HTTP request (for reading headers, IP, etc.). */
289
298
  request: Request;
290
299
  }
@@ -1,9 +1,10 @@
1
- import type { CollectionConfig, FilterValues, WhereFilterOp } from "./collections";
2
- import type { OrderByTuple } from "./filter-operators";
3
- import type { LogicalCondition } from "../controllers/data";
4
- import type { AuthAdapter } from "./auth_adapter";
5
- import type { HistoryConfig } from "../controllers/client";
6
- import type { ChannelBusSetting } from "./channel_bus";
1
+ import type { CollectionConfig, FilterValues, WhereFilterOp } from "./collections.js";
2
+ import type { OrderByTuple } from "./filter-operators.js";
3
+ import type { LogicalCondition } from "../controllers/data.js";
4
+ import type { AuthAdapter } from "./auth_adapter.js";
5
+ import type { HistoryConfig } from "../controllers/client.js";
6
+ import type { ChannelBusSetting } from "./channel_bus.js";
7
+ import type { SchemaEditingAdmin } from "./schema_editing.js";
7
8
  /**
8
9
  * Abstract database connection interface.
9
10
  * Represents a connection to any database system.
@@ -433,7 +434,19 @@ export interface BranchAdmin {
433
434
  *
434
435
  * @group Admin
435
436
  */
436
- export type DatabaseAdmin = Partial<SQLAdmin> & Partial<DocumentAdmin> & Partial<SchemaAdmin> & Partial<BranchAdmin>;
437
+ export type DatabaseAdmin = Partial<SQLAdmin> & Partial<DocumentAdmin> & Partial<SchemaAdmin> & Partial<BranchAdmin> & Partial<SchemaEditingAdmin>;
438
+ /**
439
+ * Type guard: can this admin plan a live schema change?
440
+ *
441
+ * Planning is engine-specific — it renders DDL, a Drizzle schema and the
442
+ * declarative SQL artifacts — so the implementation lives in the driver
443
+ * package. The server detects the capability structurally, exactly as it does
444
+ * for SQL, rather than importing an engine it is supposed to know nothing
445
+ * about.
446
+ *
447
+ * @group Admin
448
+ */
449
+ export declare function isSchemaEditingAdmin(admin: DatabaseAdmin | undefined): admin is SchemaEditingAdmin;
437
450
  /**
438
451
  * Type guard: does this admin support SQL operations?
439
452
  * @group Admin
@@ -697,7 +710,7 @@ export interface BackendBootstrapper {
697
710
  /**
698
711
  * Initialize WebSocket server for realtime operations.
699
712
  */
700
- initializeWebsockets?(server: unknown, realtimeService: RealtimeProvider, driver: import("../controllers/data_driver").DataDriver, config?: unknown, authAdapter?: AuthAdapter): Promise<void> | void;
713
+ initializeWebsockets?(server: unknown, realtimeService: RealtimeProvider, driver: import("../controllers/data_driver.js").DataDriver, config?: unknown, authAdapter?: AuthAdapter): Promise<void> | void;
701
714
  }
702
715
  /**
703
716
  * Result of `BackendBootstrapper.initializeDriver()`.
@@ -705,7 +718,7 @@ export interface BackendBootstrapper {
705
718
  */
706
719
  export interface InitializedDriver {
707
720
  /** The DataDriver instance, ready for use. */
708
- driver: import("../controllers/data_driver").DataDriver;
721
+ driver: import("../controllers/data_driver.js").DataDriver;
709
722
  /** The realtime service, if the driver created one during init. */
710
723
  realtimeProvider?: RealtimeProvider;
711
724
  /** A collection registry to register schema / tables into. */
@@ -716,7 +729,7 @@ export interface InitializedDriver {
716
729
  * Set by drivers that introspect in `baas` mode; the server serves these
717
730
  * instead of collections loaded from config files.
718
731
  */
719
- collections?: import("./collections").CollectionConfig[];
732
+ collections?: import("./collections.js").CollectionConfig[];
720
733
  /** The underlying database connection (for lifecycle management). */
721
734
  connection?: DatabaseConnection;
722
735
  /**
@@ -1,4 +1,4 @@
1
- import type { CollectionConfig } from "./collections";
1
+ import type { CollectionConfig } from "./collections.js";
2
2
  /**
3
3
  * Serializing collections so they survive a network hop.
4
4
  *
@@ -1,9 +1,10 @@
1
- import type { CollectionCallbacks } from "./entity_callbacks";
2
- import type { Properties, PostgresProperties, FirebaseProperties, MongoProperties } from "./properties";
3
- import type { User } from "../users";
4
- import type { Relation } from "./relations";
5
- import type { SecurityRule } from "./security_rules";
6
- import type { SearchConfig } from "./search";
1
+ import type { CollectionCallbacks } from "./entity_callbacks.js";
2
+ import type { Properties, PostgresProperties, FirebaseProperties, MongoProperties } from "./properties.js";
3
+ import type { User } from "../users/index.js";
4
+ import type { EmailSendResult } from "../controllers/email.js";
5
+ import type { Relation } from "./relations.js";
6
+ import type { SecurityRule } from "./security_rules.js";
7
+ import type { SearchConfig } from "./search.js";
7
8
  /**
8
9
  * Base interface containing all driver-agnostic collection properties.
9
10
  * Use {@link PostgresCollectionConfig} or {@link FirebaseCollectionConfig} for
@@ -475,7 +476,7 @@ export interface EntityChildView<M extends Record<string, unknown> = Record<stri
475
476
  collection: CollectionConfig<M>;
476
477
  source: ChildViewSource;
477
478
  }
478
- export type { WhereFilterOp, FilterValues, WireFilterValues, FilterPreset } from "./filter-operators";
479
+ export type { WhereFilterOp, FilterValues, WireFilterValues, FilterPreset } from "./filter-operators.js";
479
480
  export type InferCollectionConfigType<S extends CollectionConfig> = S extends CollectionConfig<infer M> ? M : never;
480
481
  /**
481
482
  * Configuration for authentication collections.
@@ -557,13 +558,19 @@ export interface AuthCollectionConfig {
557
558
  export interface AuthCollectionContext {
558
559
  /** Hash a password using the configured algorithm (scrypt by default). */
559
560
  hashPassword: (password: string) => Promise<string>;
560
- /** Send an email. Only available when email service is configured. */
561
+ /**
562
+ * Send an email. Only available when email service is configured.
563
+ *
564
+ * Resolves with what the provider reported — the assigned Message-ID, most
565
+ * usefully — so a hook that sends a message can store the id and later
566
+ * thread a reply back to it. Callers that do not care may ignore it.
567
+ */
561
568
  sendEmail?: (options: {
562
569
  to: string;
563
570
  subject: string;
564
571
  html: string;
565
572
  text?: string;
566
- }) => Promise<void>;
573
+ }) => Promise<EmailSendResult>;
567
574
  /** Whether the email service is configured and available. */
568
575
  emailConfigured: boolean;
569
576
  /** The app name from email config (for templates). */
@@ -2,8 +2,9 @@
2
2
  * How a collection points at a UI component without the backend learning about React.
3
3
  *
4
4
  * This file is the hinge the BaaS/admin split turns on. `ComponentRef` is named
5
- * by `properties.ts` (`ui.Field`, `ui.Preview`, `ui.Filter`), and `properties.ts`
6
- * must stay in the React-free core because every backend subsystem — validation,
5
+ * by a property's `admin` block (`admin.Field`, `admin.Preview`, `admin.Filter`)
6
+ * and imported by `properties.ts`, which must stay in the React-free core
7
+ * because every backend subsystem — validation,
7
8
  * the drizzle schema generator, the OpenAPI generator, the SDK codegen — reads
8
9
  * property definitions. If `ComponentRef` needed `React.ComponentType`, the whole
9
10
  * property model would have to move to the admin layer with it.
@@ -1,5 +1,4 @@
1
- import type { RebaseServerClient } from "../controllers/client";
2
- import type { RebaseSdkData } from "../controllers/data";
1
+ import type { RebaseServerClient } from "../controllers/client.js";
3
2
  /**
4
3
  * Cron Job type definitions for Rebase.
5
4
  *
@@ -107,29 +106,6 @@ export interface CronJobContext {
107
106
  * });
108
107
  */
109
108
  rebase: RebaseServerClient;
110
- /**
111
- * The same object as {@link rebase}, under the name this context used
112
- * before.
113
- *
114
- * @deprecated Use `rebase` instead. Two things made the old name a problem,
115
- * and neither was cosmetic. It contradicted every other server surface,
116
- * where the singleton is `rebase` — the previous docstring had to end with
117
- * *"it is only named `client` here"*. And typing it as `RebaseClient`
118
- * re-exposed `client.data`, the alias that {@link RebaseServerClient}
119
- * deliberately `Omit`s so the RLS-bypassing plane has exactly one name and
120
- * the privilege is visible at the call site. A reader who learned
121
- * `client.data` here carried it to a collection callback, where
122
- * `context.data` is the *user-scoped* plane — same spelling, opposite
123
- * privilege.
124
- *
125
- * Still the full server client at runtime, and `data` still resolves, so
126
- * existing cron files keep working and keep compiling. It will be removed
127
- * in the next major.
128
- */
129
- client: RebaseServerClient & {
130
- /** @deprecated Use `rebase.dataAsAdmin` — the name states the privilege. */
131
- data: RebaseSdkData;
132
- };
133
109
  }
134
110
  export type CronJobRunState = "idle" | "running" | "success" | "error" | "disabled";
135
111
  /**
@@ -1,4 +1,4 @@
1
- import { WhereFilterOp } from "./filter-operators";
1
+ import { WhereFilterOp } from "./filter-operators.js";
2
2
  /**
3
3
  * Describes the capabilities and features supported by a data source (driver).
4
4
  *
@@ -19,10 +19,10 @@
19
19
  *
20
20
  * @group Backend
21
21
  */
22
- import type { DataDriver } from "../controllers/data_driver";
23
- import type { CollectionConfig } from "./collections";
24
- import type { CollectionRegistryInterface, DatabaseAdmin, InitializedDriver, RealtimeProvider, BootstrappedAuth } from "./backend";
25
- import type { HistoryConfig } from "../controllers/client";
22
+ import type { DataDriver } from "../controllers/data_driver.js";
23
+ import type { CollectionConfig } from "./collections.js";
24
+ import type { CollectionRegistryInterface, DatabaseAdmin, InitializedDriver, RealtimeProvider, BootstrappedAuth } from "./backend.js";
25
+ import type { HistoryConfig } from "../controllers/client.js";
26
26
  /**
27
27
  * A `DatabaseAdapter` provides data persistence for Rebase.
28
28
  *
@@ -74,7 +74,7 @@ export interface DatabaseAdapter {
74
74
  * here — turning an adapter-authenticated server's socket into one that
75
75
  * accepted every client as already authenticated.
76
76
  */
77
- initializeWebsockets?(server: unknown, realtimeService: RealtimeProvider, driver: DataDriver, config?: unknown, adapter?: import("./auth_adapter").AuthAdapter): Promise<void> | void;
77
+ initializeWebsockets?(server: unknown, realtimeService: RealtimeProvider, driver: DataDriver, config?: unknown, adapter?: import("./auth_adapter.js").AuthAdapter): Promise<void> | void;
78
78
  /**
79
79
  * Bring the database's collection tables up to date, additively — the boot
80
80
  * companion to `db push`. See `BackendBootstrapper.ensureCollectionSchema`
@@ -1,4 +1,4 @@
1
- import type { SearchMatch } from "./search";
1
+ import type { SearchMatch } from "./search.js";
2
2
  /**
3
3
  * New or existing status
4
4
  * @group Models
@@ -1,7 +1,7 @@
1
- import type { CollectionConfig } from "./collections";
2
- import type { EntityStatus, EntityValues } from "./entities";
3
- import type { User } from "../users";
4
- import type { RebaseCallContext } from "../call_context";
1
+ import type { CollectionConfig } from "./collections.js";
2
+ import type { EntityStatus, EntityValues } from "./entities.js";
3
+ import type { User } from "../users/index.js";
4
+ import type { RebaseCallContext } from "../call_context.js";
5
5
  /**
6
6
  * Lifecycle callbacks for entity CRUD operations.
7
7
  *
@@ -1,29 +1,32 @@
1
- export * from "./entities";
2
- export * from "./filter-operators";
3
- export * from "./chips";
4
- export * from "./properties";
5
- export * from "./admin_block";
6
- export * from "./collections";
7
- export * from "./search";
8
- export * from "./relations";
9
- export * from "./policy";
10
- export * from "./rls-functions";
11
- export * from "./security_rules";
12
- export * from "./entity_callbacks";
13
- export * from "./websockets";
14
- export * from "./backend";
15
- export * from "./channel_bus";
16
- export * from "./data_source";
17
- export * from "./storage_source";
18
- export * from "./cron";
19
- export * from "./backup";
20
- export * from "./component_ref";
21
- export * from "./auth_adapter";
22
- export * from "./database_adapter";
23
- export * from "./api_keys";
24
- export * from "./history";
25
- export * from "./postgres_introspection";
26
- export * from "./project_manifest";
27
- export * from "./collection_contract";
28
- export * from "./schema_version";
29
- export * from "./storage_authorize";
1
+ export * from "./entities.js";
2
+ export * from "./filter-operators.js";
3
+ export * from "./chips.js";
4
+ export * from "./properties.js";
5
+ export * from "./admin_block.js";
6
+ export * from "./collections.js";
7
+ export * from "./search.js";
8
+ export * from "./relations.js";
9
+ export * from "./policy.js";
10
+ export * from "./rls-functions.js";
11
+ export * from "./security_rules.js";
12
+ export * from "./entity_callbacks.js";
13
+ export * from "./websockets.js";
14
+ export * from "./backend.js";
15
+ export * from "./schema_editing.js";
16
+ export * from "./channel_bus.js";
17
+ export * from "./data_source.js";
18
+ export * from "./resources.js";
19
+ export * from "./resource_kinds.js";
20
+ export * from "./storage_source.js";
21
+ export * from "./cron.js";
22
+ export * from "./backup.js";
23
+ export * from "./component_ref.js";
24
+ export * from "./auth_adapter.js";
25
+ export * from "./database_adapter.js";
26
+ export * from "./api_keys.js";
27
+ export * from "./history.js";
28
+ export * from "./postgres_introspection.js";
29
+ export * from "./project_manifest.js";
30
+ export * from "./collection_contract.js";
31
+ export * from "./schema_version.js";
32
+ export * from "./storage_authorize.js";
@@ -24,7 +24,8 @@
24
24
  * work: two repositories never need to know about each other, only about the
25
25
  * project.
26
26
  */
27
- import type { StorageSourceDefinition } from "./storage_source";
27
+ import type { StorageSourceDefinition } from "./storage_source.js";
28
+ import type { ResourceGraph } from "./resources.js";
28
29
  /**
29
30
  * Which kind of thing an app is.
30
31
  *
@@ -58,7 +59,7 @@ export interface RebaseBackendAppConfig {
58
59
  *
59
60
  * Independent of *where* it runs. Both run on Rebase Cloud and both
60
61
  * self-host — the destination lives in `.rebase/cloud.json`, not here. See
61
- * `docker/docker-compose.selfhost.yml`, which boots a managed bundle on a
62
+ * `infra/docker/docker-compose.selfhost.yml`, which boots a managed bundle on a
62
63
  * developer's own Docker host.
63
64
  *
64
65
  * This is authored rather than inferred on purpose. It is the single most
@@ -125,6 +126,31 @@ export interface RebaseStaticAppConfig {
125
126
  spa?: boolean;
126
127
  }
127
128
  export type RebaseAppConfig = RebaseBackendAppConfig | RebaseStaticAppConfig;
129
+ /**
130
+ * Path prefixes the backend owns, which no static app may claim.
131
+ *
132
+ * One process — and, on the platform, one hostname — serves both the API and
133
+ * however many static apps a project has. Mounting is longest-path-first, so an
134
+ * app declaring `/api` would win against the API itself and every request to it
135
+ * would be answered with that app's `index.html`: a 200 carrying HTML where the
136
+ * caller expected JSON, from a project that looks deployed and healthy.
137
+ *
138
+ * Declared here rather than in either enforcer because both must agree. The CLI
139
+ * checks it so a developer finds out while editing `rebase.json`; the control
140
+ * plane checks it again at deploy intake, because the front door's correctness
141
+ * cannot rest on a check that ran in somebody else's CLI — and a repository can
142
+ * be deployed by a CLI older than this rule.
143
+ */
144
+ export declare const RESERVED_BACKEND_PREFIXES: readonly ["/api", "/health", "/healthz", "/livez", "/readyz", "/metrics"];
145
+ /**
146
+ * Whether `path` collides with a prefix the backend owns.
147
+ *
148
+ * Compares at segment boundaries, so `/api` and `/api/v2` collide while
149
+ * `/apidocs` does not — the same rule the router matches with, because a check
150
+ * that is stricter than the router rejects paths that would have worked, and one
151
+ * that is looser admits paths that will not.
152
+ */
153
+ export declare function reservedPrefixFor(path: string): string | undefined;
128
154
  /**
129
155
  * One declared storage source, as authored in `rebase.json`.
130
156
  *
@@ -171,27 +197,20 @@ export interface RebaseProjectManifest {
171
197
  */
172
198
  apps: Record<string, RebaseAppConfig>;
173
199
  /**
174
- * Storage sources this project uses, keyed by source key.
200
+ * Buckets are NOT declared here any more.
175
201
  *
176
- * **Topology only — never credentials.** Which buckets exist is a property of
177
- * the project and belongs in the repository; how to reach each one is a
178
- * property of the deployment and lives in the environment, read per source
179
- * from `<BASE>__<KEY>` (`S3_BUCKET__MEDIA` for a source keyed `media`). The
180
- * default source takes no suffix, so a single-bucket project configured with
181
- * plain `S3_BUCKET` keeps working having declared nothing at all.
202
+ * They were, and the runtime merged this block with the declarations in
203
+ * config code — a bucket named in both had one engine kept and the other
204
+ * silently discarded. Two homes for one concept, with a merge to decide
205
+ * between them, is the shape this whole model replaced.
182
206
  *
183
- * Declared here rather than only in the config package because this file is
184
- * the one artifact a host can read *before* running a build. That is what
185
- * lets a console show "this project wants a `media` bucket, and it has none"
186
- * on a project's first deploy, and it is why the managed and custom runtimes
187
- * can present the same list — a custom build emits no bundle manifest, so a
188
- * declaration that lived only in compiled config would leave every custom
189
- * project invisible.
190
- *
191
- * Omitted entirely means one default source, which is the overwhelmingly
192
- * common project and must not be required to say so.
207
+ * `bucket("media", { engine: "s3" })` in the project's config declares one
208
+ * now, and `rebase resources --write` generates `rebase.resources.json`,
209
+ * which is what a host reads before a build. A `storage` block left in this
210
+ * file is refused by the validator, by name, with the replacement in the
211
+ * message — not ignored, because a key that still parses and does nothing
212
+ * is the failure this removed.
193
213
  */
194
- storage?: Record<string, RebaseStorageSourceConfig>;
195
214
  /**
196
215
  * Repository-wide opt-out from anonymous CLI usage sharing.
197
216
  *
@@ -263,6 +282,31 @@ export declare const BUNDLE_FORMAT_VERSION = 2;
263
282
  * any number of minors and patches while this stays put. It changes only when
264
283
  * the bundle/runtime contract breaks compatibility, and a project's
265
284
  * `manifest.runtime` range is matched against *this*.
285
+ *
286
+ * ## v2 — resources are declared, not configured
287
+ *
288
+ * `RebaseBackendConfig.dataSources` and `.storageSources` are gone. A project
289
+ * declares its databases and buckets with `database()` / `bucket()` in its
290
+ * config, and the runtime reads those declarations.
291
+ *
292
+ * This had to be a major, and the reason is the managed tier: it moves projects
293
+ * onto new images WITHOUT rebuilding them. A bundle built against v1 exports
294
+ * those keys, and a v2 runtime refuses them at boot — so without this bump, one
295
+ * image rollout would crash-loop every tenant that had ever declared a second
296
+ * database or bucket, in a wave, with the cause in a container log nobody is
297
+ * watching.
298
+ *
299
+ * With the bump, a v1 bundle on a v2 runtime is refused by
300
+ * `assertBundleCompatibility` with the remedy in the message, and the platform
301
+ * keeps it on a v1 image until it is rebuilt. That is the whole purpose of this
302
+ * number.
303
+ *
304
+ * **Release order matters and is not optional.** The control plane is the side
305
+ * that rejects, so it ships FIRST: raise `SUPPORTED_RUNTIME_CONTRACT` in the
306
+ * saas repo (it rejects only `contract >` its own, so it then accepts both),
307
+ * deploy that, and only then release a runtime implementing v2. Shipping the
308
+ * runtime first turns every deploy into a rejected intake blaming the tenant's
309
+ * bundle.
266
310
  */
267
311
  export declare const RUNTIME_CONTRACT_VERSION = 1;
268
312
  /** Where the runtime finds each part of the bundle. Paths are bundle-relative. */
@@ -313,6 +357,35 @@ export interface NativeDependency {
313
357
  * `manifest.json` — generated, and the document the runtime and control plane
314
358
  * both validate against.
315
359
  */
360
+ /**
361
+ * One custom function, as recorded in a built bundle.
362
+ *
363
+ * @see RebaseBundleManifest.functions
364
+ */
365
+ export interface RebaseBundleFunction {
366
+ /**
367
+ * The filename without its extension — which is also the URL segment it
368
+ * mounts at (`/api/functions/<name>`), the API-key permission that grants
369
+ * it, and the name `REBASE_FUNCTIONS_ONLY` selects by. One identity, used
370
+ * everywhere.
371
+ */
372
+ name: string;
373
+ /** Path inside the bundle, so a host can point at the file. */
374
+ file: string;
375
+ /**
376
+ * `false` when the function's own source imports a Node built-in or a
377
+ * package that needs one.
378
+ *
379
+ * Descriptive, never a gate: nothing refuses to build or deploy on this. It
380
+ * says where this function *could* run, not where it should.
381
+ */
382
+ portable: boolean;
383
+ /**
384
+ * Why it is not portable — one short phrase per reason, deduplicated.
385
+ * Absent when it is.
386
+ */
387
+ requires?: string[];
388
+ }
316
389
  export interface RebaseBundleManifest {
317
390
  /** @see BUNDLE_FORMAT_VERSION */
318
391
  bundleFormat: number;
@@ -353,6 +426,28 @@ export interface RebaseBundleManifest {
353
426
  entry: RebaseBundleEntrypoints;
354
427
  /** Collection slugs contained in the bundle, for quick inspection. */
355
428
  collections?: string[];
429
+ /**
430
+ * Every custom function in the bundle, named and classified.
431
+ *
432
+ * Two things are recorded per function, and both are answers a host would
433
+ * otherwise have to get by importing user code:
434
+ *
435
+ * - **What it is called.** That name is the function's identity everywhere —
436
+ * the URL segment it mounts at, the `functions/<name>` API-key
437
+ * permission, the value `REBASE_FUNCTIONS_ONLY` selects by. A host that
438
+ * wants to give one slow function its own replica count currently has to
439
+ * boot the bundle to discover what is in it.
440
+ * - **Whether it needs Node.** Purely descriptive: a function that opens a
441
+ * file or runs raw SQL is a fine function, and every deployment today is
442
+ * a Node process. It is recorded because the question "which of these
443
+ * could run somewhere else" has to be answerable from the artifact, and
444
+ * because answering it per-file after the fact — across a codebase
445
+ * already written — is the expensive version of the same question.
446
+ *
447
+ * Absent on a bundle built before this field existed, which is why every
448
+ * consumer must treat it as optional rather than as an empty list.
449
+ */
450
+ functions?: RebaseBundleFunction[];
356
451
  hooks: {
357
452
  /**
358
453
  * Whether the dependency closure contains native code.
@@ -381,17 +476,27 @@ export interface RebaseBundleManifest {
381
476
  /** Whether the config package exports a `storageAuthorize` hook. */
382
477
  authorize: boolean;
383
478
  /**
384
- * Every storage source this bundle expects, resolved at build time from
385
- * `rebase.json`'s `storage` block merged with any `storageSources` the
386
- * config package exports.
479
+ * Buckets, on bundles built before {@link RebaseBundleManifest.resources}.
387
480
  *
388
- * Recorded so the runtime does not have to import user code to learn its
389
- * own topology, and so a host can tell — from the artifact alone, before
390
- * starting anything — which buckets need configuring. Absent on bundles
391
- * built before this field existed, which means one default source.
481
+ * No longer written. A host reads `resources`, which carries every kind
482
+ * in one list; this stays declared so a control plane can keep reading
483
+ * the bundles a project shipped before it was rebuilt.
392
484
  */
393
485
  sources?: StorageSourceDefinition[];
394
486
  };
487
+ /**
488
+ * Everything the project declares it needs — databases, buckets, topics,
489
+ * and whatever kind is registered next.
490
+ *
491
+ * Recorded so a host can tell, from the artifact alone and before starting
492
+ * anything, what a deploy will need provisioned. That question used to be
493
+ * answerable for buckets and for nothing else, because buckets were the
494
+ * only kind written into an artifact — which is how a project's databases
495
+ * became invisible to the platform that runs them.
496
+ *
497
+ * Absent on bundles built before this field existed.
498
+ */
499
+ resources?: ResourceGraph;
395
500
  deps: {
396
501
  /** Runtime dependencies of user code, as declared. */
397
502
  declared: Record<string, string>;