@rebasepro/cli 0.0.1-canary.eae7889 → 0.0.1-canary.f81da60

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.
@@ -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.template .env
11
- # Edit .env — set POSTGRES_PASSWORD and JWT_SECRET (see comments for generators)
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
  ```
@@ -37,7 +37,7 @@ pnpm install
37
37
  2. Configure environment:
38
38
 
39
39
  ```bash
40
- cp .env.template .env
40
+ cp .env.example .env
41
41
  # Edit .env — set DATABASE_URL, JWT_SECRET
42
42
  ```
43
43
 
@@ -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.template # Environment variable template
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/config";
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
- tablesFilter: tableNames
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": "0.0.1",
13
+ "{{PROJECT_NAME}}-config": "workspace:*",
14
14
  "@rebasepro/server-core": "workspace:*",
15
15
  "@rebasepro/server-postgresql": "workspace:*",
16
16
  "drizzle-orm": "^0.44.4",
17
- "hono": "^4.2.0",
18
- "@hono/node-server": "^1.11.0",
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: "grayLight"
38
+ color: "gray"
39
39
  },
40
40
  {
41
41
  id: "review",
42
42
  label: "In Review",
43
- color: "orangeLight"
43
+ color: "orange"
44
44
  },
45
45
  {
46
46
  id: "published",
47
47
  label: "Published",
48
- color: "greenLight"
48
+ color: "green"
49
49
  }
50
50
  ]
51
51
  },
@@ -1,8 +1,8 @@
1
1
  # ─── Rebase — Production Docker Compose ──────────────────────────────
2
2
  #
3
3
  # Quick start:
4
- # cp .env.template .env # Edit with your secrets
5
- # docker compose up -d # Start everything
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
@@ -18,15 +18,15 @@ services:
18
18
  image: postgres:18-alpine
19
19
  restart: unless-stopped
20
20
  environment:
21
- POSTGRES_USER: ${POSTGRES_USER:-rebase}
22
- POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}
23
- POSTGRES_DB: ${POSTGRES_DB:-rebase}
21
+ POSTGRES_USER: rebase
22
+ POSTGRES_PASSWORD: ${DATABASE_PASSWORD:-changeme}
23
+ POSTGRES_DB: rebase
24
24
  ports:
25
- - "${POSTGRES_PORT:-5432}:5432"
25
+ - "5432:5432"
26
26
  volumes:
27
27
  - postgres_data:/var/lib/postgresql/data
28
28
  healthcheck:
29
- test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-rebase} -d ${POSTGRES_DB:-rebase}"]
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: postgresql://${POSTGRES_USER:-rebase}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-rebase}
58
- ADMIN_CONNECTION_STRING: postgresql://${POSTGRES_USER:-rebase}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-rebase}
59
- JWT_SECRET: ${JWT_SECRET:?Set JWT_SECRET in .env}
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
- - "${FRONTEND_PORT:-80}:80"
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": "0.0.1",
16
+ "{{PROJECT_NAME}}-config": "workspace:*",
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, { useCallback } from "react";
1
+ import React from "react";
2
2
 
3
3
  import "@fontsource/jetbrains-mono";
4
4
  import "typeface-rubik";
5
5
 
6
- import {
7
- RebaseLoginView,
8
- useBackendUserManagement,
9
- useRebaseAuthController
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
- }), [API_URL]);
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
- <SnackbarProvider>
78
- <ModeControllerProvider value={modeController}>
79
- <Rebase
80
- client={rebaseClient}
81
- apiUrl={API_URL}
82
- collectionRegistryController={collectionRegistryController}
83
- urlController={urlController}
84
- navigationStateController={navigationStateController}
85
- authController={authController}
86
- userConfigPersistence={userConfigPersistence}
87
- storageSource={rebaseClient.storage}
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: "./build",
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: [
@@ -8,13 +8,14 @@
8
8
  "dev": "rebase dev",
9
9
  "build": "pnpm -r run build",
10
10
  "start": "pnpm --filter \"*-backend\" start",
11
- "db:generate": "rebase db generate",
11
+ "db:generate": "rebase db generate --collections ../config/collections",
12
12
  "db:migrate": "rebase db migrate",
13
13
  "db:pull": "rebase db pull",
14
- "db:push": "rebase db push",
14
+ "db:push": "rebase db push --collections ../config/collections",
15
15
  "db:studio": "rebase db studio",
16
- "schema:generate": "rebase schema generate",
17
- "generate:sdk": "rebase generate-sdk"
16
+ "schema:generate": "rebase schema generate --collections ../config/collections",
17
+ "generate:sdk": "rebase generate-sdk",
18
+ "deploy": "pnpm run build && pnpm run start"
18
19
  },
19
20
  "devDependencies": {
20
21
  "@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