@rebasepro/cli 0.11.0 → 0.11.1-canary.g8caabf3
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.
- package/bin/rebase.js +21 -0
- package/dist/bundle.d.ts +15 -5
- package/dist/commands/cloud/resources.d.ts +20 -0
- package/dist/commands/eject.d.ts +1 -0
- package/dist/commands/init.d.ts +19 -15
- package/dist/fold-static.d.ts +41 -15
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +766 -241
- package/dist/index.es.js.map +1 -1
- package/dist/manifest.d.ts +26 -7
- package/package.json +7 -7
- package/runtime/dev-server.mjs +0 -1
- package/templates/{template/backend → eject}/Dockerfile +16 -4
- package/templates/{template → eject}/backend/src/env.ts +0 -1
- package/templates/eject/docker-compose.custom.yml +71 -0
- package/templates/overlays/baas/backend/package.json +1 -4
- package/templates/overlays/baas/backend/tsconfig.json +8 -2
- package/templates/overlays/baas/config/index.ts +15 -0
- package/templates/overlays/baas/config/package.json +28 -0
- package/templates/overlays/baas/package.json +2 -1
- package/templates/overlays/baas/pnpm-workspace.yaml +1 -0
- package/templates/overlays/baas/rebase.json +2 -6
- package/templates/template/README.md +34 -16
- package/templates/template/backend/package.json +1 -4
- package/templates/template/docker-compose.yml +62 -38
- package/templates/template/frontend/src/main.tsx +8 -1
- package/templates/template/frontend/vite.config.ts +5 -0
- package/templates/template/rebase.json +5 -8
- package/templates/overlays/baas/backend/src/index.ts +0 -216
- package/templates/template/frontend/Dockerfile +0 -52
- package/templates/template/frontend/nginx.conf +0 -40
- /package/templates/{template → eject}/backend/src/index.ts +0 -0
- /package/templates/overlays/baas/{backend/src → config}/storage.ts +0 -0
package/dist/manifest.d.ts
CHANGED
|
@@ -36,10 +36,12 @@ export declare function validateManifest(raw: unknown): {
|
|
|
36
36
|
* the manifest a no-op for existing projects: the synthesized result is what
|
|
37
37
|
* they would have written by hand.
|
|
38
38
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
39
|
+
* The backend's `runtime` is inferred from whether the repository declares a
|
|
40
|
+
* **Dockerfile** — the thing that actually builds an image — and from nothing
|
|
41
|
+
* else. It used to be inferred from the presence of `backend/src/index.ts`,
|
|
42
|
+
* which every scaffolded project had whether or not it wanted its own server, so
|
|
43
|
+
* projects predating the manifest silently landed on the custom runtime and paid
|
|
44
|
+
* for it (see `docs/cloud-deploy-workspace-vendoring.md`).
|
|
43
45
|
*/
|
|
44
46
|
export declare function synthesizeManifest(projectRoot: string): RebaseProjectManifest;
|
|
45
47
|
export declare function manifestPath(projectRoot: string): string;
|
|
@@ -72,12 +74,29 @@ export declare function buildableApps(manifest: RebaseProjectManifest): {
|
|
|
72
74
|
* verdict.
|
|
73
75
|
*/
|
|
74
76
|
export declare function assessManagedCompatibility(manifest: RebaseProjectManifest): ManagedCompatibility;
|
|
75
|
-
/**
|
|
76
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Resolve a backend app's directories against the conventions it omits.
|
|
79
|
+
*
|
|
80
|
+
* `hasCollections` replaces the old `mode: "cms" | "baas"` field. Where the
|
|
81
|
+
* collections come from was never an independent choice: either they are
|
|
82
|
+
* declared in code and the bundle ships them, or they are not and the runtime
|
|
83
|
+
* introspects the live database at boot. Declaring it separately only created
|
|
84
|
+
* the contradictory state — code-first declared, no collections anywhere.
|
|
85
|
+
*
|
|
86
|
+
* `hasConfig` is deliberately a **separate** question. A headless project has no
|
|
87
|
+
* `config/collections`, but it may still ship a config package — that is where
|
|
88
|
+
* the `storageAuthorize` hook lives, and storage is not under row-level
|
|
89
|
+
* security, so without one the server refuses to boot with storage enabled.
|
|
90
|
+
* Collapsing the two would leave a headless project nowhere to put it.
|
|
91
|
+
*/
|
|
92
|
+
export declare function resolveBackendPaths(app: RebaseBackendAppConfig, projectRoot: string): {
|
|
77
93
|
config: string;
|
|
78
94
|
functions: string;
|
|
79
95
|
crons: string;
|
|
80
96
|
schema: string;
|
|
81
97
|
usersCollection: string;
|
|
82
|
-
|
|
98
|
+
/** Whether a config package exists — hooks, storage authorization. */
|
|
99
|
+
hasConfig: boolean;
|
|
100
|
+
/** Whether collections are declared in code, under `<config>/collections`. */
|
|
101
|
+
hasCollections: boolean;
|
|
83
102
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/cli",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.1-canary.g8caabf3",
|
|
4
4
|
"description": "Developer tools for Rebase projects",
|
|
5
5
|
"main": "./dist/index.es.js",
|
|
6
6
|
"module": "./dist/index.es.js",
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
"execa": "^9.6.1",
|
|
32
32
|
"inquirer": "14.0.2",
|
|
33
33
|
"jiti": "^2.7.0",
|
|
34
|
-
"@rebasepro/agent-skills": "0.11.
|
|
35
|
-
"@rebasepro/client": "0.11.
|
|
36
|
-
"@rebasepro/
|
|
37
|
-
"@rebasepro/
|
|
38
|
-
"@rebasepro/
|
|
39
|
-
"@rebasepro/
|
|
34
|
+
"@rebasepro/agent-skills": "0.11.1-canary.g8caabf3",
|
|
35
|
+
"@rebasepro/client": "0.11.1-canary.g8caabf3",
|
|
36
|
+
"@rebasepro/server": "0.11.1-canary.g8caabf3",
|
|
37
|
+
"@rebasepro/codegen": "0.11.1-canary.g8caabf3",
|
|
38
|
+
"@rebasepro/server-postgres": "0.11.1-canary.g8caabf3",
|
|
39
|
+
"@rebasepro/types": "0.11.1-canary.g8caabf3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/node": "^25.9.3",
|
package/runtime/dev-server.mjs
CHANGED
|
@@ -31,7 +31,6 @@ const bundle = createSourceBundle({
|
|
|
31
31
|
functions: optional(process.env.REBASE_DEV_FUNCTIONS),
|
|
32
32
|
crons: optional(process.env.REBASE_DEV_CRONS),
|
|
33
33
|
schema: optional(process.env.REBASE_DEV_SCHEMA),
|
|
34
|
-
mode: process.env.REBASE_DEV_MODE === "baas" ? "baas" : "cms",
|
|
35
34
|
app: optional(process.env.REBASE_DEV_APP)
|
|
36
35
|
});
|
|
37
36
|
|
|
@@ -1,10 +1,22 @@
|
|
|
1
|
-
# ───
|
|
2
|
-
#
|
|
1
|
+
# ─── Your image ───────────────────────────────────────────────────────
|
|
2
|
+
#
|
|
3
|
+
# `rebase eject` wrote this file, and it is yours now — nothing regenerates or
|
|
4
|
+
# updates it. The platform runtime is no longer involved: this image compiles
|
|
5
|
+
# and runs backend/src/index.ts, so CORS, auth wiring, storage and shutdown are
|
|
6
|
+
# configured there rather than by the runtime, and Rebase runtime upgrades do
|
|
7
|
+
# not reach this project.
|
|
8
|
+
#
|
|
9
|
+
# Assumes pnpm, which is what `rebase init` scaffolds a workspace for. On npm,
|
|
10
|
+
# swap the three pnpm lines below for `npm ci` and `npm run build --workspace`.
|
|
3
11
|
#
|
|
4
12
|
# Build context: the project root (where pnpm-workspace.yaml lives)
|
|
5
13
|
# Usage:
|
|
6
|
-
# docker build -t my-app
|
|
7
|
-
# docker
|
|
14
|
+
# docker build -t my-app .
|
|
15
|
+
# docker compose -f docker-compose.custom.yml up
|
|
16
|
+
#
|
|
17
|
+
# The managed alternative — no image to build, your project mounted into the
|
|
18
|
+
# published runtime — is docker-compose.yml, which is still here and still
|
|
19
|
+
# works if you change `runtime` back to "managed" in rebase.json.
|
|
8
20
|
|
|
9
21
|
# ── Stage 1: Install + Build ─────────────────────────────────────────
|
|
10
22
|
FROM node:22-alpine AS builder
|
|
@@ -19,7 +19,6 @@ const __dirname = path.dirname(__filename);
|
|
|
19
19
|
*/
|
|
20
20
|
function findEnvFile(startDir: string): string | undefined {
|
|
21
21
|
let dir = startDir;
|
|
22
|
-
// eslint-disable-next-line no-constant-condition
|
|
23
22
|
while (true) {
|
|
24
23
|
const candidate = path.join(dir, ".env");
|
|
25
24
|
if (fs.existsSync(candidate)) return candidate;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# ─── Self-hosting an ejected project ─────────────────────────────────
|
|
2
|
+
#
|
|
3
|
+
# `rebase eject` wrote this. It builds the image described by ./Dockerfile and
|
|
4
|
+
# runs YOUR backend/src/index.ts, rather than mounting a bundle into the
|
|
5
|
+
# published Rebase runtime.
|
|
6
|
+
#
|
|
7
|
+
# docker compose -f docker-compose.custom.yml up -d db
|
|
8
|
+
# rebase db push # once
|
|
9
|
+
# docker compose -f docker-compose.custom.yml up --build
|
|
10
|
+
#
|
|
11
|
+
# What you gave up by ejecting: the platform no longer upgrades the server
|
|
12
|
+
# underneath you, and CORS, auth wiring, storage and shutdown are configured in
|
|
13
|
+
# your entrypoint rather than by the runtime. What you gained: it is your
|
|
14
|
+
# process, and you can put anything you like in it.
|
|
15
|
+
#
|
|
16
|
+
# `docker-compose.yml` is still here and still runs the managed shape. Nothing
|
|
17
|
+
# stops you going back — set `runtime: "managed"` in rebase.json, `rebase build`,
|
|
18
|
+
# and use that file instead.
|
|
19
|
+
# ─────────────────────────────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
name: {{PROJECT_NAME}}
|
|
22
|
+
|
|
23
|
+
services:
|
|
24
|
+
db:
|
|
25
|
+
image: postgres:18-alpine
|
|
26
|
+
restart: unless-stopped
|
|
27
|
+
environment:
|
|
28
|
+
POSTGRES_USER: rebase
|
|
29
|
+
POSTGRES_PASSWORD: ${DATABASE_PASSWORD:-changeme}
|
|
30
|
+
POSTGRES_DB: rebase
|
|
31
|
+
ports:
|
|
32
|
+
- "5432:5432"
|
|
33
|
+
volumes:
|
|
34
|
+
- postgres_data:/var/lib/postgresql
|
|
35
|
+
healthcheck:
|
|
36
|
+
test: ["CMD-SHELL", "pg_isready -U rebase -d rebase"]
|
|
37
|
+
interval: 5s
|
|
38
|
+
timeout: 5s
|
|
39
|
+
retries: 10
|
|
40
|
+
start_period: 10s
|
|
41
|
+
|
|
42
|
+
backend:
|
|
43
|
+
build:
|
|
44
|
+
context: .
|
|
45
|
+
dockerfile: Dockerfile
|
|
46
|
+
restart: unless-stopped
|
|
47
|
+
ports:
|
|
48
|
+
- "${PORT:-3001}:3001"
|
|
49
|
+
env_file: .env
|
|
50
|
+
environment:
|
|
51
|
+
DATABASE_URL: postgresql://rebase:${DATABASE_PASSWORD:-changeme}@db:5432/rebase?options=-c%20search_path=public
|
|
52
|
+
ADMIN_CONNECTION_STRING: postgresql://rebase:${DATABASE_PASSWORD:-changeme}@db:5432/rebase?options=-c%20search_path=public
|
|
53
|
+
NODE_ENV: production
|
|
54
|
+
PORT: "3001"
|
|
55
|
+
# Your entrypoint serves the built frontend itself (see the `serveSPA`
|
|
56
|
+
# call in backend/src/index.ts), so this is one container, same origin.
|
|
57
|
+
CORS_ORIGINS: ${CORS_ORIGINS:?set CORS_ORIGINS to the origin you browse to}
|
|
58
|
+
# A durable named volume, which is the case this flag acknowledges.
|
|
59
|
+
STORAGE_PATH: /uploads
|
|
60
|
+
FORCE_LOCAL_STORAGE: "true"
|
|
61
|
+
depends_on:
|
|
62
|
+
db:
|
|
63
|
+
condition: service_healthy
|
|
64
|
+
volumes:
|
|
65
|
+
- uploads:/uploads
|
|
66
|
+
|
|
67
|
+
volumes:
|
|
68
|
+
postgres_data:
|
|
69
|
+
driver: local
|
|
70
|
+
uploads:
|
|
71
|
+
driver: local
|
|
@@ -2,12 +2,9 @@
|
|
|
2
2
|
"name": "{{PROJECT_NAME}}-backend",
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"description": "Rebase BaaS — headless PostgreSQL API",
|
|
5
|
-
"main": "src/index.ts",
|
|
6
5
|
"type": "module",
|
|
7
6
|
"scripts": {
|
|
8
|
-
"
|
|
9
|
-
"build": "tsc",
|
|
10
|
-
"start": "node dist/index.js"
|
|
7
|
+
"build": "tsc"
|
|
11
8
|
},
|
|
12
9
|
"dependencies": {
|
|
13
10
|
"@rebasepro/server": "workspace:*",
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
"moduleResolution": "node",
|
|
6
6
|
"lib": ["ES2022"],
|
|
7
7
|
"outDir": "./dist",
|
|
8
|
-
"rootDir": "./src",
|
|
9
8
|
"strict": true,
|
|
10
9
|
"esModuleInterop": true,
|
|
11
10
|
"allowSyntheticDefaultImports": true,
|
|
@@ -15,5 +14,12 @@
|
|
|
15
14
|
"declaration": true,
|
|
16
15
|
"sourceMap": true
|
|
17
16
|
},
|
|
18
|
-
|
|
17
|
+
// `functions/` as well as `src/`, because this flavour has nothing in src:
|
|
18
|
+
// it declares no collections, so there is no generated schema, and the server
|
|
19
|
+
// entrypoint lives behind `rebase eject`. An include matching only an empty
|
|
20
|
+
// directory is TS18003 — tsc reports "no inputs" as an error, not a no-op.
|
|
21
|
+
//
|
|
22
|
+
// No `rootDir`: it would have to be `.` for both, and letting tsc infer the
|
|
23
|
+
// common root gets there without a second place to keep in sync.
|
|
24
|
+
"include": ["src/**/*", "functions/**/*"]
|
|
19
25
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The config package for a headless project.
|
|
3
|
+
*
|
|
4
|
+
* There are no collections here: this flavour introspects them from the live
|
|
5
|
+
* database at boot, which is exactly what "no `config/collections` directory"
|
|
6
|
+
* means to `rebase build`.
|
|
7
|
+
*
|
|
8
|
+
* The package still exists because storage does not run under row-level
|
|
9
|
+
* security and its keys share one flat namespace — so without an access model,
|
|
10
|
+
* a deployment with file storage enabled serves every user's files to every
|
|
11
|
+
* signed-in user. The server refuses to boot in that state, and this is the
|
|
12
|
+
* export it looks for.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export { storageAuthorize } from "./storage.js";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}-config",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Storage access control for a headless Rebase project",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"private": true,
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"dev": "tsc --watch",
|
|
12
|
+
"clean": "rm -rf dist"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@rebasepro/types": "workspace:*"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"typescript": "^5.9.2"
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"import": "./dist/index.js",
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"default": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://rebase.pro/schemas/rebase.json",
|
|
3
|
-
"
|
|
3
|
+
"rebase": "^1",
|
|
4
4
|
"apps": {
|
|
5
5
|
"backend": {
|
|
6
6
|
"type": "backend",
|
|
7
|
-
"
|
|
8
|
-
},
|
|
9
|
-
"admin": {
|
|
10
|
-
"type": "admin",
|
|
11
|
-
"mode": "hosted"
|
|
7
|
+
"runtime": "managed"
|
|
12
8
|
}
|
|
13
9
|
}
|
|
14
10
|
}
|
|
@@ -60,20 +60,27 @@ server). Pin a port with `rebase dev --port 3001` if you need a stable one.
|
|
|
60
60
|
## Project Structure
|
|
61
61
|
|
|
62
62
|
```
|
|
63
|
-
├── frontend/ # React
|
|
64
|
-
|
|
65
|
-
│ └── nginx.conf # SPA routing + compression
|
|
66
|
-
├── backend/ # Hono backend with PostgreSQL
|
|
67
|
-
│ ├── Dockerfile # Multi-stage production build
|
|
63
|
+
├── frontend/ # Your admin panel (React + Vite)
|
|
64
|
+
├── backend/ # Server code
|
|
68
65
|
│ ├── functions/ # Custom API endpoints (auto-discovered)
|
|
69
|
-
│ └── src/
|
|
66
|
+
│ └── src/ # Generated database schema
|
|
70
67
|
├── config/ # Shared collection definitions
|
|
71
68
|
│ └── collections/ # Schema-as-Code TypeScript files
|
|
72
|
-
├──
|
|
69
|
+
├── rebase.json # Which apps this repository contains
|
|
70
|
+
├── docker-compose.yml # Self-hosting stack (Postgres + the Rebase runtime)
|
|
73
71
|
├── .env.example # Environment variable reference
|
|
74
72
|
└── package.json # Root workspace config
|
|
75
73
|
```
|
|
76
74
|
|
|
75
|
+
There is no Dockerfile, and that is deliberate: `rebase build` produces a
|
|
76
|
+
**bundle** — your compiled collections, functions, crons and admin assets — and
|
|
77
|
+
the published `rebasepro/server` image boots it. The artifact you self-host is
|
|
78
|
+
the artifact Rebase Cloud runs, so moving between them changes nothing in this
|
|
79
|
+
repository.
|
|
80
|
+
|
|
81
|
+
If you would rather run your own server process, `rebase eject` writes the
|
|
82
|
+
entrypoint, a Dockerfile and a compose file that builds them.
|
|
83
|
+
|
|
77
84
|
### Custom Functions
|
|
78
85
|
|
|
79
86
|
Drop a Hono app in `backend/functions/` and it's auto-mounted at `/api/functions/<name>`:
|
|
@@ -105,23 +112,28 @@ All configuration is managed through a single `.env` file in the project root. B
|
|
|
105
112
|
|
|
106
113
|
`init` already generated your `.env`. See the comments in `.env.example` for details on each variable, and edit `.env` directly to change any of them.
|
|
107
114
|
|
|
108
|
-
##
|
|
115
|
+
## Self-hosting
|
|
116
|
+
|
|
117
|
+
Two containers: PostgreSQL, and the Rebase runtime with your built project
|
|
118
|
+
mounted into it. There is no application image to build.
|
|
109
119
|
|
|
110
|
-
The
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
database is up before (or right after) starting the rest of the stack.
|
|
120
|
+
The runtime creates its auth tables at boot but **not** your collection tables —
|
|
121
|
+
a container restart must not be able to change a schema as a side effect — so
|
|
122
|
+
push the schema once, while the database is up.
|
|
114
123
|
|
|
115
124
|
```bash
|
|
116
|
-
# 1.
|
|
125
|
+
# 1. Build your project into ./dist-bundle
|
|
126
|
+
pnpm run build # or: npm run build
|
|
127
|
+
|
|
128
|
+
# 2. Start the database and create the tables from your collections
|
|
117
129
|
docker compose up -d db
|
|
118
130
|
pnpm run db:push # or: npm run db:push
|
|
119
131
|
|
|
120
|
-
#
|
|
121
|
-
docker compose up -d
|
|
132
|
+
# 3. Start the runtime
|
|
133
|
+
docker compose up -d
|
|
122
134
|
|
|
123
135
|
# View logs
|
|
124
|
-
docker compose logs -f
|
|
136
|
+
docker compose logs -f api
|
|
125
137
|
|
|
126
138
|
# Stop
|
|
127
139
|
docker compose down
|
|
@@ -130,6 +142,12 @@ docker compose down
|
|
|
130
142
|
docker compose down -v
|
|
131
143
|
```
|
|
132
144
|
|
|
145
|
+
One container now serves the API at `/api` and the admin at `/` — same origin,
|
|
146
|
+
so there is no CORS between them and no second web server to run.
|
|
147
|
+
|
|
148
|
+
To upgrade Rebase, set `REBASE_VERSION` in `.env` and restart. Your bundle is
|
|
149
|
+
untouched.
|
|
150
|
+
|
|
133
151
|
> `docker compose` reads the generated `.env` as-is. Set production values
|
|
134
152
|
> (a strong `DATABASE_PASSWORD`, `JWT_SECRET`, storage credentials, …) by
|
|
135
153
|
> editing `.env` directly — see `.env.example` for the full list. Do not
|
|
@@ -2,12 +2,9 @@
|
|
|
2
2
|
"name": "{{PROJECT_NAME}}-backend",
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"description": "Rebase backend with PostgreSQL",
|
|
5
|
-
"main": "src/index.ts",
|
|
6
5
|
"type": "module",
|
|
7
6
|
"scripts": {
|
|
8
|
-
"
|
|
9
|
-
"build": "rebase schema generate --collections ../config/collections && tsc",
|
|
10
|
-
"start": "node dist/backend/src/index.js"
|
|
7
|
+
"build": "rebase schema generate --collections ../config/collections && tsc"
|
|
11
8
|
},
|
|
12
9
|
"dependencies": {
|
|
13
10
|
"{{PROJECT_NAME}}-config": "*",
|
|
@@ -1,17 +1,32 @@
|
|
|
1
|
-
# ───
|
|
1
|
+
# ─── Self-hosting this project ───────────────────────────────────────
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
3
|
+
# Two containers: PostgreSQL, and the Rebase runtime with your built project
|
|
4
|
+
# mounted into it. There is no application image to build here — the runtime is
|
|
5
|
+
# the same published image every Rebase deployment runs, and your project
|
|
6
|
+
# travels as a bundle.
|
|
6
7
|
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
8
|
+
# That is the point: the artifact you self-host is the artifact Rebase Cloud
|
|
9
|
+
# runs. Nothing about this repository changes when you move between them; only
|
|
10
|
+
# the destination does, and that lives in `.rebase/cloud.json`, which is not
|
|
11
|
+
# committed.
|
|
12
|
+
#
|
|
13
|
+
# rebase build # produces ./dist-bundle
|
|
14
|
+
# docker compose up -d db
|
|
15
|
+
# rebase db push # create the collection tables, once
|
|
16
|
+
# docker compose up
|
|
17
|
+
#
|
|
18
|
+
# One container then serves the API at /api and the admin at / — same origin, so
|
|
19
|
+
# there is no CORS to configure between them and no second web server.
|
|
11
20
|
#
|
|
12
21
|
# For development, use `rebase dev` instead.
|
|
22
|
+
#
|
|
23
|
+
# To upgrade Rebase, change REBASE_VERSION and restart. Your bundle is untouched.
|
|
24
|
+
# To run your OWN server code instead, `rebase eject` — it writes the entrypoint,
|
|
25
|
+
# a Dockerfile and a compose file that builds them.
|
|
13
26
|
# ─────────────────────────────────────────────────────────────────────
|
|
14
27
|
|
|
28
|
+
name: {{PROJECT_NAME}}
|
|
29
|
+
|
|
15
30
|
services:
|
|
16
31
|
# ── PostgreSQL ───────────────────────────────────────────────────────
|
|
17
32
|
db:
|
|
@@ -21,20 +36,25 @@ services:
|
|
|
21
36
|
POSTGRES_USER: rebase
|
|
22
37
|
POSTGRES_PASSWORD: ${DATABASE_PASSWORD:-changeme}
|
|
23
38
|
POSTGRES_DB: rebase
|
|
39
|
+
# Published so `rebase db push` can reach it from the host. Remove this
|
|
40
|
+
# mapping once the schema is in place if the database should not be
|
|
41
|
+
# reachable from outside the compose network.
|
|
24
42
|
ports:
|
|
25
43
|
- "5432:5432"
|
|
26
44
|
volumes:
|
|
27
45
|
- postgres_data:/var/lib/postgresql
|
|
28
46
|
healthcheck:
|
|
47
|
+
# The runtime must not start before the database can answer, or its first
|
|
48
|
+
# boot fails on a connection refused and the container restarts for no
|
|
49
|
+
# reason a reader would understand.
|
|
29
50
|
test: ["CMD-SHELL", "pg_isready -U rebase -d rebase"]
|
|
30
51
|
interval: 5s
|
|
31
52
|
timeout: 5s
|
|
32
53
|
retries: 10
|
|
33
54
|
start_period: 10s
|
|
34
|
-
# Production tuning (adjust for your workload)
|
|
35
55
|
command:
|
|
36
56
|
- "postgres"
|
|
37
|
-
- "-c"
|
|
57
|
+
- "-c"
|
|
38
58
|
- "shared_buffers=256MB"
|
|
39
59
|
- "-c"
|
|
40
60
|
- "max_connections=100"
|
|
@@ -45,44 +65,48 @@ services:
|
|
|
45
65
|
- "-c"
|
|
46
66
|
- "log_min_duration_statement=1000"
|
|
47
67
|
|
|
48
|
-
# ──
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
context: .
|
|
52
|
-
dockerfile: backend/Dockerfile
|
|
68
|
+
# ── The Rebase runtime, booting your bundle ──────────────────────────
|
|
69
|
+
api:
|
|
70
|
+
image: rebasepro/server:${REBASE_VERSION:-latest}
|
|
53
71
|
restart: unless-stopped
|
|
72
|
+
depends_on:
|
|
73
|
+
db:
|
|
74
|
+
condition: service_healthy
|
|
54
75
|
ports:
|
|
55
76
|
- "${PORT:-3001}:3001"
|
|
56
|
-
env_file: .env
|
|
57
77
|
environment:
|
|
58
|
-
# Override DATABASE_URL to point to the Docker network service
|
|
59
78
|
DATABASE_URL: postgresql://rebase:${DATABASE_PASSWORD:-changeme}@db:5432/rebase?options=-c%20search_path=public
|
|
60
79
|
ADMIN_CONNECTION_STRING: postgresql://rebase:${DATABASE_PASSWORD:-changeme}@db:5432/rebase?options=-c%20search_path=public
|
|
80
|
+
JWT_SECRET: ${JWT_SECRET:?set JWT_SECRET in .env — `rebase init` generates one}
|
|
81
|
+
REBASE_SERVICE_KEY: ${REBASE_SERVICE_KEY:?set REBASE_SERVICE_KEY in .env — `rebase init` generates one}
|
|
61
82
|
NODE_ENV: production
|
|
62
83
|
PORT: "3001"
|
|
63
|
-
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
|
|
84
|
+
|
|
85
|
+
# The origins a browser will load the admin from. With the admin folded
|
|
86
|
+
# into the bundle it is served from this very container, so this is just
|
|
87
|
+
# your own address — but it is still required, because an API that guesses
|
|
88
|
+
# its allowed origins is one that eventually allows the wrong one.
|
|
89
|
+
CORS_ORIGINS: ${CORS_ORIGINS:?set CORS_ORIGINS to the origin you browse to, e.g. http://localhost:3001}
|
|
90
|
+
|
|
91
|
+
# Auth tables are created at boot. Collection tables are not: run
|
|
92
|
+
# `rebase db push` once, against the database above. A container restart
|
|
93
|
+
# must not be able to change a schema as a side effect.
|
|
94
|
+
REBASE_MIGRATE_ON_BOOT: ${REBASE_MIGRATE_ON_BOOT:-ensure}
|
|
95
|
+
|
|
96
|
+
# Uploads land on the named volume below, which survives restarts. That is
|
|
97
|
+
# the case FORCE_LOCAL_STORAGE exists to acknowledge — without a durable
|
|
98
|
+
# mount the server refuses local storage in production, because the
|
|
99
|
+
# container filesystem is destroyed on the next deploy and every uploaded
|
|
100
|
+
# file goes with it. Switch to STORAGE_TYPE=s3 or gcs and drop both lines
|
|
101
|
+
# if you move storage off-box.
|
|
102
|
+
STORAGE_PATH: /uploads
|
|
69
103
|
FORCE_LOCAL_STORAGE: "true"
|
|
70
|
-
depends_on:
|
|
71
|
-
db:
|
|
72
|
-
condition: service_healthy
|
|
73
104
|
volumes:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
context: .
|
|
80
|
-
dockerfile: frontend/Dockerfile
|
|
81
|
-
restart: unless-stopped
|
|
82
|
-
ports:
|
|
83
|
-
- "80:80"
|
|
84
|
-
depends_on:
|
|
85
|
-
- backend
|
|
105
|
+
# Your built project. Writable, because the runtime installs the bundle's
|
|
106
|
+
# declared dependencies into it on first start — `rebase build` emits a
|
|
107
|
+
# package.json but not a node_modules.
|
|
108
|
+
- ./dist-bundle:/bundle
|
|
109
|
+
- uploads:/uploads
|
|
86
110
|
|
|
87
111
|
volumes:
|
|
88
112
|
postgres_data:
|
|
@@ -8,12 +8,19 @@ window.addEventListener("unhandledrejection", (event: PromiseRejectionEvent) =>
|
|
|
8
8
|
console.error("[Rebase] Unhandled promise rejection:", event.reason);
|
|
9
9
|
});
|
|
10
10
|
|
|
11
|
+
// Where this app is mounted, from the `path` declared in rebase.json.
|
|
12
|
+
//
|
|
13
|
+
// `rebase build` passes it to Vite as `base` (REBASE_APP_BASE), and Vite exposes
|
|
14
|
+
// it back as BASE_URL — so the assets, the router and the server all agree on
|
|
15
|
+
// one value without it being written down three times. At "/" this is "".
|
|
16
|
+
const basename = import.meta.env.BASE_URL.replace(/\/$/, "");
|
|
17
|
+
|
|
11
18
|
const router = createBrowserRouter([
|
|
12
19
|
{
|
|
13
20
|
path: "/*",
|
|
14
21
|
element: <App/>
|
|
15
22
|
}
|
|
16
|
-
]);
|
|
23
|
+
], { basename });
|
|
17
24
|
|
|
18
25
|
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
|
19
26
|
<React.StrictMode>
|
|
@@ -7,6 +7,11 @@ import { rebaseCollectionsPlugin } from "@rebasepro/app/vitePlugin";
|
|
|
7
7
|
|
|
8
8
|
export default defineConfig({
|
|
9
9
|
envDir: path.resolve(__dirname, ".."),
|
|
10
|
+
// The public path this app is served under, from its `path` in rebase.json.
|
|
11
|
+
// `rebase build` sets REBASE_APP_BASE; without this line an app declared at
|
|
12
|
+
// "/admin" would emit assets rooted at "/" and render a blank page. The
|
|
13
|
+
// build refuses to ship that — see docs/apps-and-runtimes.md §4.2.
|
|
14
|
+
base: process.env.REBASE_APP_BASE ?? "/",
|
|
10
15
|
// Force a single copy of React and React Router across the app and all
|
|
11
16
|
// @rebasepro/* packages. Without this, a locally `link:`ed Rebase checkout
|
|
12
17
|
// resolves its own copies of react-router, producing "multiple copies of
|
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://rebase.pro/schemas/rebase.json",
|
|
3
|
-
"
|
|
3
|
+
"rebase": "^1",
|
|
4
4
|
"apps": {
|
|
5
5
|
"backend": {
|
|
6
|
-
"type": "backend"
|
|
6
|
+
"type": "backend",
|
|
7
|
+
"runtime": "managed"
|
|
7
8
|
},
|
|
8
|
-
"
|
|
9
|
+
"admin": {
|
|
9
10
|
"type": "static",
|
|
10
11
|
"root": "frontend",
|
|
11
12
|
"build": "npm run build --workspace frontend",
|
|
12
13
|
"output": "frontend/dist",
|
|
13
|
-
"
|
|
14
|
-
},
|
|
15
|
-
"admin": {
|
|
16
|
-
"type": "admin",
|
|
17
|
-
"mode": "hosted"
|
|
14
|
+
"path": "/"
|
|
18
15
|
}
|
|
19
16
|
}
|
|
20
17
|
}
|