@rebasepro/cli 0.0.1-canary.eae7889 → 0.1.0
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/dist/commands/build.d.ts +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/start.d.ts +1 -0
- package/dist/index.cjs +249 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.es.js +250 -44
- package/dist/index.es.js.map +1 -1
- package/dist/utils/package-manager.d.ts +31 -0
- package/dist/utils/package-manager.test.d.ts +1 -0
- package/package.json +4 -5
- package/templates/template/.dockerignore +1 -1
- package/templates/template/.env.example +96 -0
- package/templates/template/README.md +17 -7
- package/templates/template/backend/drizzle.config.ts +24 -4
- package/templates/template/backend/package.json +3 -3
- package/templates/template/config/collections/posts.ts +3 -3
- package/templates/template/docker-compose.yml +13 -38
- package/templates/template/frontend/package.json +1 -1
- package/templates/template/frontend/src/App.tsx +19 -98
- package/templates/template/frontend/vite.config.ts +32 -2
- package/templates/template/package.json +13 -7
- package/templates/template/.env.template +0 -62
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
|
2
|
+
# ║ Rebase Environment Configuration ║
|
|
3
|
+
# ║ Copy this file to .env and fill in the values ║
|
|
4
|
+
# ╚══════════════════════════════════════════════════════════════════════════════╝
|
|
5
|
+
|
|
6
|
+
# ── Database ──────────────────────────────────────────────────────────────────
|
|
7
|
+
# Database connection string (required)
|
|
8
|
+
# You can use PostgreSQL (postgresql://) or MongoDB (mongodb:// or mongodb+srv://).
|
|
9
|
+
# The backend will automatically detect the database type.
|
|
10
|
+
DATABASE_URL=postgresql://rebase:changeme@localhost:5432/rebase
|
|
11
|
+
# DATABASE_URL=mongodb://localhost:27017/rebase
|
|
12
|
+
|
|
13
|
+
# Separate admin connection string for migrations and schema operations (optional)
|
|
14
|
+
# Falls back to DATABASE_URL if not set
|
|
15
|
+
# ADMIN_CONNECTION_STRING=postgresql://postgres:your-password@localhost:5432/rebase
|
|
16
|
+
|
|
17
|
+
# Connection pool tuning (optional — sensible defaults are built-in)
|
|
18
|
+
# DB_POOL_MAX=20
|
|
19
|
+
# DB_POOL_IDLE_TIMEOUT=30000
|
|
20
|
+
# DB_POOL_CONNECT_TIMEOUT=10000
|
|
21
|
+
|
|
22
|
+
# ── Server ────────────────────────────────────────────────────────────────────
|
|
23
|
+
PORT=3001
|
|
24
|
+
NODE_ENV=development
|
|
25
|
+
|
|
26
|
+
# ── Logging ───────────────────────────────────────────────────────────────────
|
|
27
|
+
# Levels: error, warn, info, debug
|
|
28
|
+
LOG_LEVEL=info
|
|
29
|
+
|
|
30
|
+
# ── JWT Authentication (required) ─────────────────────────────────────────────
|
|
31
|
+
# Must be at least 32 characters. Generate with:
|
|
32
|
+
# node -e "console.log(require('crypto').randomBytes(48).toString('base64'))"
|
|
33
|
+
JWT_SECRET=
|
|
34
|
+
JWT_ACCESS_EXPIRES_IN=1h
|
|
35
|
+
JWT_REFRESH_EXPIRES_IN=30d
|
|
36
|
+
|
|
37
|
+
# ── Registration ──────────────────────────────────────────────────────────────
|
|
38
|
+
ALLOW_REGISTRATION=true
|
|
39
|
+
|
|
40
|
+
# ── Email (optional — required for password reset / verification) ─────────────
|
|
41
|
+
# SMTP_HOST=smtp.example.com
|
|
42
|
+
# SMTP_PORT=587
|
|
43
|
+
# SMTP_SECURE=false
|
|
44
|
+
# SMTP_USER=
|
|
45
|
+
# SMTP_PASS=
|
|
46
|
+
# SMTP_FROM=noreply@yourapp.com
|
|
47
|
+
# APP_NAME=Your App Name
|
|
48
|
+
|
|
49
|
+
# ── URLs ──────────────────────────────────────────────────────────────────────
|
|
50
|
+
# Canonical frontend URL (used in password-reset / verification emails)
|
|
51
|
+
FRONTEND_URL=http://localhost:5173
|
|
52
|
+
|
|
53
|
+
# Allowed CORS origins in production (comma-separated)
|
|
54
|
+
# CORS_ORIGINS=https://yourdomain.com
|
|
55
|
+
|
|
56
|
+
# ── OAuth Providers (optional — uncomment to enable) ──────────────────────────
|
|
57
|
+
# GOOGLE_CLIENT_ID=
|
|
58
|
+
|
|
59
|
+
# ── Frontend (Vite) ──────────────────────────────────────────────────────────
|
|
60
|
+
VITE_API_URL=http://localhost:3001
|
|
61
|
+
# VITE_GOOGLE_CLIENT_ID=
|
|
62
|
+
|
|
63
|
+
# ── Storage ───────────────────────────────────────────────────────────────────
|
|
64
|
+
# Set STORAGE_TYPE to choose a storage backend. Default is "local" (filesystem).
|
|
65
|
+
#
|
|
66
|
+
# Supported values: local, s3
|
|
67
|
+
#
|
|
68
|
+
# STORAGE_TYPE=local
|
|
69
|
+
|
|
70
|
+
# --- Local filesystem (default — great for dev and single-server deployments) --
|
|
71
|
+
# STORAGE_PATH=./uploads
|
|
72
|
+
|
|
73
|
+
# --- S3-compatible (AWS S3, Cloudflare R2, MinIO, Hetzner Object Storage, Backblaze B2) ---
|
|
74
|
+
# STORAGE_TYPE=s3
|
|
75
|
+
# S3_BUCKET=my-app-uploads
|
|
76
|
+
# S3_REGION=us-east-1
|
|
77
|
+
# S3_ACCESS_KEY_ID=
|
|
78
|
+
# S3_SECRET_ACCESS_KEY=
|
|
79
|
+
# S3_ENDPOINT= # Required for R2, MinIO, Hetzner (e.g. https://fsn1.your-objectstorage.com)
|
|
80
|
+
# S3_FORCE_PATH_STYLE= # Set to "true" for MinIO
|
|
81
|
+
|
|
82
|
+
# --- GCS via S3 interop (Cloud Run, GKE, etc.) ---
|
|
83
|
+
# Use GCS HMAC keys: https://cloud.google.com/storage/docs/interoperability
|
|
84
|
+
# STORAGE_TYPE=s3
|
|
85
|
+
# S3_BUCKET=my-gcs-bucket
|
|
86
|
+
# S3_ENDPOINT=https://storage.googleapis.com
|
|
87
|
+
# S3_ACCESS_KEY_ID=GOOG... # HMAC access key
|
|
88
|
+
# S3_SECRET_ACCESS_KEY=... # HMAC secret
|
|
89
|
+
#
|
|
90
|
+
# For native GCS SDK or other providers (Azure Blob, etc.), implement the
|
|
91
|
+
# StorageController interface and pass it directly in your backend config.
|
|
92
|
+
|
|
93
|
+
# ── Admin Service Key (optional) ──────────────────────────────────────────────
|
|
94
|
+
# When set, scripts authenticate with: Authorization: Bearer <key>
|
|
95
|
+
# Generate with: node -e "console.log(require('crypto').randomBytes(48).toString('base64'))"
|
|
96
|
+
# REBASE_SERVICE_KEY=
|
|
@@ -7,8 +7,8 @@ A [Rebase](https://rebase.pro) project with a PostgreSQL backend.
|
|
|
7
7
|
### Option 1: Docker (recommended for production)
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
cp .env.
|
|
11
|
-
# Edit .env — set
|
|
10
|
+
cp .env.example .env
|
|
11
|
+
# Edit .env — set JWT_SECRET and DATABASE_URL (see comments for generators)
|
|
12
12
|
|
|
13
13
|
docker compose up -d
|
|
14
14
|
```
|
|
@@ -23,7 +23,7 @@ That's it. Your app is running:
|
|
|
23
23
|
#### Prerequisites
|
|
24
24
|
|
|
25
25
|
- [Node.js](https://nodejs.org) >= 18
|
|
26
|
-
- [pnpm](https://pnpm.io)
|
|
26
|
+
- [pnpm](https://pnpm.io) or [npm](https://www.npmjs.com) (v7+)
|
|
27
27
|
- A PostgreSQL database
|
|
28
28
|
|
|
29
29
|
#### Setup
|
|
@@ -31,13 +31,13 @@ That's it. Your app is running:
|
|
|
31
31
|
1. Install dependencies:
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
pnpm install
|
|
34
|
+
pnpm install # or: npm install
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
2. Configure environment:
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
cp .env.
|
|
40
|
+
cp .env.example .env
|
|
41
41
|
# Edit .env — set DATABASE_URL, JWT_SECRET
|
|
42
42
|
```
|
|
43
43
|
|
|
@@ -51,7 +51,7 @@ rebase db push
|
|
|
51
51
|
4. Start the dev server:
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
|
-
pnpm dev
|
|
54
|
+
pnpm dev # or: npm run dev
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
Backend (Hono + PostgreSQL) on port 3001, frontend (Vite + React) on port 5173.
|
|
@@ -69,7 +69,7 @@ Backend (Hono + PostgreSQL) on port 3001, frontend (Vite + React) on port 5173.
|
|
|
69
69
|
├── config/ # Shared collection definitions
|
|
70
70
|
│ └── collections/ # Schema-as-Code TypeScript files
|
|
71
71
|
├── docker-compose.yml # Production stack (Postgres + Backend + Frontend)
|
|
72
|
-
├── .env.
|
|
72
|
+
├── .env.example # Environment variable reference
|
|
73
73
|
└── package.json # Root workspace config
|
|
74
74
|
```
|
|
75
75
|
|
|
@@ -94,6 +94,16 @@ Call from the client SDK: `client.call("functions/hello", { name: "World" })`
|
|
|
94
94
|
|
|
95
95
|
Collections are defined once in `config/collections/` and used by both the frontend and backend. This ensures your schema stays in sync across the stack.
|
|
96
96
|
|
|
97
|
+
## Environment Configuration
|
|
98
|
+
|
|
99
|
+
All configuration is managed through a single `.env` file in the project root. Both the backend and frontend read from this file:
|
|
100
|
+
|
|
101
|
+
- **Backend**: loads via `dotenv` from `../../.env` (relative to `backend/src/`)
|
|
102
|
+
- **Frontend**: Vite reads `VITE_*` variables via `envDir` pointing to the project root
|
|
103
|
+
- **Scripts**: load via `dotenv` from the project root
|
|
104
|
+
|
|
105
|
+
Copy `.env.example` to `.env` to get started. See the comments in `.env.example` for details on each variable.
|
|
106
|
+
|
|
97
107
|
## Production Deployment
|
|
98
108
|
|
|
99
109
|
```bash
|
|
@@ -1,14 +1,23 @@
|
|
|
1
|
-
import "dotenv
|
|
1
|
+
import * as dotenv from "dotenv";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
2
4
|
import { defineConfig } from "drizzle-kit";
|
|
3
5
|
import { tables } from "./src/schema.generated";
|
|
4
6
|
import { getTableName, Table } from "drizzle-orm";
|
|
5
7
|
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
// Load .env from the project root (single file for the entire project)
|
|
12
|
+
dotenv.config({ path: path.resolve(__dirname, "../.env") });
|
|
13
|
+
|
|
6
14
|
if (!process.env.DATABASE_URL) {
|
|
7
15
|
throw new Error("DATABASE_URL is not set. Make sure .env file exists in the project root and contains DATABASE_URL");
|
|
8
16
|
}
|
|
9
17
|
|
|
10
|
-
// Extract table names from the generated schema
|
|
11
|
-
// This ensures drizzle-kit ONLY manages tables defined in the schema
|
|
18
|
+
// Extract table names from the generated schema.
|
|
19
|
+
// This ensures drizzle-kit ONLY manages tables defined in the schema.
|
|
20
|
+
// Any tables in the database that are NOT part of the Rebase schema are left untouched.
|
|
12
21
|
const tableNames = Object.values(tables).map(table => getTableName(table as Table));
|
|
13
22
|
|
|
14
23
|
export default defineConfig({
|
|
@@ -18,5 +27,16 @@ export default defineConfig({
|
|
|
18
27
|
dbCredentials: {
|
|
19
28
|
url: process.env.DATABASE_URL
|
|
20
29
|
},
|
|
21
|
-
|
|
30
|
+
// Only manage tables defined in the generated schema.
|
|
31
|
+
// Unmapped tables in the database are completely ignored.
|
|
32
|
+
tablesFilter: tableNames,
|
|
33
|
+
// Restrict drizzle-kit to the public schema only — tables in other schemas
|
|
34
|
+
// (e.g. extensions, custom schemas) are never touched.
|
|
35
|
+
schemaFilter: ["public"],
|
|
36
|
+
// Prevent drizzle-kit from managing roles not defined in the schema
|
|
37
|
+
entities: {
|
|
38
|
+
roles: false
|
|
39
|
+
},
|
|
40
|
+
// If PostGIS or other extensions create helper tables, ignore them
|
|
41
|
+
extensionsFilters: ["postgis"]
|
|
22
42
|
});
|
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
"start": "tsx src/index.ts"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"{{PROJECT_NAME}}-config": "
|
|
13
|
+
"{{PROJECT_NAME}}-config": "*",
|
|
14
14
|
"@rebasepro/server-core": "workspace:*",
|
|
15
15
|
"@rebasepro/server-postgresql": "workspace:*",
|
|
16
16
|
"drizzle-orm": "^0.44.4",
|
|
17
|
-
"hono": "^4.
|
|
18
|
-
"@hono/node-server": "^1.
|
|
17
|
+
"hono": "^4.12.10",
|
|
18
|
+
"@hono/node-server": "^1.19.12",
|
|
19
19
|
"pg": "^8.11.3",
|
|
20
20
|
"ws": "^8.16.0",
|
|
21
21
|
"zod": "^3.22.4",
|
|
@@ -35,17 +35,17 @@ const postsCollection: EntityCollection = {
|
|
|
35
35
|
{
|
|
36
36
|
id: "draft",
|
|
37
37
|
label: "Draft",
|
|
38
|
-
color: "
|
|
38
|
+
color: "gray"
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
id: "review",
|
|
42
42
|
label: "In Review",
|
|
43
|
-
color: "
|
|
43
|
+
color: "orange"
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
46
|
id: "published",
|
|
47
47
|
label: "Published",
|
|
48
|
-
color: "
|
|
48
|
+
color: "green"
|
|
49
49
|
}
|
|
50
50
|
]
|
|
51
51
|
},
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# ─── Rebase — Production Docker Compose ──────────────────────────────
|
|
2
2
|
#
|
|
3
3
|
# Quick start:
|
|
4
|
-
# cp .env.
|
|
5
|
-
# docker compose up -d
|
|
4
|
+
# cp .env.example .env # Edit with your secrets
|
|
5
|
+
# docker compose up -d # Start everything
|
|
6
6
|
#
|
|
7
7
|
# This runs:
|
|
8
8
|
# 1. PostgreSQL 18 with persistent data
|
|
9
9
|
# 2. Backend (Node.js / Hono) with health checks
|
|
10
10
|
# 3. Frontend (nginx) serving the Vite build
|
|
11
11
|
#
|
|
12
|
-
# For development, use `
|
|
12
|
+
# For development, use `rebase dev` instead.
|
|
13
13
|
# ─────────────────────────────────────────────────────────────────────
|
|
14
14
|
|
|
15
15
|
services:
|
|
@@ -18,15 +18,15 @@ services:
|
|
|
18
18
|
image: postgres:18-alpine
|
|
19
19
|
restart: unless-stopped
|
|
20
20
|
environment:
|
|
21
|
-
POSTGRES_USER:
|
|
22
|
-
POSTGRES_PASSWORD: ${
|
|
23
|
-
POSTGRES_DB:
|
|
21
|
+
POSTGRES_USER: rebase
|
|
22
|
+
POSTGRES_PASSWORD: ${DATABASE_PASSWORD:-changeme}
|
|
23
|
+
POSTGRES_DB: rebase
|
|
24
24
|
ports:
|
|
25
|
-
- "
|
|
25
|
+
- "5432:5432"
|
|
26
26
|
volumes:
|
|
27
27
|
- postgres_data:/var/lib/postgresql/data
|
|
28
28
|
healthcheck:
|
|
29
|
-
test: ["CMD-SHELL", "pg_isready -U
|
|
29
|
+
test: ["CMD-SHELL", "pg_isready -U rebase -d rebase"]
|
|
30
30
|
interval: 5s
|
|
31
31
|
timeout: 5s
|
|
32
32
|
retries: 10
|
|
@@ -53,38 +53,13 @@ services:
|
|
|
53
53
|
restart: unless-stopped
|
|
54
54
|
ports:
|
|
55
55
|
- "${PORT:-3001}:3001"
|
|
56
|
+
env_file: .env
|
|
56
57
|
environment:
|
|
57
|
-
DATABASE_URL
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
JWT_ACCESS_EXPIRES_IN: ${JWT_ACCESS_EXPIRES_IN:-1h}
|
|
61
|
-
JWT_REFRESH_EXPIRES_IN: ${JWT_REFRESH_EXPIRES_IN:-30d}
|
|
58
|
+
# Override DATABASE_URL to point to the Docker network service
|
|
59
|
+
DATABASE_URL: postgresql://rebase:${DATABASE_PASSWORD:-changeme}@db:5432/rebase
|
|
60
|
+
ADMIN_CONNECTION_STRING: postgresql://rebase:${DATABASE_PASSWORD:-changeme}@db:5432/rebase
|
|
62
61
|
NODE_ENV: production
|
|
63
62
|
PORT: "3001"
|
|
64
|
-
ALLOW_REGISTRATION: ${ALLOW_REGISTRATION:-false}
|
|
65
|
-
FRONTEND_URL: ${FRONTEND_URL:-http://localhost}
|
|
66
|
-
CORS_ORIGINS: ${CORS_ORIGINS:-}
|
|
67
|
-
# Optional Google OAuth
|
|
68
|
-
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}
|
|
69
|
-
# Optional SMTP
|
|
70
|
-
SMTP_HOST: ${SMTP_HOST:-}
|
|
71
|
-
SMTP_PORT: ${SMTP_PORT:-}
|
|
72
|
-
SMTP_SECURE: ${SMTP_SECURE:-}
|
|
73
|
-
SMTP_USER: ${SMTP_USER:-}
|
|
74
|
-
SMTP_PASS: ${SMTP_PASS:-}
|
|
75
|
-
SMTP_FROM: ${SMTP_FROM:-}
|
|
76
|
-
APP_NAME: ${APP_NAME:-Rebase}
|
|
77
|
-
# Storage
|
|
78
|
-
STORAGE_TYPE: ${STORAGE_TYPE:-local}
|
|
79
|
-
STORAGE_PATH: ${STORAGE_PATH:-/app/backend/uploads}
|
|
80
|
-
S3_BUCKET: ${S3_BUCKET:-}
|
|
81
|
-
S3_REGION: ${S3_REGION:-}
|
|
82
|
-
S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID:-}
|
|
83
|
-
S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY:-}
|
|
84
|
-
S3_ENDPOINT: ${S3_ENDPOINT:-}
|
|
85
|
-
S3_FORCE_PATH_STYLE: ${S3_FORCE_PATH_STYLE:-}
|
|
86
|
-
# Service key for scripts & server-to-server admin access
|
|
87
|
-
REBASE_SERVICE_KEY: ${REBASE_SERVICE_KEY:-}
|
|
88
63
|
depends_on:
|
|
89
64
|
db:
|
|
90
65
|
condition: service_healthy
|
|
@@ -98,7 +73,7 @@ services:
|
|
|
98
73
|
dockerfile: frontend/Dockerfile
|
|
99
74
|
restart: unless-stopped
|
|
100
75
|
ports:
|
|
101
|
-
- "
|
|
76
|
+
- "80:80"
|
|
102
77
|
depends_on:
|
|
103
78
|
- backend
|
|
104
79
|
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"@rebasepro/types": "workspace:*",
|
|
14
14
|
"@rebasepro/ui": "workspace:*",
|
|
15
15
|
"@fontsource/jetbrains-mono": "^5.2.5",
|
|
16
|
-
"{{PROJECT_NAME}}-config": "
|
|
16
|
+
"{{PROJECT_NAME}}-config": "*",
|
|
17
17
|
"react": "^19.0.0",
|
|
18
18
|
"react-dom": "^19.0.0",
|
|
19
19
|
"react-router": "^7.0.0",
|
|
@@ -1,47 +1,23 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from "react";
|
|
2
2
|
|
|
3
3
|
import "@fontsource/jetbrains-mono";
|
|
4
4
|
import "typeface-rubik";
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from "@rebasepro/auth";
|
|
11
|
-
import {
|
|
12
|
-
AppBar,
|
|
13
|
-
Drawer,
|
|
14
|
-
Rebase,
|
|
15
|
-
ModeControllerProvider,
|
|
16
|
-
NotFoundPage,
|
|
17
|
-
Scaffold,
|
|
18
|
-
SideDialogs,
|
|
19
|
-
RebaseRoutes,
|
|
20
|
-
SnackbarProvider,
|
|
21
|
-
ContentHomePage,
|
|
22
|
-
useBuildUrlController,
|
|
23
|
-
useBuildCollectionRegistryController,
|
|
24
|
-
useBuildLocalConfigurationPersistence,
|
|
25
|
-
useBuildModeController,
|
|
26
|
-
useBuildNavigationStateController
|
|
27
|
-
} from "@rebasepro/core";
|
|
28
|
-
import { RebaseRoute } from "@rebasepro/admin";
|
|
29
|
-
import { CircularProgressCenter } from "@rebasepro/ui";
|
|
30
|
-
import { collections } from "virtual:rebase-collections";
|
|
31
|
-
import { Route, Outlet } from "react-router-dom";
|
|
6
|
+
import { useRebaseAuthController, useBackendUserManagement, RebaseAuth } from "@rebasepro/auth";
|
|
7
|
+
import { Rebase } from "@rebasepro/core";
|
|
8
|
+
import { RebaseCMS, RebaseShell } from "@rebasepro/admin";
|
|
9
|
+
import { RebaseStudio } from "@rebasepro/studio";
|
|
32
10
|
import { createRebaseClient } from "@rebasepro/client";
|
|
11
|
+
import { collections } from "virtual:rebase-collections";
|
|
33
12
|
|
|
34
13
|
// Configuration from environment
|
|
35
14
|
const API_URL = import.meta.env.VITE_API_URL || (import.meta.env.DEV ? "http://localhost:3001" : undefined);
|
|
36
15
|
const GOOGLE_CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID;
|
|
37
16
|
|
|
38
17
|
export function App() {
|
|
39
|
-
const modeController = useBuildModeController();
|
|
40
|
-
const userConfigPersistence = useBuildLocalConfigurationPersistence();
|
|
41
|
-
|
|
42
18
|
const rebaseClient = React.useMemo(() => createRebaseClient({
|
|
43
19
|
baseUrl: API_URL
|
|
44
|
-
}), [
|
|
20
|
+
}), []);
|
|
45
21
|
|
|
46
22
|
const authController = useRebaseAuthController({
|
|
47
23
|
client: rebaseClient,
|
|
@@ -53,73 +29,18 @@ export function App() {
|
|
|
53
29
|
currentUser: authController.user
|
|
54
30
|
});
|
|
55
31
|
|
|
56
|
-
const collectionsBuilder = useCallback(() => {
|
|
57
|
-
return [...collections];
|
|
58
|
-
}, []);
|
|
59
|
-
|
|
60
|
-
const collectionRegistryController = useBuildCollectionRegistryController({ userConfigPersistence });
|
|
61
|
-
const urlController = useBuildUrlController({
|
|
62
|
-
basePath: "/",
|
|
63
|
-
baseCollectionPath: "/c",
|
|
64
|
-
collectionRegistryController
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const navigationStateController = useBuildNavigationStateController({
|
|
68
|
-
collections: collectionsBuilder,
|
|
69
|
-
authController,
|
|
70
|
-
data: rebaseClient.data,
|
|
71
|
-
collectionRegistryController,
|
|
72
|
-
urlController,
|
|
73
|
-
userManagement
|
|
74
|
-
});
|
|
75
|
-
|
|
76
32
|
return (
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
{({ loading }) => {
|
|
90
|
-
if (loading || authController.initialLoading) {
|
|
91
|
-
return <CircularProgressCenter/>;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (!authController.user) {
|
|
95
|
-
return (
|
|
96
|
-
<RebaseLoginView
|
|
97
|
-
authController={authController}
|
|
98
|
-
googleEnabled={!!GOOGLE_CLIENT_ID}
|
|
99
|
-
googleClientId={GOOGLE_CLIENT_ID}
|
|
100
|
-
/>
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return (
|
|
105
|
-
<RebaseRoutes>
|
|
106
|
-
<Route element={
|
|
107
|
-
<Scaffold autoOpenDrawer={false}>
|
|
108
|
-
<AppBar/>
|
|
109
|
-
<Drawer/>
|
|
110
|
-
<Outlet/>
|
|
111
|
-
<SideDialogs/>
|
|
112
|
-
</Scaffold>
|
|
113
|
-
}>
|
|
114
|
-
<Route path={"/"} element={<ContentHomePage/>}/>
|
|
115
|
-
<Route path={"/c/*"} element={<RebaseRoute/>}/>
|
|
116
|
-
<Route path={"*"} element={<NotFoundPage/>}/>
|
|
117
|
-
</Route>
|
|
118
|
-
</RebaseRoutes>
|
|
119
|
-
);
|
|
120
|
-
}}
|
|
121
|
-
</Rebase>
|
|
122
|
-
</ModeControllerProvider>
|
|
123
|
-
</SnackbarProvider>
|
|
33
|
+
<Rebase
|
|
34
|
+
client={rebaseClient}
|
|
35
|
+
authController={authController}
|
|
36
|
+
userManagement={userManagement}
|
|
37
|
+
>
|
|
38
|
+
<RebaseAuth />
|
|
39
|
+
<RebaseCMS
|
|
40
|
+
collections={collections}
|
|
41
|
+
/>
|
|
42
|
+
<RebaseStudio/>
|
|
43
|
+
<RebaseShell title="Rebase"/>
|
|
44
|
+
</Rebase>
|
|
124
45
|
);
|
|
125
46
|
}
|
|
@@ -7,14 +7,44 @@ import tailwindcss from "@tailwindcss/vite";
|
|
|
7
7
|
import { rebaseCollectionsPlugin } from "@rebasepro/core/vitePlugin";
|
|
8
8
|
|
|
9
9
|
export default defineConfig({
|
|
10
|
+
envDir: path.resolve(__dirname, ".."),
|
|
10
11
|
esbuild: {
|
|
11
12
|
logOverride: { "this-is-undefined-in-esm": "silent" }
|
|
12
13
|
},
|
|
13
14
|
build: {
|
|
14
15
|
minify: true,
|
|
15
|
-
outDir: "./
|
|
16
|
+
outDir: "./dist",
|
|
16
17
|
target: "ESNEXT",
|
|
17
|
-
sourcemap: true
|
|
18
|
+
sourcemap: true,
|
|
19
|
+
rollupOptions: {
|
|
20
|
+
output: {
|
|
21
|
+
manualChunks(id) {
|
|
22
|
+
// Heavy vendor libraries — split into individually cached chunks
|
|
23
|
+
if (id.includes("xlsx")) return "vendor-xlsx";
|
|
24
|
+
if (id.includes("prosemirror")) return "vendor-prosemirror";
|
|
25
|
+
if (id.includes("monaco-editor") || id.includes("@monaco-editor")) return "vendor-monaco";
|
|
26
|
+
if (id.includes("@xyflow") || id.includes("dagre")) return "vendor-xyflow";
|
|
27
|
+
if (id.includes("@dnd-kit")) return "vendor-dnd";
|
|
28
|
+
if (id.includes("prism-react-renderer")) return "vendor-prism";
|
|
29
|
+
if (id.includes("markdown-it")) return "vendor-markdown";
|
|
30
|
+
if (id.includes("react-dropzone")) return "vendor-dropzone";
|
|
31
|
+
if (id.includes("date-fns")) return "vendor-datefns";
|
|
32
|
+
if (id.includes("fuse.js")) return "vendor-fuse";
|
|
33
|
+
if (id.includes("node_modules/react-dom/")) return "vendor-react-dom";
|
|
34
|
+
if (id.includes("node_modules/react-router") || id.includes("node_modules/@remix-run")) return "vendor-react-router";
|
|
35
|
+
if (id.includes("node_modules/@radix-ui/")) return "vendor-radix";
|
|
36
|
+
if (id.includes("node_modules/framer-motion/")) return "vendor-framer-motion";
|
|
37
|
+
if (id.includes("node_modules/zod/")) return "vendor-zod";
|
|
38
|
+
if (id.includes("node_modules/i18next") || id.includes("node_modules/react-i18next")) return "vendor-i18next";
|
|
39
|
+
if (id.includes("node_modules/@floating-ui/")) return "vendor-floating-ui";
|
|
40
|
+
if (id.includes("node_modules/tailwind-merge/")) return "vendor-tailwind-merge";
|
|
41
|
+
if (id.includes("node_modules/notistack/")) return "vendor-notistack";
|
|
42
|
+
if (id.includes("node_modules/lucide-react/")) return "vendor-lucide-react";
|
|
43
|
+
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
18
48
|
},
|
|
19
49
|
optimizeDeps: { include: ["react/jsx-runtime"] },
|
|
20
50
|
plugins: [
|
|
@@ -4,17 +4,23 @@
|
|
|
4
4
|
"description": "Rebase application with PostgreSQL backend",
|
|
5
5
|
"private": true,
|
|
6
6
|
"type": "module",
|
|
7
|
+
"workspaces": [
|
|
8
|
+
"frontend",
|
|
9
|
+
"backend",
|
|
10
|
+
"config"
|
|
11
|
+
],
|
|
7
12
|
"scripts": {
|
|
8
13
|
"dev": "rebase dev",
|
|
9
|
-
"build": "
|
|
10
|
-
"start": "
|
|
11
|
-
"db:generate": "rebase db generate",
|
|
14
|
+
"build": "rebase build",
|
|
15
|
+
"start": "rebase start",
|
|
16
|
+
"db:generate": "rebase db generate --collections ../config/collections",
|
|
12
17
|
"db:migrate": "rebase db migrate",
|
|
13
|
-
"
|
|
14
|
-
"db:push": "rebase db push",
|
|
18
|
+
"schema:introspect": "rebase schema introspect",
|
|
19
|
+
"db:push": "rebase db push --collections ../config/collections",
|
|
15
20
|
"db:studio": "rebase db studio",
|
|
16
|
-
"schema:generate": "rebase schema generate",
|
|
17
|
-
"generate:sdk": "rebase generate-sdk"
|
|
21
|
+
"schema:generate": "rebase schema generate --collections ../config/collections",
|
|
22
|
+
"generate:sdk": "rebase generate-sdk",
|
|
23
|
+
"deploy": "rebase build && rebase start"
|
|
18
24
|
},
|
|
19
25
|
"devDependencies": {
|
|
20
26
|
"@rebasepro/cli": "workspace:*",
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# ─── Rebase Environment Configuration ────────────────────────────────
|
|
2
|
-
# Copy this file to .env and fill in your values:
|
|
3
|
-
# cp .env.template .env
|
|
4
|
-
|
|
5
|
-
# ── Database ─────────────────────────────────────────────────────────
|
|
6
|
-
# Used by Docker Compose AND the backend
|
|
7
|
-
POSTGRES_USER=rebase
|
|
8
|
-
POSTGRES_PASSWORD= # REQUIRED — generate with: openssl rand -base64 32
|
|
9
|
-
POSTGRES_DB=rebase
|
|
10
|
-
POSTGRES_PORT=5432
|
|
11
|
-
|
|
12
|
-
# For local dev (without Docker):
|
|
13
|
-
DATABASE_URL=postgresql://rebase:${POSTGRES_PASSWORD}@localhost:5432/rebase
|
|
14
|
-
|
|
15
|
-
# ── Server ───────────────────────────────────────────────────────────
|
|
16
|
-
PORT=3001
|
|
17
|
-
NODE_ENV=development
|
|
18
|
-
|
|
19
|
-
# ── Authentication ───────────────────────────────────────────────────
|
|
20
|
-
JWT_SECRET= # REQUIRED — generate with: openssl rand -base64 64
|
|
21
|
-
JWT_ACCESS_EXPIRES_IN=1h
|
|
22
|
-
JWT_REFRESH_EXPIRES_IN=30d
|
|
23
|
-
ALLOW_REGISTRATION=true
|
|
24
|
-
|
|
25
|
-
# Admin service key for scripts & server-to-server calls (optional).
|
|
26
|
-
# When set, scripts authenticate with: Authorization: Bearer <key>
|
|
27
|
-
# REBASE_SERVICE_KEY= # generate with: node -e "console.log(require('crypto').randomBytes(48).toString('base64'))"
|
|
28
|
-
|
|
29
|
-
# ── Frontend ─────────────────────────────────────────────────────────
|
|
30
|
-
FRONTEND_PORT=80
|
|
31
|
-
VITE_API_URL=http://localhost:3001
|
|
32
|
-
|
|
33
|
-
# Canonical frontend URL (used in password-reset / verification emails)
|
|
34
|
-
FRONTEND_URL=http://localhost
|
|
35
|
-
|
|
36
|
-
# Allowed CORS origins in production (comma-separated)
|
|
37
|
-
# CORS_ORIGINS=https://yourdomain.com,https://app.yourdomain.com
|
|
38
|
-
|
|
39
|
-
# ── Google OAuth (optional) ──────────────────────────────────────────
|
|
40
|
-
# GOOGLE_CLIENT_ID=your-google-client-id
|
|
41
|
-
# VITE_GOOGLE_CLIENT_ID=your-google-client-id
|
|
42
|
-
|
|
43
|
-
# ── Email / SMTP (optional — enables password reset emails) ──────────
|
|
44
|
-
# SMTP_HOST=smtp.example.com
|
|
45
|
-
# SMTP_PORT=587
|
|
46
|
-
# SMTP_SECURE=false
|
|
47
|
-
# SMTP_USER=your-smtp-username
|
|
48
|
-
# SMTP_PASS=your-smtp-password
|
|
49
|
-
# SMTP_FROM=noreply@yourapp.com
|
|
50
|
-
# APP_NAME=My Rebase App
|
|
51
|
-
|
|
52
|
-
# ── Storage ──────────────────────────────────────────────────────────
|
|
53
|
-
# STORAGE_TYPE=local # Options: "local" or "s3"
|
|
54
|
-
# STORAGE_PATH=./uploads # Path for "local" storage
|
|
55
|
-
|
|
56
|
-
# S3 Configuration (Required if STORAGE_TYPE=s3)
|
|
57
|
-
# S3_BUCKET=my-rebase-bucket
|
|
58
|
-
# S3_REGION=us-east-1
|
|
59
|
-
# S3_ACCESS_KEY_ID=your-access-key
|
|
60
|
-
# S3_SECRET_ACCESS_KEY=your-secret-key
|
|
61
|
-
# S3_ENDPOINT=https://s3.us-east-1.amazonaws.com # Optional, used for MinIO or Cloudflare R2
|
|
62
|
-
# S3_FORCE_PATH_STYLE=false # Set to true for MinIO
|