@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.
Files changed (48) hide show
  1. package/dist/commands/auth.d.ts +1 -0
  2. package/dist/commands/cli.test.d.ts +1 -0
  3. package/dist/commands/db.d.ts +1 -0
  4. package/dist/commands/dev.d.ts +1 -0
  5. package/dist/commands/dev.test.d.ts +1 -0
  6. package/dist/commands/doctor.d.ts +1 -0
  7. package/dist/commands/generate_sdk.d.ts +18 -0
  8. package/dist/commands/init.d.ts +1 -0
  9. package/dist/commands/init.test.d.ts +1 -0
  10. package/dist/commands/schema.d.ts +1 -0
  11. package/dist/index.cjs +986 -27
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.ts +5 -0
  14. package/dist/index.es.js +987 -26
  15. package/dist/index.es.js.map +1 -1
  16. package/dist/utils/project.d.ts +45 -0
  17. package/dist/utils/project.test.d.ts +1 -0
  18. package/package.json +20 -11
  19. package/templates/template/.dockerignore +28 -0
  20. package/templates/template/.env.template +42 -11
  21. package/templates/template/README.md +74 -17
  22. package/templates/template/backend/Dockerfile +55 -10
  23. package/templates/template/backend/functions/hello.ts +52 -0
  24. package/templates/template/backend/package.json +30 -34
  25. package/templates/template/backend/src/env.ts +52 -0
  26. package/templates/template/backend/src/index.ts +113 -99
  27. package/templates/template/backend/tsconfig.json +1 -1
  28. package/templates/template/config/collections/authors.ts +45 -0
  29. package/templates/template/config/collections/index.ts +5 -0
  30. package/templates/template/{shared → config}/collections/posts.ts +40 -2
  31. package/templates/template/config/collections/tags.ts +27 -0
  32. package/templates/template/config/package.json +28 -0
  33. package/templates/template/docker-compose.yml +77 -16
  34. package/templates/template/frontend/Dockerfile +36 -14
  35. package/templates/template/frontend/nginx.conf +40 -0
  36. package/templates/template/frontend/package.json +9 -10
  37. package/templates/template/frontend/src/App.tsx +26 -33
  38. package/templates/template/frontend/src/index.css +15 -1
  39. package/templates/template/frontend/src/main.tsx +2 -2
  40. package/templates/template/frontend/vite.config.ts +1 -1
  41. package/templates/template/package.json +11 -16
  42. package/templates/template/pnpm-workspace.yaml +4 -0
  43. package/templates/template/scripts/example.ts +91 -0
  44. package/templates/template/backend/scripts/db-generate.ts +0 -60
  45. package/templates/template/shared/collections/index.ts +0 -3
  46. package/templates/template/shared/package.json +0 -28
  47. /package/templates/template/{shared → config}/index.ts +0 -0
  48. /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
- version: '3.8'
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: 5
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
- - DATABASE_URL=postgresql://rebase:${POSTGRES_PASSWORD}@db:5432/rebase
28
- - JWT_SECRET=${JWT_SECRET}
29
- - NODE_ENV=development
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
- - ./backend/uploads:/app/backend/uploads
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
- - "5173:5173"
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
- FROM node:24-alpine AS base
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 configurations
10
- COPY package.json ./
19
+ # Copy workspace root files
20
+ COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
11
21
 
12
- # Copy internal workspaces
22
+ # Copy workspace packages
13
23
  COPY frontend ./frontend
14
- COPY shared ./shared
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
- # Build shared and frontend
20
- RUN pnpm run build:shared
21
- RUN pnpm run build:frontend
45
+ EXPOSE 80
22
46
 
23
- # Install a simple static server
24
- RUN npm install -g serve
47
+ HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
48
+ CMD wget --no-verbose --tries=1 --spider http://localhost:80/ || exit 1
25
49
 
26
- WORKDIR /app/frontend
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": "^4.0.0",
8
- "@rebasepro/core": "^4.0.0",
9
- "@rebasepro/data_enhancement": "^4.0.0",
10
- "@rebasepro/data_export": "^4.0.0",
11
- "@rebasepro/data_import": "^4.0.0",
12
- "@rebasepro/postgresql": "^4.0.0",
13
- "@rebasepro/studio": "^4.0.0",
14
- "@rebasepro/types": "^4.0.0",
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}}-shared": "workspace:*",
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
- useBackendStorageSource,
25
- useBuildCMSUrlController,
22
+ useBuildUrlController,
26
23
  useBuildCollectionRegistryController,
27
24
  useBuildLocalConfigurationPersistence,
28
25
  useBuildModeController,
29
26
  useBuildNavigationStateController
30
27
  } from "@rebasepro/core";
31
- import { usePostgresClientDataSource } from "@rebasepro/postgresql";
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
- apiUrl: API_URL,
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
- apiUrl: API_URL,
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 cmsUrlController = useBuildCMSUrlController({
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
- dataSource: postgresDelegate,
70
+ data: rebaseClient.data,
79
71
  collectionRegistryController,
80
- cmsUrlController,
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
- cmsUrlController={cmsUrlController}
83
+ urlController={urlController}
90
84
  navigationStateController={navigationStateController}
91
85
  authController={authController}
92
86
  userConfigPersistence={userConfigPersistence}
93
- dataSource={postgresDelegate}
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
  );
@@ -21,6 +21,6 @@ export default defineConfig({
21
21
  svgr(),
22
22
  react({}),
23
23
  tailwindcss(),
24
- rebaseCollectionsPlugin({ collectionsDir: "../shared/collections" })
24
+ rebaseCollectionsPlugin({ collectionsDir: "../config/collections" })
25
25
  ]
26
26
  });
@@ -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": "concurrently \"pnpm run dev:backend\" \"pnpm run dev:frontend\"",
14
- "dev:frontend": "cd frontend && pnpm run dev",
15
- "dev:backend": "cd backend && pnpm run dev",
16
- "build": "pnpm run build:shared && pnpm run build:frontend && pnpm run build:backend",
17
- "build:shared": "cd shared && pnpm run build",
18
- "build:frontend": "cd frontend && pnpm run build",
19
- "build:backend": "cd backend && pnpm run build",
20
- "start": "cd backend && pnpm start",
21
- "db:generate": "cd backend && pnpm run db:generate",
22
- "db:migrate": "cd backend && pnpm run db:migrate",
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,4 @@
1
+ packages:
2
+ - "frontend"
3
+ - "backend"
4
+ - "config"
@@ -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
- });
@@ -1,3 +0,0 @@
1
- import postsCollection from "./posts";
2
-
3
- export const collections = [postsCollection];