@rebasepro/cli 0.0.1-canary.2 → 0.0.1-canary.4f204c2
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/auth.d.ts +1 -0
- package/dist/commands/cli.test.d.ts +1 -0
- package/dist/commands/db.d.ts +1 -0
- package/dist/commands/dev.d.ts +1 -0
- package/dist/commands/dev.test.d.ts +1 -0
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/generate_sdk.d.ts +18 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.test.d.ts +1 -0
- package/dist/commands/schema.d.ts +1 -0
- package/dist/index.cjs +986 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.es.js +987 -26
- package/dist/index.es.js.map +1 -1
- package/dist/utils/project.d.ts +45 -0
- package/dist/utils/project.test.d.ts +1 -0
- package/package.json +20 -11
- package/templates/template/.dockerignore +28 -0
- package/templates/template/.env.template +42 -11
- package/templates/template/README.md +74 -17
- package/templates/template/backend/Dockerfile +55 -10
- package/templates/template/backend/functions/hello.ts +52 -0
- package/templates/template/backend/package.json +30 -34
- package/templates/template/backend/src/env.ts +52 -0
- package/templates/template/backend/src/index.ts +113 -99
- package/templates/template/backend/tsconfig.json +1 -1
- package/templates/template/config/collections/authors.ts +45 -0
- package/templates/template/config/collections/index.ts +5 -0
- package/templates/template/{shared → config}/collections/posts.ts +40 -2
- package/templates/template/config/collections/tags.ts +27 -0
- package/templates/template/config/package.json +28 -0
- package/templates/template/docker-compose.yml +77 -16
- package/templates/template/frontend/Dockerfile +36 -14
- package/templates/template/frontend/nginx.conf +40 -0
- package/templates/template/frontend/package.json +9 -10
- package/templates/template/frontend/src/App.tsx +26 -33
- package/templates/template/frontend/src/index.css +15 -1
- package/templates/template/frontend/src/main.tsx +2 -2
- package/templates/template/frontend/vite.config.ts +1 -1
- package/templates/template/package.json +11 -16
- package/templates/template/pnpm-workspace.yaml +4 -0
- package/templates/template/scripts/example.ts +91 -0
- package/templates/template/backend/scripts/db-generate.ts +0 -60
- package/templates/template/shared/collections/index.ts +0 -3
- package/templates/template/shared/package.json +0 -28
- /package/templates/template/{shared → config}/index.ts +0 -0
- /package/templates/template/{shared → config}/tsconfig.json +0 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}-config",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Shared collections for frontend and backend",
|
|
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,48 +1,109 @@
|
|
|
1
|
-
|
|
1
|
+
# ─── Rebase — Production Docker Compose ──────────────────────────────
|
|
2
|
+
#
|
|
3
|
+
# Quick start:
|
|
4
|
+
# cp .env.template .env # Edit with your secrets
|
|
5
|
+
# docker compose up -d # Start everything
|
|
6
|
+
#
|
|
7
|
+
# This runs:
|
|
8
|
+
# 1. PostgreSQL 18 with persistent data
|
|
9
|
+
# 2. Backend (Node.js / Hono) with health checks
|
|
10
|
+
# 3. Frontend (nginx) serving the Vite build
|
|
11
|
+
#
|
|
12
|
+
# For development, use `pnpm dev` instead.
|
|
13
|
+
# ─────────────────────────────────────────────────────────────────────
|
|
2
14
|
|
|
3
15
|
services:
|
|
16
|
+
# ── PostgreSQL ───────────────────────────────────────────────────────
|
|
4
17
|
db:
|
|
5
18
|
image: postgres:18-alpine
|
|
19
|
+
restart: unless-stopped
|
|
6
20
|
environment:
|
|
7
|
-
POSTGRES_USER: rebase
|
|
8
|
-
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
|
9
|
-
POSTGRES_DB: rebase
|
|
21
|
+
POSTGRES_USER: ${POSTGRES_USER:-rebase}
|
|
22
|
+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}
|
|
23
|
+
POSTGRES_DB: ${POSTGRES_DB:-rebase}
|
|
10
24
|
ports:
|
|
11
|
-
- "5432:5432"
|
|
25
|
+
- "${POSTGRES_PORT:-5432}:5432"
|
|
12
26
|
volumes:
|
|
13
27
|
- postgres_data:/var/lib/postgresql/data
|
|
14
28
|
healthcheck:
|
|
15
|
-
test: ["CMD-SHELL", "pg_isready -U rebase"]
|
|
29
|
+
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-rebase} -d ${POSTGRES_DB:-rebase}"]
|
|
16
30
|
interval: 5s
|
|
17
31
|
timeout: 5s
|
|
18
|
-
retries:
|
|
32
|
+
retries: 10
|
|
33
|
+
start_period: 10s
|
|
34
|
+
# Production tuning (adjust for your workload)
|
|
35
|
+
command:
|
|
36
|
+
- "postgres"
|
|
37
|
+
- "-c"
|
|
38
|
+
- "shared_buffers=256MB"
|
|
39
|
+
- "-c"
|
|
40
|
+
- "max_connections=100"
|
|
41
|
+
- "-c"
|
|
42
|
+
- "work_mem=4MB"
|
|
43
|
+
- "-c"
|
|
44
|
+
- "effective_cache_size=768MB"
|
|
45
|
+
- "-c"
|
|
46
|
+
- "log_min_duration_statement=1000"
|
|
19
47
|
|
|
48
|
+
# ── Backend ──────────────────────────────────────────────────────────
|
|
20
49
|
backend:
|
|
21
|
-
build:
|
|
50
|
+
build:
|
|
22
51
|
context: .
|
|
23
52
|
dockerfile: backend/Dockerfile
|
|
53
|
+
restart: unless-stopped
|
|
24
54
|
ports:
|
|
25
|
-
- "3001:3001"
|
|
55
|
+
- "${PORT:-3001}:3001"
|
|
26
56
|
environment:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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}
|
|
62
|
+
NODE_ENV: production
|
|
63
|
+
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:-}
|
|
30
88
|
depends_on:
|
|
31
89
|
db:
|
|
32
90
|
condition: service_healthy
|
|
33
91
|
volumes:
|
|
34
|
-
-
|
|
92
|
+
- uploads:/app/backend/uploads
|
|
35
93
|
|
|
94
|
+
# ── Frontend ─────────────────────────────────────────────────────────
|
|
36
95
|
frontend:
|
|
37
96
|
build:
|
|
38
97
|
context: .
|
|
39
98
|
dockerfile: frontend/Dockerfile
|
|
99
|
+
restart: unless-stopped
|
|
40
100
|
ports:
|
|
41
|
-
- "
|
|
42
|
-
environment:
|
|
43
|
-
- VITE_API_URL=http://localhost:3001
|
|
101
|
+
- "${FRONTEND_PORT:-80}:80"
|
|
44
102
|
depends_on:
|
|
45
103
|
- backend
|
|
46
104
|
|
|
47
105
|
volumes:
|
|
48
106
|
postgres_data:
|
|
107
|
+
driver: local
|
|
108
|
+
uploads:
|
|
109
|
+
driver: local
|
|
@@ -1,28 +1,50 @@
|
|
|
1
|
-
|
|
1
|
+
# ─── Multi-stage production Dockerfile for the Rebase frontend ────────
|
|
2
|
+
# Builds the Vite app, then serves via nginx for proper caching/compression.
|
|
3
|
+
#
|
|
4
|
+
# Build context: the project root (where pnpm-workspace.yaml lives)
|
|
5
|
+
# Usage:
|
|
6
|
+
# docker build -t my-app-frontend -f frontend/Dockerfile .
|
|
7
|
+
|
|
8
|
+
# ── Stage 1: Install + Build ─────────────────────────────────────────
|
|
9
|
+
FROM node:24-alpine AS builder
|
|
10
|
+
|
|
2
11
|
ENV PNPM_HOME="/pnpm"
|
|
3
12
|
ENV PATH="$PNPM_HOME:$PATH"
|
|
4
13
|
RUN corepack enable
|
|
14
|
+
|
|
5
15
|
RUN apk add --no-cache python3 make g++
|
|
6
16
|
|
|
7
17
|
WORKDIR /app
|
|
8
18
|
|
|
9
|
-
# Copy root
|
|
10
|
-
COPY package.json ./
|
|
19
|
+
# Copy workspace root files
|
|
20
|
+
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
|
11
21
|
|
|
12
|
-
# Copy
|
|
22
|
+
# Copy workspace packages
|
|
13
23
|
COPY frontend ./frontend
|
|
14
|
-
COPY
|
|
24
|
+
COPY config ./config
|
|
15
25
|
|
|
16
26
|
# Install dependencies
|
|
17
|
-
RUN pnpm install
|
|
27
|
+
RUN pnpm install --frozen-lockfile
|
|
28
|
+
|
|
29
|
+
# Build config first, then frontend
|
|
30
|
+
RUN pnpm --filter "*-config" run build
|
|
31
|
+
RUN pnpm --filter "*-frontend" run build
|
|
32
|
+
|
|
33
|
+
# ── Stage 2: Serve with nginx ────────────────────────────────────────
|
|
34
|
+
FROM nginx:1.27-alpine AS runtime
|
|
35
|
+
|
|
36
|
+
# Remove default nginx page
|
|
37
|
+
RUN rm -rf /usr/share/nginx/html/*
|
|
38
|
+
|
|
39
|
+
# Copy built assets
|
|
40
|
+
COPY --from=builder /app/frontend/dist /usr/share/nginx/html
|
|
41
|
+
|
|
42
|
+
# Custom nginx config for SPA routing + compression
|
|
43
|
+
COPY frontend/nginx.conf /etc/nginx/conf.d/default.conf
|
|
18
44
|
|
|
19
|
-
|
|
20
|
-
RUN pnpm run build:shared
|
|
21
|
-
RUN pnpm run build:frontend
|
|
45
|
+
EXPOSE 80
|
|
22
46
|
|
|
23
|
-
|
|
24
|
-
|
|
47
|
+
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
|
|
48
|
+
CMD wget --no-verbose --tries=1 --spider http://localhost:80/ || exit 1
|
|
25
49
|
|
|
26
|
-
|
|
27
|
-
EXPOSE 5173
|
|
28
|
-
CMD ["serve", "-s", "dist", "-l", "5173"]
|
|
50
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
server {
|
|
2
|
+
listen 80;
|
|
3
|
+
server_name _;
|
|
4
|
+
|
|
5
|
+
root /usr/share/nginx/html;
|
|
6
|
+
index index.html;
|
|
7
|
+
|
|
8
|
+
# Gzip compression
|
|
9
|
+
gzip on;
|
|
10
|
+
gzip_vary on;
|
|
11
|
+
gzip_proxied any;
|
|
12
|
+
gzip_comp_level 6;
|
|
13
|
+
gzip_min_length 256;
|
|
14
|
+
gzip_types
|
|
15
|
+
text/plain
|
|
16
|
+
text/css
|
|
17
|
+
text/javascript
|
|
18
|
+
application/javascript
|
|
19
|
+
application/json
|
|
20
|
+
application/xml
|
|
21
|
+
image/svg+xml
|
|
22
|
+
font/woff2;
|
|
23
|
+
|
|
24
|
+
# Cache static assets aggressively (hashed filenames from Vite)
|
|
25
|
+
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
|
26
|
+
expires 1y;
|
|
27
|
+
add_header Cache-Control "public, immutable";
|
|
28
|
+
try_files $uri =404;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# SPA fallback: serve index.html for all non-file routes
|
|
32
|
+
location / {
|
|
33
|
+
try_files $uri $uri/ /index.html;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# Security headers
|
|
37
|
+
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
38
|
+
add_header X-Content-Type-Options "nosniff" always;
|
|
39
|
+
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
40
|
+
}
|
|
@@ -4,17 +4,16 @@
|
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@rebasepro/auth": "
|
|
8
|
-
"@rebasepro/core": "
|
|
9
|
-
"@rebasepro/
|
|
10
|
-
"@rebasepro/
|
|
11
|
-
"@rebasepro/
|
|
12
|
-
"@rebasepro/
|
|
13
|
-
"@rebasepro/
|
|
14
|
-
"@rebasepro/
|
|
15
|
-
"@rebasepro/ui": "^4.0.0",
|
|
7
|
+
"@rebasepro/auth": "workspace:*",
|
|
8
|
+
"@rebasepro/core": "workspace:*",
|
|
9
|
+
"@rebasepro/plugin-data-enhancement": "workspace:*",
|
|
10
|
+
"@rebasepro/client": "workspace:*",
|
|
11
|
+
"@rebasepro/admin": "workspace:*",
|
|
12
|
+
"@rebasepro/studio": "workspace:*",
|
|
13
|
+
"@rebasepro/types": "workspace:*",
|
|
14
|
+
"@rebasepro/ui": "workspace:*",
|
|
16
15
|
"@fontsource/jetbrains-mono": "^5.2.5",
|
|
17
|
-
"{{PROJECT_NAME}}-
|
|
16
|
+
"{{PROJECT_NAME}}-config": "workspace:*",
|
|
18
17
|
"react": "^19.0.0",
|
|
19
18
|
"react-dom": "^19.0.0",
|
|
20
19
|
"react-router": "^7.0.0",
|
|
@@ -10,10 +10,8 @@ import {
|
|
|
10
10
|
} from "@rebasepro/auth";
|
|
11
11
|
import {
|
|
12
12
|
AppBar,
|
|
13
|
-
CircularProgressCenter,
|
|
14
13
|
Drawer,
|
|
15
14
|
Rebase,
|
|
16
|
-
RebaseRoute,
|
|
17
15
|
ModeControllerProvider,
|
|
18
16
|
NotFoundPage,
|
|
19
17
|
Scaffold,
|
|
@@ -21,52 +19,46 @@ import {
|
|
|
21
19
|
RebaseRoutes,
|
|
22
20
|
SnackbarProvider,
|
|
23
21
|
ContentHomePage,
|
|
24
|
-
|
|
25
|
-
useBuildCMSUrlController,
|
|
22
|
+
useBuildUrlController,
|
|
26
23
|
useBuildCollectionRegistryController,
|
|
27
24
|
useBuildLocalConfigurationPersistence,
|
|
28
25
|
useBuildModeController,
|
|
29
26
|
useBuildNavigationStateController
|
|
30
27
|
} from "@rebasepro/core";
|
|
31
|
-
import {
|
|
28
|
+
import { RebaseRoute } from "@rebasepro/admin";
|
|
29
|
+
import { CircularProgressCenter } from "@rebasepro/ui";
|
|
32
30
|
import { collections } from "virtual:rebase-collections";
|
|
33
31
|
import { Route, Outlet } from "react-router-dom";
|
|
32
|
+
import { createRebaseClient } from "@rebasepro/client";
|
|
34
33
|
|
|
35
34
|
// Configuration from environment
|
|
36
|
-
const API_URL = import.meta.env.VITE_API_URL || "http://localhost:3001";
|
|
35
|
+
const API_URL = import.meta.env.VITE_API_URL || (import.meta.env.DEV ? "http://localhost:3001" : undefined);
|
|
37
36
|
const GOOGLE_CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID;
|
|
38
37
|
|
|
39
38
|
export function App() {
|
|
40
39
|
const modeController = useBuildModeController();
|
|
41
40
|
const userConfigPersistence = useBuildLocalConfigurationPersistence();
|
|
42
41
|
|
|
42
|
+
const rebaseClient = React.useMemo(() => createRebaseClient({
|
|
43
|
+
baseUrl: API_URL
|
|
44
|
+
}), [API_URL]);
|
|
45
|
+
|
|
43
46
|
const authController = useRebaseAuthController({
|
|
44
|
-
|
|
47
|
+
client: rebaseClient,
|
|
45
48
|
googleClientId: GOOGLE_CLIENT_ID
|
|
46
49
|
});
|
|
47
50
|
|
|
48
|
-
const storageSource = useBackendStorageSource({
|
|
49
|
-
apiUrl: API_URL,
|
|
50
|
-
getAuthToken: authController.getAuthToken
|
|
51
|
-
});
|
|
52
|
-
|
|
53
51
|
const userManagement = useBackendUserManagement({
|
|
54
|
-
|
|
55
|
-
getAuthToken: authController.getAuthToken,
|
|
52
|
+
client: rebaseClient,
|
|
56
53
|
currentUser: authController.user
|
|
57
54
|
});
|
|
58
55
|
|
|
59
|
-
const postgresDelegate = usePostgresClientDataSource({
|
|
60
|
-
websocketUrl: API_URL.replace(/^http/, "ws"),
|
|
61
|
-
getAuthToken: authController.initialLoading ? undefined : authController.getAuthToken
|
|
62
|
-
});
|
|
63
|
-
|
|
64
56
|
const collectionsBuilder = useCallback(() => {
|
|
65
57
|
return [...collections];
|
|
66
58
|
}, []);
|
|
67
59
|
|
|
68
60
|
const collectionRegistryController = useBuildCollectionRegistryController({ userConfigPersistence });
|
|
69
|
-
const
|
|
61
|
+
const urlController = useBuildUrlController({
|
|
70
62
|
basePath: "/",
|
|
71
63
|
baseCollectionPath: "/c",
|
|
72
64
|
collectionRegistryController
|
|
@@ -75,9 +67,9 @@ export function App() {
|
|
|
75
67
|
const navigationStateController = useBuildNavigationStateController({
|
|
76
68
|
collections: collectionsBuilder,
|
|
77
69
|
authController,
|
|
78
|
-
|
|
70
|
+
data: rebaseClient.data,
|
|
79
71
|
collectionRegistryController,
|
|
80
|
-
|
|
72
|
+
urlController,
|
|
81
73
|
userManagement
|
|
82
74
|
});
|
|
83
75
|
|
|
@@ -85,17 +77,18 @@ export function App() {
|
|
|
85
77
|
<SnackbarProvider>
|
|
86
78
|
<ModeControllerProvider value={modeController}>
|
|
87
79
|
<Rebase
|
|
80
|
+
client={rebaseClient}
|
|
81
|
+
apiUrl={API_URL}
|
|
88
82
|
collectionRegistryController={collectionRegistryController}
|
|
89
|
-
|
|
83
|
+
urlController={urlController}
|
|
90
84
|
navigationStateController={navigationStateController}
|
|
91
85
|
authController={authController}
|
|
92
86
|
userConfigPersistence={userConfigPersistence}
|
|
93
|
-
|
|
94
|
-
storageSource={storageSource}
|
|
87
|
+
storageSource={rebaseClient.storage}
|
|
95
88
|
>
|
|
96
89
|
{({ loading }) => {
|
|
97
90
|
if (loading || authController.initialLoading) {
|
|
98
|
-
return <CircularProgressCenter
|
|
91
|
+
return <CircularProgressCenter/>;
|
|
99
92
|
}
|
|
100
93
|
|
|
101
94
|
if (!authController.user) {
|
|
@@ -112,15 +105,15 @@ export function App() {
|
|
|
112
105
|
<RebaseRoutes>
|
|
113
106
|
<Route element={
|
|
114
107
|
<Scaffold autoOpenDrawer={false}>
|
|
115
|
-
<AppBar
|
|
116
|
-
<Drawer
|
|
117
|
-
<Outlet
|
|
118
|
-
<SideDialogs
|
|
108
|
+
<AppBar/>
|
|
109
|
+
<Drawer/>
|
|
110
|
+
<Outlet/>
|
|
111
|
+
<SideDialogs/>
|
|
119
112
|
</Scaffold>
|
|
120
113
|
}>
|
|
121
|
-
<Route path={"/"} element={<ContentHomePage
|
|
122
|
-
<Route path={"/c/*"} element={<RebaseRoute
|
|
123
|
-
<Route path={"*"} element={<NotFoundPage
|
|
114
|
+
<Route path={"/"} element={<ContentHomePage/>}/>
|
|
115
|
+
<Route path={"/c/*"} element={<RebaseRoute/>}/>
|
|
116
|
+
<Route path={"*"} element={<NotFoundPage/>}/>
|
|
124
117
|
</Route>
|
|
125
118
|
</RebaseRoutes>
|
|
126
119
|
);
|
|
@@ -1,2 +1,16 @@
|
|
|
1
1
|
@import "tailwindcss";
|
|
2
|
-
@import "@rebasepro/ui/index.css";
|
|
2
|
+
@import "@rebasepro/ui/index.css" layer(base);
|
|
3
|
+
|
|
4
|
+
@source "../node_modules/@rebasepro";
|
|
5
|
+
|
|
6
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
7
|
+
|
|
8
|
+
@layer utilities {
|
|
9
|
+
body {
|
|
10
|
+
@apply w-full min-h-screen bg-surface-50 dark:bg-surface-900 flex flex-col items-center justify-center;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
a {
|
|
14
|
+
@apply text-primary dark:text-primary;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -7,12 +7,12 @@ import "./index.css";
|
|
|
7
7
|
const router = createBrowserRouter([
|
|
8
8
|
{
|
|
9
9
|
path: "/*",
|
|
10
|
-
element: <App
|
|
10
|
+
element: <App/>
|
|
11
11
|
}
|
|
12
12
|
]);
|
|
13
13
|
|
|
14
14
|
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
|
15
15
|
<React.StrictMode>
|
|
16
|
-
<RouterProvider router={router}
|
|
16
|
+
<RouterProvider router={router}/>
|
|
17
17
|
</React.StrictMode>
|
|
18
18
|
);
|
|
@@ -4,25 +4,20 @@
|
|
|
4
4
|
"description": "Rebase application with PostgreSQL backend",
|
|
5
5
|
"private": true,
|
|
6
6
|
"type": "module",
|
|
7
|
-
"workspaces": [
|
|
8
|
-
"frontend",
|
|
9
|
-
"backend",
|
|
10
|
-
"shared"
|
|
11
|
-
],
|
|
12
7
|
"scripts": {
|
|
13
|
-
"dev": "
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"db:studio": "cd backend && pnpm run db:studio"
|
|
8
|
+
"dev": "rebase dev",
|
|
9
|
+
"build": "pnpm -r run build",
|
|
10
|
+
"start": "pnpm --filter \"*-backend\" start",
|
|
11
|
+
"db:generate": "rebase db generate",
|
|
12
|
+
"db:migrate": "rebase db migrate",
|
|
13
|
+
"db:pull": "rebase db pull",
|
|
14
|
+
"db:push": "rebase db push",
|
|
15
|
+
"db:studio": "rebase db studio",
|
|
16
|
+
"schema:generate": "rebase schema generate",
|
|
17
|
+
"generate:sdk": "rebase generate-sdk"
|
|
24
18
|
},
|
|
25
19
|
"devDependencies": {
|
|
20
|
+
"@rebasepro/cli": "workspace:*",
|
|
26
21
|
"concurrently": "^8.2.2",
|
|
27
22
|
"typescript": "^5.9.2"
|
|
28
23
|
},
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example Rebase Script
|
|
3
|
+
*
|
|
4
|
+
* Scripts run OUTSIDE the server and need explicit authentication.
|
|
5
|
+
* Use a Service Key (set in .env as REBASE_SERVICE_KEY) to get admin
|
|
6
|
+
* access — similar to a Firebase Service Account credential.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* # With local dev server running (`pnpm dev` in another terminal):
|
|
10
|
+
* npx tsx scripts/example.ts
|
|
11
|
+
*
|
|
12
|
+
* # With remote backend:
|
|
13
|
+
* REBASE_URL=https://api.yourdomain.com npx tsx scripts/example.ts
|
|
14
|
+
*
|
|
15
|
+
* # Service key can also be passed as env var:
|
|
16
|
+
* REBASE_SERVICE_KEY=<key> REBASE_URL=https://api.yourdomain.com npx tsx scripts/example.ts
|
|
17
|
+
*
|
|
18
|
+
* Generate a service key:
|
|
19
|
+
* node -e "console.log(require('crypto').randomBytes(48).toString('base64'))"
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import fs from "node:fs";
|
|
23
|
+
import path from "node:path";
|
|
24
|
+
import * as dotenv from "dotenv";
|
|
25
|
+
import { createRebaseClient } from "@rebasepro/client";
|
|
26
|
+
// import type { Database } from "../config/database.types"; // Optional: For fully typed collections
|
|
27
|
+
|
|
28
|
+
// Load .env from project root (same file the backend uses)
|
|
29
|
+
dotenv.config({ path: path.resolve(process.cwd(), ".env") });
|
|
30
|
+
|
|
31
|
+
// ─── Resolve Backend URL ─────────────────────────────────────────────
|
|
32
|
+
let baseUrl = process.env.REBASE_URL;
|
|
33
|
+
|
|
34
|
+
if (!baseUrl) {
|
|
35
|
+
try {
|
|
36
|
+
// Try to read the URL from the local dev server
|
|
37
|
+
const urlFile = path.join(process.cwd(), ".rebase-dev-url");
|
|
38
|
+
if (fs.existsSync(urlFile)) {
|
|
39
|
+
baseUrl = fs.readFileSync(urlFile, "utf-8").trim();
|
|
40
|
+
console.log(`Found local dev server running at: ${baseUrl}`);
|
|
41
|
+
}
|
|
42
|
+
} catch (e) {
|
|
43
|
+
// Ignore errors reading the file
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!baseUrl) {
|
|
48
|
+
console.error("❌ No backend URL found!");
|
|
49
|
+
console.error("");
|
|
50
|
+
console.error("Please make sure you have either:");
|
|
51
|
+
console.error("1. Started the local dev server in another terminal (`pnpm dev`)");
|
|
52
|
+
console.error("2. Set the REBASE_URL environment variable (e.g. `REBASE_URL=https://api.yourdomain.com npx tsx scripts/example.ts`)");
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ─── Resolve Service Key ─────────────────────────────────────────────
|
|
57
|
+
const serviceKey = process.env.REBASE_SERVICE_KEY;
|
|
58
|
+
|
|
59
|
+
if (!serviceKey) {
|
|
60
|
+
console.warn("⚠️ No REBASE_SERVICE_KEY found — requests will be unauthenticated.");
|
|
61
|
+
console.warn(" Set REBASE_SERVICE_KEY in your .env to get admin access.");
|
|
62
|
+
console.warn(" Generate one with: node -e \"console.log(require('crypto').randomBytes(48).toString('base64'))\"");
|
|
63
|
+
console.warn("");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ─── Initialize the SDK client ───────────────────────────────────────
|
|
67
|
+
const rebase = createRebaseClient({
|
|
68
|
+
baseUrl,
|
|
69
|
+
// The service key is sent as a Bearer token for admin access
|
|
70
|
+
token: serviceKey
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
async function run() {
|
|
74
|
+
console.log("🚀 Starting script...");
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
// Example: Check backend health
|
|
78
|
+
const health = await fetch(`${baseUrl}/api/health`).then(res => res.json());
|
|
79
|
+
console.log("✅ Backend health:", health);
|
|
80
|
+
|
|
81
|
+
// Example: Fetch some data (requires auth if backend is secure-by-default)
|
|
82
|
+
// const items = await rebase.data.collection("users").find({ limit: 5 });
|
|
83
|
+
// console.log("Items:", items);
|
|
84
|
+
|
|
85
|
+
console.log("✨ Script finished successfully.");
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.error("❌ Script failed:", error);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
run();
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from "child_process";
|
|
3
|
-
|
|
4
|
-
// --- Helper Functions ---
|
|
5
|
-
const formatTerminalText = (text: string, options: {
|
|
6
|
-
bold?: boolean;
|
|
7
|
-
backgroundColor?: "blue" | "green" | "red" | "yellow" | "cyan" | "magenta";
|
|
8
|
-
textColor?: "white" | "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan";
|
|
9
|
-
} = {}): string => {
|
|
10
|
-
let codes = "";
|
|
11
|
-
if (options.bold) codes += "\x1b[1m";
|
|
12
|
-
if (options.backgroundColor) {
|
|
13
|
-
const bgColors = {
|
|
14
|
-
blue: "\x1b[44m",
|
|
15
|
-
green: "\x1b[42m",
|
|
16
|
-
red: "\x1b[41m",
|
|
17
|
-
yellow: "\x1b[43m",
|
|
18
|
-
cyan: "\x1b[46m",
|
|
19
|
-
magenta: "\x1b[45m"
|
|
20
|
-
} as const;
|
|
21
|
-
codes += bgColors[options.backgroundColor];
|
|
22
|
-
}
|
|
23
|
-
if (options.textColor) {
|
|
24
|
-
const textColors = {
|
|
25
|
-
white: "\x1b[37m",
|
|
26
|
-
black: "\x1b[30m",
|
|
27
|
-
red: "\x1b[31m",
|
|
28
|
-
green: "\x1b[32m",
|
|
29
|
-
yellow: "\x1b[33m",
|
|
30
|
-
blue: "\x1b[34m",
|
|
31
|
-
magenta: "\x1b[35m",
|
|
32
|
-
cyan: "\x1b[36m"
|
|
33
|
-
} as const;
|
|
34
|
-
codes += textColors[options.textColor];
|
|
35
|
-
}
|
|
36
|
-
return `${codes}${text}\x1b[0m`;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// Run drizzle-kit generate with the correct env path
|
|
40
|
-
const child = spawn("npx", ["drizzle-kit", "generate"], {
|
|
41
|
-
stdio: "inherit",
|
|
42
|
-
env: {
|
|
43
|
-
...process.env,
|
|
44
|
-
DOTENV_CONFIG_PATH: "../.env"
|
|
45
|
-
},
|
|
46
|
-
shell: true
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
child.on("close", (code) => {
|
|
50
|
-
if (code === 0) {
|
|
51
|
-
console.log("");
|
|
52
|
-
console.log(`You can now run ${formatTerminalText("pnpm db:migrate", {
|
|
53
|
-
bold: true,
|
|
54
|
-
backgroundColor: "green",
|
|
55
|
-
textColor: "black"
|
|
56
|
-
})} to apply the migrations to your database.`);
|
|
57
|
-
console.log("");
|
|
58
|
-
}
|
|
59
|
-
process.exit(code ?? 0);
|
|
60
|
-
});
|