@rebasepro/server 0.10.1-canary.6f89f77 → 0.10.1-canary.7801eed

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 (36) hide show
  1. package/bin/rebase-server.js +55 -0
  2. package/dist/api/ast-schema-editor.d.ts +10 -0
  3. package/dist/api/contract-routes.d.ts +36 -0
  4. package/dist/api/rest/api-generator.d.ts +14 -0
  5. package/dist/auth/rate-limit-store.d.ts +8 -1
  6. package/dist/boot/boot.d.ts +59 -0
  7. package/dist/boot/bundle.d.ts +134 -0
  8. package/dist/boot/driver.d.ts +57 -0
  9. package/dist/boot/env.d.ts +129 -0
  10. package/dist/boot/options.d.ts +20 -0
  11. package/dist/boot/sources.d.ts +77 -0
  12. package/dist/chunk-DSJWtz9O.js +40 -0
  13. package/dist/index.d.ts +15 -0
  14. package/dist/index.es.js +3360 -4689
  15. package/dist/index.es.js.map +1 -1
  16. package/dist/init/health.d.ts +11 -2
  17. package/dist/init/middlewares.d.ts +9 -0
  18. package/dist/init.d.ts +19 -0
  19. package/dist/{jwt-Dj7r7QX7.js → jwt-D-eI6TTu.js} +4 -39
  20. package/dist/{jwt-Dj7r7QX7.js.map → jwt-D-eI6TTu.js.map} +1 -1
  21. package/dist/metrics/index.d.ts +83 -0
  22. package/dist/{openapi-generator-DqSIwNLV.js → openapi-generator-CeOnlAJ3.js} +12 -14
  23. package/dist/openapi-generator-CeOnlAJ3.js.map +1 -0
  24. package/dist/{schema-editor-routes-D3ef8zu1.js → schema-editor-routes-BFpXKkPD.js} +30 -2
  25. package/dist/schema-editor-routes-BFpXKkPD.js.map +1 -0
  26. package/dist/{src-CsHhSKbi.js → src-BYbxB4PR.js} +282 -2
  27. package/dist/src-BYbxB4PR.js.map +1 -0
  28. package/dist/src-q6_elgGZ.js +3183 -0
  29. package/dist/src-q6_elgGZ.js.map +1 -0
  30. package/dist/storage/routes.d.ts +9 -1
  31. package/dist/storage/types.d.ts +1 -32
  32. package/dist/utils/dev-port.d.ts +5 -2
  33. package/package.json +12 -11
  34. package/dist/openapi-generator-DqSIwNLV.js.map +0 -1
  35. package/dist/schema-editor-routes-D3ef8zu1.js.map +0 -1
  36. package/dist/src-CsHhSKbi.js.map +0 -1
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The Rebase runtime entrypoint.
4
+ *
5
+ * Runs a built project bundle. This is what the official `rebasepro/server`
6
+ * container image executes, and what a self-hosted deployment runs directly:
7
+ *
8
+ * rebase-server ./dist-bundle
9
+ * REBASE_BUNDLE=/bundle rebase-server
10
+ *
11
+ * The bundle is the project; this process is the engine. Keeping them separate
12
+ * is what allows the engine to be upgraded — a security patch, a performance
13
+ * fix — without rebuilding anyone's application.
14
+ */
15
+ import { runFromBundle } from "../dist/index.es.js";
16
+
17
+ const args = process.argv.slice(2);
18
+
19
+ if (args[0] === "--help" || args[0] === "-h") {
20
+ console.log(`
21
+ rebase-server — run a built Rebase project bundle
22
+
23
+ Usage:
24
+ rebase-server [bundle-dir]
25
+
26
+ Arguments:
27
+ bundle-dir Path to the bundle. Defaults to $REBASE_BUNDLE, then ./dist-bundle
28
+
29
+ Key environment variables:
30
+ DATABASE_URL Connection string for the default database (required)
31
+ JWT_SECRET Signing secret, >=32 chars (required in production)
32
+ PORT Port to bind (default 3001)
33
+ CORS_ORIGINS Comma-separated allowed origins (required in production)
34
+ REBASE_METRICS "true" to expose Prometheus metrics at /metrics
35
+ REBASE_MIGRATE_ON_BOOT none | ensure (collection tables: run 'rebase db push')
36
+
37
+ Additional databases and buckets are configured by suffixing the variable with
38
+ the source key, e.g. DATABASE_URL__ANALYTICS or S3_BUCKET__MEDIA.
39
+
40
+ Docs: https://rebase.pro/docs/deployment/self-hosting/
41
+ `.trim());
42
+ process.exit(0);
43
+ }
44
+
45
+ if (args[0] === "--version" || args[0] === "-v") {
46
+ const { readFileSync } = await import("node:fs");
47
+ const { fileURLToPath } = await import("node:url");
48
+ const { dirname, join } = await import("node:path");
49
+ const here = dirname(fileURLToPath(import.meta.url));
50
+ const pkg = JSON.parse(readFileSync(join(here, "..", "package.json"), "utf8"));
51
+ console.log(pkg.version);
52
+ process.exit(0);
53
+ }
54
+
55
+ await runFromBundle({ bundleDir: args[0] });
@@ -1,3 +1,13 @@
1
+ /**
2
+ * Move presentation keys into the `admin` block.
3
+ *
4
+ * `ADMIN_COLLECTION_KEYS` comes from `@rebasepro/types` rather than being spelled
5
+ * out here, so adding a field to `AdminCollectionOptions` cannot leave this writer
6
+ * behind. Any such key already inside `admin` wins over a top-level copy: the
7
+ * nested one is what the file said, and a flat duplicate is the view model's
8
+ * flattening leaking back.
9
+ */
10
+ export declare function nestAdminKeys(collectionData: Record<string, unknown>): Record<string, unknown>;
1
11
  export declare class AstSchemaEditor {
2
12
  private project;
3
13
  private collectionsDir;
@@ -0,0 +1,36 @@
1
+ import { Hono } from "hono";
2
+ import { type CollectionConfig } from "@rebasepro/types";
3
+ import type { HonoEnv } from "./types";
4
+ /**
5
+ * The project contract endpoint.
6
+ *
7
+ * This is what makes a repository able to build against a project it does not
8
+ * contain. Without it, a typed client can only be generated from local
9
+ * collection *source*, which means every frontend must live in the same
10
+ * repository as the backend. Serving the contract turns that around: an app
11
+ * asks the project what its shape is, so a web app, a second web app and a
12
+ * mobile app can each live wherever they like and none of them needs to know
13
+ * about the others.
14
+ *
15
+ * Admin-gated. Collection definitions describe every table, column and relation
16
+ * in the project, including ones no security rule would ever expose — that is a
17
+ * map of the database, not public API documentation.
18
+ */
19
+ export interface ContractRoutesConfig {
20
+ collectionRegistry: {
21
+ getRawCollections(): CollectionConfig[];
22
+ };
23
+ /**
24
+ * The schema version recorded at build time.
25
+ *
26
+ * Preferred over recomputing, so that what a client is told matches exactly
27
+ * what the bundle claims. It is recomputed only when a bundle did not record
28
+ * one — a `baas`-mode project derives its collections from the live database
29
+ * at boot, so there was nothing to hash when it was built.
30
+ */
31
+ schemaVersion?: string;
32
+ mode: "cms" | "baas";
33
+ /** Runtime package version, surfaced so a client can report what it built against. */
34
+ runtimeVersion?: string;
35
+ }
36
+ export declare function createContractRoutes(config: ContractRoutesConfig): Hono<HonoEnv>;
@@ -41,6 +41,20 @@ export declare class RestApiGenerator {
41
41
  * slug, never an id.
42
42
  */
43
43
  private enforceSubcollectionApiKeyPermission;
44
+ /**
45
+ * The collection a nested path writes into — the target of the relation its
46
+ * last segment names.
47
+ *
48
+ * Needed so a nested write can be checked against a schema at all. Without
49
+ * it these routes skipped `assertKnownWriteFields` entirely, which is why a
50
+ * typo `POST /posts` rejected with a 400 while the same typo on
51
+ * `POST /authors/1/posts` reached the database.
52
+ *
53
+ * Returns `undefined` rather than throwing when the path cannot be walked:
54
+ * the driver raises the authoritative error a moment later, and duplicating
55
+ * it here would report a resolution failure as a validation failure.
56
+ */
57
+ private resolveNestedWriteCollection;
44
58
  /**
45
59
  * Get the request-scoped driver. Throws if none is set — never falls
46
60
  * back to the unscoped `this.driver` to avoid bypassing RLS/auth.
@@ -42,7 +42,14 @@ export interface RateLimitStore {
42
42
  export declare class MemoryRateLimitStore implements RateLimitStore {
43
43
  private store;
44
44
  private cleanupInterval?;
45
- constructor(sweepMs?: number);
45
+ private now;
46
+ /**
47
+ * `now` exists so the window can be driven directly instead of by sleeping:
48
+ * a test that waits half a real window is a test that fails on a loaded
49
+ * machine, where the sleep overruns and the hits it expects to still be in
50
+ * the window have left it.
51
+ */
52
+ constructor(sweepMs?: number, now?: () => number);
46
53
  hit(key: string, windowMs: number, limit: number): Promise<RateLimitDecision>;
47
54
  private sweep;
48
55
  dispose(): void;
@@ -0,0 +1,59 @@
1
+ import { type Server } from "http";
2
+ import { Hono } from "hono";
3
+ import { type RebaseBackendInstance } from "../init";
4
+ import type { HonoEnv } from "../api/types";
5
+ import { type RebaseBootEnv } from "./env";
6
+ import { type LoadedBundle } from "./bundle";
7
+ import { type InitializedDataSource } from "./driver";
8
+ /** A running runtime, and the handle to stop it. */
9
+ export interface BootedRuntime {
10
+ app: Hono<HonoEnv>;
11
+ server: Server;
12
+ backend: RebaseBackendInstance;
13
+ bundle: LoadedBundle;
14
+ env: RebaseBootEnv;
15
+ /** The port actually bound, which in development may not be the one asked for. */
16
+ port: number;
17
+ dataSources: InitializedDataSource[];
18
+ shutdown: () => Promise<void>;
19
+ }
20
+ export interface BootOptions {
21
+ /** Bundle directory. Defaults to `REBASE_BUNDLE` or `./dist-bundle`. */
22
+ bundleDir?: string;
23
+ /**
24
+ * A bundle that has already been resolved.
25
+ *
26
+ * `rebase dev` passes one built from source (see `createSourceBundle`), so
27
+ * development and production run the identical boot path rather than two
28
+ * implementations that drift apart.
29
+ */
30
+ bundle?: LoadedBundle;
31
+ /** Skip binding a port. Used by tests that drive `app.fetch` directly. */
32
+ listen?: boolean;
33
+ /** Install SIGTERM/SIGINT handlers. Off for tests. */
34
+ handleSignals?: boolean;
35
+ }
36
+ /**
37
+ * Boot a Rebase runtime from a built bundle.
38
+ *
39
+ * This is the entrypoint the official container image runs, and it is the same
40
+ * code path a self-hosted deployment uses — there is no separate "platform"
41
+ * runtime. Everything it does was previously the responsibility of a
42
+ * hand-written `backend/src/index.ts` in every project: wiring CORS and security
43
+ * headers, opening database connections, resolving storage, mounting health and
44
+ * metrics, serving the client bundle, and shutting all of it down cleanly.
45
+ *
46
+ * Moving it here is what makes a project's *code* separable from the *engine*
47
+ * that runs it: the bundle can then be handed to a newer runtime without being
48
+ * rebuilt, which is the precondition for patching a fleet.
49
+ */
50
+ export declare function bootFromBundle(options?: BootOptions): Promise<BootedRuntime>;
51
+ /**
52
+ * Boot and keep running, reporting failures the way a container should.
53
+ *
54
+ * A `BundleError` is a configuration problem with a known fix, so it prints the
55
+ * message and its hint without a stack trace — the stack is noise when the
56
+ * answer is "set DATABASE_URL". Anything else keeps its stack, because it is a
57
+ * bug and the trace is the point.
58
+ */
59
+ export declare function runFromBundle(options?: BootOptions): Promise<BootedRuntime>;
@@ -0,0 +1,134 @@
1
+ import { type CollectionConfig, type CollectionCallbacks, type DataSourceDefinition, type RebaseBundleManifest, type StorageSourceDefinition } from "@rebasepro/types";
2
+ import type { StorageAuthorize } from "../storage/types";
3
+ /** Thrown when a bundle cannot be read, or claims a contract this runtime cannot honour. */
4
+ export declare class BundleError extends Error {
5
+ readonly hint?: string | undefined;
6
+ constructor(message: string, hint?: string | undefined);
7
+ }
8
+ /** A bundle that has been located and whose manifest has been validated. */
9
+ export interface LoadedBundle {
10
+ dir: string;
11
+ manifest: RebaseBundleManifest;
12
+ /** Absolute path to the compiled collections directory, when present. */
13
+ collectionsDir?: string;
14
+ functionsDir?: string;
15
+ cronsDir?: string;
16
+ /** Absolute path to built admin assets, when the admin panel is bundled. */
17
+ adminDir?: string;
18
+ /** Absolute path to built static assets to serve from this process. */
19
+ staticDir?: string;
20
+ }
21
+ /**
22
+ * Read and validate a bundle's manifest.
23
+ *
24
+ * The checks here are the runtime half of the compatibility contract, and they
25
+ * all fail loudly at boot rather than at the first request. A container that
26
+ * refuses to start is a deploy that rolls back; a container that starts and then
27
+ * misbehaves is an incident.
28
+ */
29
+ export declare function readBundleManifest(bundleDir: string): RebaseBundleManifest;
30
+ /**
31
+ * Locate a bundle and resolve every directory the runtime needs from it.
32
+ *
33
+ * Entry paths in the manifest are bundle-relative and are resolved here, once,
34
+ * so nothing downstream has to know the layout. A declared directory that does
35
+ * not exist is dropped with a warning rather than failing the boot: an empty
36
+ * `functions/` is a perfectly ordinary project, and refusing to start over one
37
+ * would be the runtime inventing a requirement the developer never stated.
38
+ */
39
+ /**
40
+ * Resolve a bundle-relative entry, refusing anything that escapes the bundle.
41
+ *
42
+ * Applied to the entries that are `import()`ed — the schema, the config index,
43
+ * the users collection — and not only to the ones that are merely scanned. Those
44
+ * three *execute code*, so they are precisely the ones a malformed or hostile
45
+ * manifest would target, and leaving them unchecked while guarding the read-only
46
+ * paths would be defending the wrong door.
47
+ */
48
+ export declare function resolveBundlePath(bundleDir: string, entry: string, label: string): string;
49
+ export declare function loadBundle(bundleDir: string): LoadedBundle;
50
+ /**
51
+ * The Drizzle schema a bundle ships: tables, enums and relations, as generated
52
+ * from the project's collections.
53
+ */
54
+ export interface BundleSchemaExports {
55
+ tables?: Record<string, unknown>;
56
+ enums?: Record<string, unknown>;
57
+ relations?: Record<string, unknown>;
58
+ }
59
+ /**
60
+ * Import the bundle's Drizzle schema module.
61
+ *
62
+ * Returns `undefined` when the bundle declares none — `baas` mode introspects the
63
+ * live database instead of shipping a schema.
64
+ */
65
+ export declare function loadBundleSchema(bundle: LoadedBundle): Promise<BundleSchemaExports | undefined>;
66
+ /**
67
+ * Build a bundle view over a project's **source** directories.
68
+ *
69
+ * `rebase dev` runs TypeScript directly through tsx, so there is no compiled
70
+ * bundle to load — but everything downstream of loading (drivers, storage, auth,
71
+ * routes) should be identical, or development stops predicting production. This
72
+ * produces the same {@link LoadedBundle} shape from source paths, so the one boot
73
+ * path serves both.
74
+ *
75
+ * The schema version is left empty deliberately: nothing has been built, so
76
+ * there is no build-time answer, and the runtime computes one from the live
77
+ * collections instead.
78
+ */
79
+ export declare function createSourceBundle(options: {
80
+ projectRoot: string;
81
+ config?: string;
82
+ collections?: string;
83
+ functions?: string;
84
+ crons?: string;
85
+ schema?: string;
86
+ mode?: "cms" | "baas" | "static";
87
+ app?: string;
88
+ }): LoadedBundle;
89
+ /**
90
+ * Declarations a bundle's config package exports alongside its collections.
91
+ *
92
+ * These describe *topology* — which databases and which buckets exist — so they
93
+ * belong to the project rather than to the environment. The environment then
94
+ * supplies credentials for each declared key. Splitting it this way is what lets
95
+ * a deploy be validated before it runs: the set of things needing configuration
96
+ * is known from the bundle, without reading anyone's secrets.
97
+ */
98
+ export interface BundleConfigExports {
99
+ dataSources?: DataSourceDefinition[];
100
+ storageSources?: StorageSourceDefinition[];
101
+ /**
102
+ * Per-object storage access control.
103
+ *
104
+ * A function, so it can only come from the project's own code — there is no
105
+ * environment variable that could express "this user may read this key".
106
+ * Without a way to supply it, a production deployment with a bucket would be
107
+ * forced to choose between `STORAGE_PUBLIC_READ` (world-readable) and
108
+ * `STORAGE_ALLOW_ANY_AUTHENTICATED` (every signed-in user can read, overwrite
109
+ * and delete every other user's files) — the runtime would be making an
110
+ * insecure choice on the developer's behalf.
111
+ */
112
+ storageAuthorize?: StorageAuthorize;
113
+ /** Lifecycle callbacks applied to every collection. */
114
+ callbacks?: CollectionCallbacks;
115
+ }
116
+ /**
117
+ * Read the config package's `index` for declarations.
118
+ *
119
+ * Absent, empty or unreadable all mean the same thing: a single default database
120
+ * and a single default bucket. That is the overwhelmingly common project, and it
121
+ * must not be required to say so. A malformed export is reported and ignored
122
+ * rather than fatal — a typo in an optional declaration should not take down a
123
+ * server whose collections are fine.
124
+ */
125
+ export declare function loadBundleConfigExports(bundle: LoadedBundle): Promise<BundleConfigExports>;
126
+ /**
127
+ * Import the collection that backs authentication.
128
+ *
129
+ * Auth needs to know which table holds users. The bundle names the module; the
130
+ * convention (`collections/users`) covers every project that did not rename it.
131
+ * Returning `undefined` is valid — a `baas`-mode project has no config package,
132
+ * and the auth bootstrapper falls back to its own default users table.
133
+ */
134
+ export declare function loadUsersCollection(bundle: LoadedBundle): Promise<CollectionConfig | undefined>;
@@ -0,0 +1,57 @@
1
+ import type { BackendBootstrapper } from "@rebasepro/types";
2
+ import type { ResolvedDataSourceConfig } from "./sources";
3
+ /** The connection handle a driver hands back. */
4
+ export interface DatabaseConnection {
5
+ db: unknown;
6
+ /**
7
+ * Present for pool-based drivers. Closed during shutdown, and used to probe
8
+ * the source for health — `query` lives here, not on the connection itself.
9
+ */
10
+ pool?: {
11
+ end: () => Promise<void>;
12
+ query?: (sql: string) => Promise<unknown>;
13
+ };
14
+ /** Some drivers expose a query directly instead of via a pool. */
15
+ query?: (sql: string) => Promise<unknown>;
16
+ connectionString?: string;
17
+ }
18
+ /**
19
+ * Run a trivial query against a source, to see whether it answers.
20
+ *
21
+ * Returns `undefined` when the driver exposes no way to ask — a driver that
22
+ * cannot be probed must not be reported as unhealthy, only as unknown.
23
+ */
24
+ export declare function probeDataSource(source: InitializedDataSource): Promise<{
25
+ healthy: boolean;
26
+ error?: string;
27
+ } | undefined>;
28
+ /** One initialized data source: its bootstrapper plus the handle to close. */
29
+ export interface InitializedDataSource {
30
+ key: string;
31
+ engine: string;
32
+ driverPackage: string;
33
+ bootstrapper: BackendBootstrapper;
34
+ connection: DatabaseConnection;
35
+ }
36
+ export interface BundleSchema {
37
+ tables?: Record<string, unknown>;
38
+ enums?: Record<string, unknown>;
39
+ relations?: Record<string, unknown>;
40
+ }
41
+ /**
42
+ * Build a driver for one data source.
43
+ *
44
+ * Only the default source receives the bundle's Drizzle schema: the schema
45
+ * describes the tables generated from this project's collections, which live in
46
+ * the default database. Handing it to a secondary source would tell that
47
+ * driver's adapter about tables it does not have.
48
+ */
49
+ export declare function initializeDataSource(source: ResolvedDataSourceConfig, schema: BundleSchema | undefined, resolveFrom?: string[]): Promise<InitializedDataSource>;
50
+ /**
51
+ * Build drivers for every resolved data source.
52
+ *
53
+ * Sequential on purpose: a failure on the second source should not leave a
54
+ * half-opened pool from a third racing behind it, and the log then reads in the
55
+ * order a human would expect.
56
+ */
57
+ export declare function initializeDataSources(sources: ResolvedDataSourceConfig[], schema: BundleSchema | undefined, resolveFrom?: string[]): Promise<InitializedDataSource[]>;
@@ -0,0 +1,129 @@
1
+ import { z } from "zod";
2
+ import { type RebaseEnv } from "../env";
3
+ /**
4
+ * The environment a bundle-booted runtime understands.
5
+ *
6
+ * This extends the base {@link loadEnv} schema with the variables an application
7
+ * used to declare for itself in its own `env.ts`. They live here now because the
8
+ * runtime, not the application, is what reads them: a project ships a bundle and
9
+ * a set of environment variables, and everything either side needs to agree on
10
+ * has to be part of the contract rather than a convention each project reinvents.
11
+ */
12
+ declare const bootEnvExtension: z.ZodObject<{
13
+ SMTP_HOST: z.ZodOptional<z.ZodString>;
14
+ SMTP_PORT: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<number, string>>;
15
+ SMTP_SECURE: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
16
+ "": "";
17
+ true: "true";
18
+ false: "false";
19
+ }>>, z.ZodTransform<boolean, "" | "true" | "false">>;
20
+ SMTP_USER: z.ZodOptional<z.ZodString>;
21
+ SMTP_PASS: z.ZodOptional<z.ZodString>;
22
+ SMTP_FROM: z.ZodOptional<z.ZodString>;
23
+ SMTP_NAME: z.ZodOptional<z.ZodString>;
24
+ APP_NAME: z.ZodDefault<z.ZodString>;
25
+ REBASE_SERVE_STATIC: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
26
+ "": "";
27
+ true: "true";
28
+ false: "false";
29
+ }>>, z.ZodTransform<boolean, "" | "true" | "false">>;
30
+ REBASE_MIGRATE_ON_BOOT: z.ZodOptional<z.ZodEnum<{
31
+ "": "";
32
+ push: "push";
33
+ none: "none";
34
+ ensure: "ensure";
35
+ }>>;
36
+ REBASE_METRICS: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
37
+ "": "";
38
+ true: "true";
39
+ false: "false";
40
+ }>>, z.ZodTransform<boolean, "" | "true" | "false">>;
41
+ REBASE_METRICS_TOKEN: z.ZodOptional<z.ZodString>;
42
+ LOG_LEVEL: z.ZodOptional<z.ZodEnum<{
43
+ "": "";
44
+ debug: "debug";
45
+ info: "info";
46
+ warn: "warn";
47
+ error: "error";
48
+ }>>;
49
+ STORAGE_PUBLIC_READ: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
50
+ "": "";
51
+ true: "true";
52
+ false: "false";
53
+ }>>, z.ZodTransform<boolean, "" | "true" | "false">>;
54
+ STORAGE_ALLOW_ANY_AUTHENTICATED: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
55
+ "": "";
56
+ true: "true";
57
+ false: "false";
58
+ }>>, z.ZodTransform<boolean, "" | "true" | "false">>;
59
+ AUTH_REQUIRE: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
60
+ "": "";
61
+ true: "true";
62
+ false: "false";
63
+ }>>, z.ZodTransform<boolean, "" | "true" | "false">>;
64
+ AUTH_ALLOW_USER_LOOKUP: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
65
+ "": "";
66
+ true: "true";
67
+ false: "false";
68
+ }>>, z.ZodTransform<boolean, "" | "true" | "false">>;
69
+ AUTH_COOKIE_SAME_SITE: z.ZodOptional<z.ZodEnum<{
70
+ "": "";
71
+ Strict: "Strict";
72
+ Lax: "Lax";
73
+ None: "None";
74
+ }>>;
75
+ AUTH_DEFAULT_ROLE: z.ZodOptional<z.ZodString>;
76
+ GITHUB_CLIENT_ID: z.ZodOptional<z.ZodString>;
77
+ GITHUB_CLIENT_SECRET: z.ZodOptional<z.ZodString>;
78
+ MICROSOFT_CLIENT_ID: z.ZodOptional<z.ZodString>;
79
+ MICROSOFT_CLIENT_SECRET: z.ZodOptional<z.ZodString>;
80
+ REBASE_BASE_PATH: z.ZodDefault<z.ZodString>;
81
+ REBASE_ENABLE_SWAGGER: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
82
+ "": "";
83
+ true: "true";
84
+ false: "false";
85
+ }>>, z.ZodTransform<boolean, "" | "true" | "false">>;
86
+ REBASE_MAX_BODY_SIZE: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
87
+ REBASE_COMPRESSION: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
88
+ "": "";
89
+ true: "true";
90
+ false: "false";
91
+ }>>, z.ZodTransform<boolean, "" | "true" | "false">>;
92
+ REBASE_HISTORY: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
93
+ "": "";
94
+ true: "true";
95
+ false: "false";
96
+ }>>, z.ZodTransform<boolean, "" | "true" | "false">>;
97
+ CORS_ORIGINS: z.ZodOptional<z.ZodString>;
98
+ }, z.core.$strip>;
99
+ export type RebaseBootEnv = RebaseEnv & z.infer<typeof bootEnvExtension>;
100
+ /**
101
+ * Load and validate the environment for a bundle boot.
102
+ *
103
+ * Does not read `.env` files — that is the deployment's job (a container gets
104
+ * real environment variables; `rebase dev` and `rebase start` load dotenv before
105
+ * calling in).
106
+ */
107
+ export declare function loadBootEnv(): RebaseBootEnv;
108
+ /**
109
+ * Whether an origin is a loopback address.
110
+ *
111
+ * In development the runtime reflects only localhost origins. It cannot reflect
112
+ * an arbitrary `Origin`, because credentials are enabled: any site the developer
113
+ * happened to visit could otherwise make credentialed requests against the dev
114
+ * server with the developer's session and read the responses.
115
+ */
116
+ export declare function isLocalhostOrigin(origin: string): boolean;
117
+ /** A CORS origin resolver of the shape Hono's `cors()` middleware expects. */
118
+ export type CorsOriginResolver = (origin: string) => string | null;
119
+ /**
120
+ * Build the CORS origin policy.
121
+ *
122
+ * Production serves an explicit allow-list and nothing else. `loadEnv` already
123
+ * refuses to start a production process with neither `CORS_ORIGINS` nor
124
+ * `FRONTEND_URL`, so an empty list here can only mean the values were blank
125
+ * strings — still worth failing on, because the alternative is an API that
126
+ * quietly rejects its own frontend.
127
+ */
128
+ export declare function resolveCorsOrigin(env: RebaseBootEnv): CorsOriginResolver;
129
+ export {};
@@ -0,0 +1,20 @@
1
+ import type { CollectionConfig } from "@rebasepro/types";
2
+ import type { RebaseAuthConfig } from "../init";
3
+ import type { EmailConfig } from "../email";
4
+ import type { RebaseBootEnv } from "./env";
5
+ /**
6
+ * Build the email configuration, or `undefined` when no SMTP host is set.
7
+ *
8
+ * Without it the auth adapter still works; password-reset and verification mail
9
+ * simply has nowhere to go, which the auth routes report for themselves.
10
+ */
11
+ export declare function resolveEmailOptions(env: RebaseBootEnv): EmailConfig | undefined;
12
+ /**
13
+ * Build the auth configuration from the environment and the bundle's users
14
+ * collection.
15
+ *
16
+ * OAuth providers are included only when both halves of a credential pair are
17
+ * present. Google is the exception the template already made: a client id alone
18
+ * is enough, because the ID-token flow needs no secret.
19
+ */
20
+ export declare function resolveAuthOptions(env: RebaseBootEnv, usersCollection: CollectionConfig | undefined): RebaseAuthConfig;
@@ -0,0 +1,77 @@
1
+ import { type DataSourceDefinition, type StorageSourceDefinition } from "@rebasepro/types";
2
+ import type { BackendStorageConfig } from "../storage/types";
3
+ /**
4
+ * Resolving *named* data and storage sources from the environment.
5
+ *
6
+ * A project is not required to have one database and one bucket. Collections
7
+ * already route by `collection.dataSource`, storage properties already route by
8
+ * `storageSource`, and the backend already registers one driver per source key —
9
+ * so the only piece missing was a way to *configure* the second, third and fourth
10
+ * of each without hand-writing an entrypoint.
11
+ *
12
+ * The naming rule is mechanical, and deliberately derives the variable name from
13
+ * the declared key rather than trying to discover keys by scanning the
14
+ * environment. Scanning would have to guess how `DATABASE_URL_READ_REPLICA` splits
15
+ * into a key; deriving cannot be ambiguous, and a typo shows up as a missing
16
+ * source at boot instead of a silently ignored variable.
17
+ *
18
+ * ```
19
+ * <BASE> the default source DATABASE_URL, S3_BUCKET
20
+ * <BASE>__<KEY> a named source DATABASE_URL__ANALYTICS, S3_BUCKET__MEDIA
21
+ * ```
22
+ *
23
+ * The double underscore matters: single-underscore suffixes collide with real
24
+ * variable names (`S3_BUCKET_NAME` would parse as bucket "name").
25
+ */
26
+ /** Environment lookup, injectable so tests need not mutate `process.env`. */
27
+ export type EnvBag = Record<string, string | undefined>;
28
+ /**
29
+ * Convert a source key into the suffix used in environment variable names.
30
+ *
31
+ * The default key maps to no suffix at all, which is what keeps every existing
32
+ * single-database deployment working untouched.
33
+ */
34
+ export declare function envSuffixForKey(key: string, defaultKey: string): string;
35
+ /** A data source resolved to everything needed to build a driver for it. */
36
+ export interface ResolvedDataSourceConfig {
37
+ /** Data-source key — becomes the driver-registry id collections route by. */
38
+ key: string;
39
+ engine: string;
40
+ /** npm package implementing the driver. */
41
+ driverPackage: string;
42
+ connectionString: string;
43
+ adminConnectionString?: string;
44
+ readConnectionString?: string;
45
+ isDefault: boolean;
46
+ poolConfig?: Record<string, number>;
47
+ }
48
+ /**
49
+ * Resolve every server-transport data source to a connection.
50
+ *
51
+ * `direct` and `custom` transports are skipped: the client talks to those
52
+ * itself, so the backend holds no connection for them and must not demand one.
53
+ *
54
+ * A declared source with no connection string is an error rather than a warning.
55
+ * The alternative — starting without it — means every collection routed to that
56
+ * source silently falls back to the default database, which is data landing in
57
+ * the wrong place with a healthy-looking server in front of it.
58
+ */
59
+ export declare function resolveDataSources(env: EnvBag, definitions: DataSourceDefinition[] | undefined): ResolvedDataSourceConfig[];
60
+ /**
61
+ * Build one storage configuration from the variables for a single source.
62
+ *
63
+ * Returns `undefined` when the source has no configuration at all, so an
64
+ * optional bucket that was never set does not fail a boot. The production
65
+ * "local storage is off" rule deliberately does *not* live here — it is enforced
66
+ * once, in `initializeStorage`, which logs precisely why storage is disabled.
67
+ * Duplicating it would mean two places to keep in agreement.
68
+ */
69
+ export declare function resolveStorageBackend(env: EnvBag, key: string, engineHint: string | undefined, defaultBasePath: string): BackendStorageConfig | undefined;
70
+ /**
71
+ * Resolve every server-transport storage source into a controller config map.
72
+ *
73
+ * The returned shape is the `Record<key, config>` the backend already accepts,
74
+ * so multiple buckets need nothing new downstream — they were always supported,
75
+ * they just had no way to be configured from the environment.
76
+ */
77
+ export declare function resolveStorageSources(env: EnvBag, definitions: StorageSourceDefinition[] | undefined, defaultBasePath: string): Record<string, BackendStorageConfig> | undefined;
@@ -0,0 +1,40 @@
1
+ import { createRequire as __createRequire } from "module";
2
+ import "process";
3
+ const require = __createRequire(import.meta.url);
4
+ //#region \0rolldown/runtime.js
5
+ var __create = Object.create;
6
+ var __defProp = Object.defineProperty;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
+ var __getOwnPropNames = Object.getOwnPropertyNames;
9
+ var __getProtoOf = Object.getPrototypeOf;
10
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
11
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
12
+ var __exportAll = (all, no_symbols) => {
13
+ let target = {};
14
+ for (var name in all) __defProp(target, name, {
15
+ get: all[name],
16
+ enumerable: true
17
+ });
18
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
19
+ return target;
20
+ };
21
+ var __copyProps = (to, from, except, desc) => {
22
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
23
+ key = keys[i];
24
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
25
+ get: ((k) => from[k]).bind(null, key),
26
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
27
+ });
28
+ }
29
+ return to;
30
+ };
31
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
32
+ value: mod,
33
+ enumerable: true
34
+ }) : target, mod));
35
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) {
36
+ if (typeof require !== "undefined") return require.apply(this, arguments);
37
+ throw Error("Calling `require` for \"" + x + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
38
+ });
39
+ //#endregion
40
+ export { __toESM as i, __exportAll as n, __require as r, __commonJSMin as t };