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

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 (72) hide show
  1. package/LICENSE +17 -196
  2. package/README.md +57 -33
  3. package/dist/commands/api-keys.d.ts +1 -0
  4. package/dist/commands/build.d.ts +1 -0
  5. package/dist/commands/cloud/auth.d.ts +3 -0
  6. package/dist/commands/cloud/context.d.ts +61 -0
  7. package/dist/commands/cloud/databases.d.ts +1 -0
  8. package/dist/commands/cloud/deploy.d.ts +2 -0
  9. package/dist/commands/cloud/index.d.ts +1 -0
  10. package/dist/commands/cloud/link.d.ts +5 -0
  11. package/dist/commands/cloud/orgs.d.ts +1 -0
  12. package/dist/commands/cloud/projects.d.ts +13 -0
  13. package/dist/commands/cloud/resources.d.ts +6 -0
  14. package/dist/commands/generate_sdk.d.ts +1 -1
  15. package/dist/commands/init.d.ts +37 -1
  16. package/dist/commands/skills.d.ts +1 -0
  17. package/dist/commands/start.d.ts +1 -0
  18. package/dist/index.d.ts +6 -1
  19. package/dist/index.es.js +3781 -1089
  20. package/dist/index.es.js.map +1 -1
  21. package/dist/utils/package-manager.d.ts +33 -0
  22. package/dist/utils/project.d.ts +16 -1
  23. package/package.json +26 -22
  24. package/templates/overlays/baas/README.md +37 -0
  25. package/templates/overlays/baas/backend/package.json +31 -0
  26. package/templates/overlays/baas/backend/src/index.ts +172 -0
  27. package/templates/overlays/baas/backend/tsconfig.json +18 -0
  28. package/templates/overlays/baas/package.json +42 -0
  29. package/templates/overlays/baas/pnpm-workspace.yaml +9 -0
  30. package/templates/template/.cursorrules +2 -0
  31. package/templates/template/.env.example +25 -1
  32. package/templates/template/.github/copilot-instructions.md +2 -0
  33. package/templates/template/.windsurfrules +2 -0
  34. package/templates/template/AGENTS.md +2 -0
  35. package/templates/template/CLAUDE.md +2 -0
  36. package/templates/template/README.md +6 -6
  37. package/templates/template/ai-instructions.md +17 -0
  38. package/templates/template/backend/Dockerfile +5 -4
  39. package/templates/template/backend/functions/hello.ts +36 -32
  40. package/templates/template/backend/package.json +9 -9
  41. package/templates/template/backend/src/env.ts +13 -42
  42. package/templates/template/backend/src/index.ts +54 -28
  43. package/templates/template/config/collections/authors.ts +2 -2
  44. package/templates/template/config/collections/index.ts +25 -4
  45. package/templates/template/config/collections/posts.ts +12 -32
  46. package/templates/template/config/collections/presets/blank/index.ts +3 -0
  47. package/templates/template/config/collections/presets/ecommerce/categories.ts +40 -0
  48. package/templates/template/config/collections/presets/ecommerce/index.ts +6 -0
  49. package/templates/template/config/collections/presets/ecommerce/orders.ts +66 -0
  50. package/templates/template/config/collections/presets/ecommerce/products.ts +64 -0
  51. package/templates/template/config/collections/tags.ts +3 -5
  52. package/templates/template/config/collections/users.ts +142 -0
  53. package/templates/template/config/index.ts +1 -1
  54. package/templates/template/docker-compose.yml +4 -4
  55. package/templates/template/frontend/Dockerfile +5 -3
  56. package/templates/template/frontend/package.json +8 -7
  57. package/templates/template/frontend/src/App.tsx +22 -22
  58. package/templates/template/frontend/src/main.tsx +4 -0
  59. package/templates/template/frontend/src/virtual.d.ts +6 -0
  60. package/templates/template/frontend/tsconfig.json +3 -2
  61. package/templates/template/frontend/vite.config.ts +16 -3
  62. package/templates/template/package.json +18 -5
  63. package/templates/template/pnpm-workspace.yaml +9 -0
  64. package/templates/template/scripts/example.ts +5 -2
  65. package/dist/auth.d.ts +0 -5
  66. package/dist/commands/cli.test.d.ts +0 -1
  67. package/dist/commands/dev.test.d.ts +0 -1
  68. package/dist/commands/init.test.d.ts +0 -1
  69. package/dist/index.cjs +0 -1306
  70. package/dist/index.cjs.map +0 -1
  71. package/dist/utils/project.test.d.ts +0 -1
  72. package/templates/template/backend/drizzle.config.ts +0 -42
@@ -0,0 +1,33 @@
1
+ export type PackageManager = "pnpm" | "npm";
2
+ export interface PMCommands {
3
+ /** The binary name ("pnpm" | "npm"). */
4
+ name: PackageManager;
5
+ /** Install all dependencies — e.g. `pnpm install` / `npm install`. */
6
+ install: string[];
7
+ /** Run a script — e.g. `pnpm run dev` / `npm run dev`. */
8
+ run: (script: string) => string[];
9
+ /** Execute a local bin — e.g. `pnpm exec rebase ...` / `npx rebase ...`. */
10
+ exec: (bin: string, args: string[]) => string[];
11
+ /** Query the registry — e.g. `pnpm view <pkg> version` / `npm view <pkg> version`. */
12
+ view: (pkg: string, field: string) => string[];
13
+ /** Run all workspace scripts — e.g. `pnpm -r run build` / `npm run build --workspaces`. */
14
+ runAll: (script: string) => string[];
15
+ /** Run a script in a specific workspace — e.g. `pnpm --filter "*-backend" start` / `npm run start -w backend`. */
16
+ runWorkspace: (workspace: string, script: string) => string[];
17
+ /** Execute a one-off package — e.g. `pnpm dlx skills ...` / `npx -y skills ...`. */
18
+ dlx: (pkg: string, args: string[]) => string[];
19
+ /** The workspace dependency protocol: `"workspace:*"` for pnpm, `"*"` for npm. */
20
+ workspaceProtocol: string;
21
+ }
22
+ /**
23
+ * Detect the package manager from the environment or the target directory.
24
+ *
25
+ * Detection order:
26
+ * 1. Explicit override (if provided)
27
+ * 2. `npm_config_user_agent` env var (set by npm/pnpm when running via `npx`/`pnpm dlx`)
28
+ * 3. Lock-file presence in the target directory
29
+ * 4. Default to pnpm (Rebase's recommended PM)
30
+ */
31
+ export declare function detectPackageManager(targetDir?: string): PackageManager;
32
+ /** Build the command helpers for a given package manager. */
33
+ export declare function getPMCommands(pm: PackageManager): PMCommands;
@@ -11,7 +11,7 @@ export declare function findProjectRoot(startDir?: string): string | null;
11
11
  */
12
12
  export declare function findBackendDir(projectRoot: string): string | null;
13
13
  /**
14
- * Detect the active backend plugin (e.g. @rebasepro/server-postgresql) from the backend's package.json.
14
+ * Detect the active backend plugin (e.g. @rebasepro/server-postgres) from the backend's package.json.
15
15
  */
16
16
  export declare function getActiveBackendPlugin(backendDir: string): string | null;
17
17
  /**
@@ -35,6 +35,21 @@ export declare function resolveLocalBin(projectRoot: string, binName: string): s
35
35
  * Resolve the tsx binary. Checks backend node_modules first, then root.
36
36
  */
37
37
  export declare function resolveTsx(projectRoot: string): string | null;
38
+ /**
39
+ * Validate that a resolved tsx binary actually has an intact installation.
40
+ *
41
+ * `resolveLocalBin` only checks whether `node_modules/.bin/tsx` (a symlink)
42
+ * exists. If the pnpm content-addressable store was cleaned or a previous
43
+ * install was interrupted, the symlink can exist while critical files inside
44
+ * the tsx package (e.g. `dist/preflight.cjs`) are missing — causing a
45
+ * confusing MODULE_NOT_FOUND error at runtime.
46
+ *
47
+ * This function follows the symlink, walks up to find the tsx package root
48
+ * (`package.json` with `name: "tsx"`), and verifies that `dist/preflight.cjs`
49
+ * is present. Returns `null` when the installation looks healthy, or an
50
+ * error description string when it appears corrupted.
51
+ */
52
+ export declare function validateTsxInstallation(tsxBinPath: string): string | null;
38
53
  /**
39
54
  * Require the project root or exit with a helpful error.
40
55
  */
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@rebasepro/cli",
3
- "version": "0.0.1-canary.f81da60",
3
+ "version": "0.0.1-canary.fc811d7",
4
4
  "description": "Developer tools for Rebase projects",
5
- "main": "./dist/index.cjs",
5
+ "main": "./dist/index.es.js",
6
6
  "module": "./dist/index.es.js",
7
7
  "types": "./dist/index.d.ts",
8
8
  "type": "module",
@@ -26,21 +26,25 @@
26
26
  "license": "MIT",
27
27
  "dependencies": {
28
28
  "arg": "^5.0.2",
29
- "chalk": "^4.1.2",
30
- "dotenv": "^16.0.0",
31
- "execa": "^4.1.0",
32
- "inquirer": "12.11.1",
33
- "ncp": "^2.0.0",
34
- "pnpm": "^9.0.0",
35
- "@rebasepro/server-core": "0.0.1-canary.f81da60",
36
- "@rebasepro/sdk-generator": "0.0.1-canary.f81da60",
37
- "@rebasepro/types": "0.0.1-canary.f81da60"
29
+ "chalk": "^5.6.2",
30
+ "dotenv": "^17.4.2",
31
+ "execa": "^9.6.1",
32
+ "inquirer": "14.0.2",
33
+ "jiti": "^2.7.0",
34
+ "@rebasepro/agent-skills": "0.0.1-canary.fc811d7",
35
+ "@rebasepro/codegen": "0.0.1-canary.fc811d7",
36
+ "@rebasepro/client": "0.0.1-canary.fc811d7",
37
+ "@rebasepro/server": "0.0.1-canary.fc811d7",
38
+ "@rebasepro/types": "0.0.1-canary.fc811d7",
39
+ "@rebasepro/server-postgres": "0.0.1-canary.fc811d7"
38
40
  },
39
41
  "devDependencies": {
40
- "@types/node": "^20.19.17",
41
- "typescript": "^5.9.3",
42
- "vite": "^7.2.4",
43
- "vitest": "4.1.5"
42
+ "@types/node": "^25.9.3",
43
+ "@types/pg": "^8.20.0",
44
+ "pg": "^8.21.0",
45
+ "typescript": "^6.0.3",
46
+ "vite": "^8.0.16",
47
+ "vitest": "4.1.8"
44
48
  },
45
49
  "files": [
46
50
  "bin/",
@@ -50,17 +54,17 @@
50
54
  "exports": {
51
55
  ".": {
52
56
  "types": "./dist/index.d.ts",
53
- "import": "./dist/index.es.js",
54
- "require": "./dist/index.cjs"
57
+ "import": "./dist/index.es.js"
55
58
  }
56
59
  },
57
- "exclude": [
58
- "node_modules",
59
- "templates/template/node_modules"
60
- ],
61
- "gitHead": "d935eefa5aa8d1009a2398cfac2c1e4ee9aeb6b6",
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "https://github.com/rebasepro/rebase.git",
63
+ "directory": "packages/cli"
64
+ },
62
65
  "scripts": {
63
66
  "test": "vitest run",
67
+ "test:e2e": "vitest run --config vitest.e2e.config.ts",
64
68
  "build": "vite build && tsc --emitDeclarationOnly -p tsconfig.json",
65
69
  "clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f"
66
70
  }
@@ -0,0 +1,37 @@
1
+ # {{PROJECT_NAME}}
2
+
3
+ A headless Rebase backend: a REST API, auth, storage, realtime and backups over
4
+ your PostgreSQL database.
5
+
6
+ There are no collection files. The server reads your database schema at boot and
7
+ serves every table, so the API follows your migrations — change the schema and
8
+ the endpoints change with it.
9
+
10
+ ## Run it
11
+
12
+ ```bash
13
+ pnpm install
14
+ pnpm dev
15
+ ```
16
+
17
+ - API: `http://localhost:3001/api/data/<table>`
18
+ - Docs: `http://localhost:3001/api/swagger`
19
+ - Health: `http://localhost:3001/health`
20
+
21
+ Set `DATABASE_URL` in `.env` to point at your database.
22
+
23
+ ## Use it from an app
24
+
25
+ ```ts
26
+ import { createRebaseClient } from "@rebasepro/client";
27
+
28
+ const rebase = createRebaseClient({ baseUrl: "http://localhost:3001" });
29
+ const posts = await rebase.data.collection("posts").find();
30
+ ```
31
+
32
+ ## Adding an admin UI later
33
+
34
+ Nothing here locks you out of it. Switch `mode` to `"cms"` in
35
+ `backend/src/index.ts`, add a `config/collections` directory, and add a frontend
36
+ that renders them. See MODULAR-ARCHITECTURE.md in the Rebase repo for the three
37
+ adoption modes.
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "{{PROJECT_NAME}}-backend",
3
+ "version": "1.0.0",
4
+ "description": "Rebase BaaS — headless PostgreSQL API",
5
+ "main": "src/index.ts",
6
+ "type": "module",
7
+ "scripts": {
8
+ "dev": "tsx watch src/index.ts",
9
+ "build": "tsc",
10
+ "start": "node dist/backend/src/index.js"
11
+ },
12
+ "dependencies": {
13
+ "@rebasepro/server": "workspace:*",
14
+ "@rebasepro/server-postgres": "workspace:*",
15
+ "@rebasepro/types": "workspace:*",
16
+ "drizzle-orm": "^0.45.2",
17
+ "hono": "^4.12.10",
18
+ "@hono/node-server": "^1.19.12",
19
+ "pg": "^8.11.3",
20
+ "ws": "^8.16.0",
21
+ "dotenv": "^16.0.0",
22
+ "zod": "^4.4.3"
23
+ },
24
+ "devDependencies": {
25
+ "@types/pg": "^8.6.5",
26
+ "@types/node": "^20.10.5",
27
+ "@types/ws": "^8.5.10",
28
+ "tsx": "^4.20.6",
29
+ "typescript": "^5.9.2"
30
+ }
31
+ }
@@ -0,0 +1,172 @@
1
+ import { Hono } from "hono";
2
+ import { cors } from "hono/cors";
3
+ import { secureHeaders } from "hono/secure-headers";
4
+ import { getRequestListener } from "@hono/node-server";
5
+ import { createServer } from "http";
6
+ import path from "path";
7
+ import { fileURLToPath } from "url";
8
+ import {
9
+ initializeRebaseBackend,
10
+ installShutdownHandlers,
11
+ HonoEnv,
12
+ listenWithPortRetry,
13
+ cleanupDevPortFile,
14
+ logger
15
+ } from "@rebasepro/server";
16
+ import { createPostgresDatabaseConnection, createPostgresAdapter } from "@rebasepro/server-postgres";
17
+ import { env } from "./env.js";
18
+
19
+ const __filename = fileURLToPath(import.meta.url);
20
+ const __dirname = path.dirname(__filename);
21
+
22
+ // ─── App ─────────────────────────────────────────────────────────────
23
+ const app: Hono<HonoEnv> = new Hono<HonoEnv>();
24
+
25
+ const isProduction = env.NODE_ENV === "production";
26
+ const allowedOrigins = isProduction
27
+ ? (() => {
28
+ const origins = env.CORS_ORIGINS || env.FRONTEND_URL;
29
+ if (!origins) {
30
+ throw new Error(
31
+ "CORS_ORIGINS or FRONTEND_URL must be set in production. " +
32
+ "Example: CORS_ORIGINS=https://yourdomain.com"
33
+ );
34
+ }
35
+ return origins.split(",").map(s => s.trim());
36
+ })()
37
+ : [];
38
+
39
+ app.use("/*", cors({
40
+ origin: (origin) => {
41
+ if (!isProduction) return origin || "*";
42
+ return allowedOrigins.includes(origin) ? origin : null;
43
+ },
44
+ credentials: true
45
+ }));
46
+
47
+ app.use("/*", secureHeaders());
48
+
49
+ // ─── Database ────────────────────────────────────────────────────────
50
+ const databaseUrl = env.DATABASE_URL;
51
+
52
+ const { db, pool, connectionString } = createPostgresDatabaseConnection(databaseUrl);
53
+
54
+ // ─── Start ───────────────────────────────────────────────────────────
55
+ async function startServer() {
56
+ const jwtSecret = env.JWT_SECRET;
57
+ const PORT = env.PORT;
58
+ const server = createServer(getRequestListener(app.fetch));
59
+
60
+ const backend = await initializeRebaseBackend({
61
+ // BaaS mode: every RLS-protected table is served over REST. There are
62
+ // no collection files to write or keep in sync — change the schema with
63
+ // a migration and the API follows.
64
+ //
65
+ // Your database's own row-level security is the whole authorization
66
+ // model here: requests run as the `rebase_user` role, so a table
67
+ // without RLS has no rules at all and is not served. Protect one with:
68
+ // ALTER TABLE mytable ENABLE ROW LEVEL SECURITY;
69
+ // CREATE POLICY mytable_read ON mytable FOR SELECT TO public USING (true);
70
+ mode: "baas",
71
+ functionsDir: path.resolve(__dirname, "../functions"),
72
+ server,
73
+ app,
74
+ database: createPostgresAdapter({
75
+ connection: db,
76
+ adminConnectionString: env.ADMIN_CONNECTION_STRING || databaseUrl,
77
+ connectionString
78
+ }),
79
+ auth: {
80
+ // No `collection` here: BaaS mode has no collection files, and the
81
+ // auth adapter owns its own user tables.
82
+ jwtSecret,
83
+ accessExpiresIn: env.JWT_ACCESS_EXPIRES_IN,
84
+ refreshExpiresIn: env.JWT_REFRESH_EXPIRES_IN,
85
+ serviceKey: env.REBASE_SERVICE_KEY,
86
+ cookieAuth: { sameSite: "Lax" },
87
+ google: env.GOOGLE_CLIENT_ID
88
+ ? { clientId: env.GOOGLE_CLIENT_ID }
89
+ : undefined,
90
+ allowRegistration: env.ALLOW_REGISTRATION,
91
+ email: env.SMTP_HOST
92
+ ? {
93
+ from: env.SMTP_FROM || `${env.APP_NAME} <noreply@rebase.pro>`,
94
+ smtp: {
95
+ host: env.SMTP_HOST,
96
+ port: env.SMTP_PORT,
97
+ secure: env.SMTP_SECURE,
98
+ auth: env.SMTP_USER
99
+ ? { user: env.SMTP_USER,
100
+ pass: env.SMTP_PASS! }
101
+ : undefined,
102
+ name: env.SMTP_NAME
103
+ },
104
+ appName: env.APP_NAME,
105
+ resetPasswordUrl: env.FRONTEND_URL
106
+ }
107
+ : undefined
108
+ },
109
+ storage: env.STORAGE_TYPE === "s3"
110
+ ? {
111
+ type: "s3",
112
+ bucket: env.S3_BUCKET!,
113
+ region: env.S3_REGION || "auto",
114
+ accessKeyId: env.S3_ACCESS_KEY_ID || "",
115
+ secretAccessKey: env.S3_SECRET_ACCESS_KEY || "",
116
+ endpoint: env.S3_ENDPOINT,
117
+ forcePathStyle: env.S3_FORCE_PATH_STYLE
118
+ }
119
+ : {
120
+ type: "local",
121
+ basePath: env.STORAGE_PATH || path.resolve(__dirname, "../../uploads")
122
+ },
123
+ history: true,
124
+ enableSwagger: true
125
+ });
126
+
127
+ // ─── Health check ─────────────────────────────────────────────
128
+ app.get("/health", async (c) => {
129
+ const result = await backend.healthCheck();
130
+ const status = result.healthy ? 200 : 503;
131
+ return c.json({
132
+ status: result.healthy ? "ok" : "degraded",
133
+ latencyMs: result.latencyMs,
134
+ ...(result.details ? { details: result.details } : {})
135
+ }, status);
136
+ });
137
+
138
+ // No serveSPA: this is a headless API. Point any frontend at it over HTTP.
139
+
140
+ if (!isProduction) {
141
+ // Dev mode: retry the next port if the current one is in use
142
+ const projectRoot = path.resolve(__dirname, "../..");
143
+ const actualPort = await listenWithPortRetry(server, PORT, { portFileDir: projectRoot, serviceKey: env.REBASE_SERVICE_KEY });
144
+
145
+ // Clean up port file on exit
146
+ const cleanup = () => cleanupDevPortFile(projectRoot);
147
+ process.on("SIGINT", cleanup);
148
+ process.on("SIGTERM", cleanup);
149
+ process.on("exit", cleanup);
150
+
151
+ logger.info(`API running at http://localhost:${actualPort}`);
152
+ logger.info(`API docs at http://localhost:${actualPort}/api/swagger`);
153
+ } else {
154
+ server.listen(PORT, () => {
155
+ logger.info(`API running at http://localhost:${PORT}`);
156
+ });
157
+ }
158
+
159
+ // ─── Graceful Shutdown ───────────────────────────────────────────────
160
+ // Drains HTTP, stops crons, tears down realtime, then closes the pool.
161
+ // Guards against double signals and force-exits if shutdown hangs.
162
+ installShutdownHandlers(backend, {
163
+ onCleanup: () => pool.end()
164
+ });
165
+ }
166
+
167
+ startServer().catch(err => {
168
+ logger.error("Failed to start server", { error: err instanceof Error ? err : new Error(String(err)) });
169
+ process.exit(1);
170
+ });
171
+
172
+ export { app };
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "node",
6
+ "lib": ["ES2022"],
7
+ "outDir": "./dist",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "allowSyntheticDefaultImports": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "resolveJsonModule": true,
14
+ "declaration": true,
15
+ "sourceMap": true
16
+ },
17
+ "include": ["src/**/*", "drizzle.config.ts"]
18
+ }
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "{{PROJECT_NAME}}",
3
+ "version": "1.0.0",
4
+ "description": "Rebase BaaS — headless PostgreSQL API",
5
+ "private": true,
6
+ "type": "module",
7
+ "workspaces": [
8
+ "backend"
9
+ ],
10
+ "scripts": {
11
+ "dev": "rebase dev",
12
+ "build": "rebase build",
13
+ "start": "rebase start",
14
+ "db:migrate": "rebase db migrate",
15
+ "schema:introspect": "rebase schema introspect",
16
+ "generate:sdk": "rebase generate-sdk",
17
+ "skills:install": "rebase skills install",
18
+ "example": "tsx scripts/example.ts",
19
+ "deploy": "rebase build && rebase start"
20
+ },
21
+ "devDependencies": {
22
+ "@rebasepro/cli": "workspace:*",
23
+ "@rebasepro/types": "workspace:*",
24
+ "concurrently": "^8.2.2",
25
+ "tsx": "^4.20.6",
26
+ "typescript": "^5.9.2"
27
+ },
28
+ "dependencies": {
29
+ "@rebasepro/client": "workspace:*",
30
+ "dotenv": "^16.0.0"
31
+ },
32
+ "engines": {
33
+ "node": ">=18.0.0"
34
+ },
35
+ "pnpm": {
36
+ "onlyBuiltDependencies": [
37
+ "esbuild",
38
+ "sharp",
39
+ "@ariga/atlas"
40
+ ]
41
+ }
42
+ }
@@ -0,0 +1,9 @@
1
+ packages:
2
+ - "backend"
3
+ linkWorkspacePackages: true
4
+ blockExoticSubdeps: false
5
+ minimumReleaseAge: 0
6
+ allowBuilds:
7
+ esbuild: true
8
+ sharp: true
9
+ "@ariga/atlas": true
@@ -0,0 +1,2 @@
1
+ # Rebase AI Rules
2
+ Please refer to and follow the instructions defined in [ai-instructions.md](./ai-instructions.md).
@@ -7,8 +7,12 @@
7
7
  # Database connection string (required)
8
8
  # You can use PostgreSQL (postgresql://) or MongoDB (mongodb:// or mongodb+srv://).
9
9
  # The backend will automatically detect the database type.
10
- DATABASE_URL=postgresql://rebase:changeme@localhost:5432/rebase
10
+ DATABASE_URL=postgresql://rebase:changeme@localhost:5432/rebase?options=-c%20search_path=public
11
11
  # DATABASE_URL=mongodb://localhost:27017/rebase
12
+ #
13
+ # Local Postgres without SSL? If you see "SSL is not enabled on the server",
14
+ # append &sslmode=disable to the connection string, e.g.:
15
+ # DATABASE_URL=postgresql://rebase:changeme@localhost:5432/rebase?options=-c%20search_path=public&sslmode=disable
12
16
 
13
17
  # Separate admin connection string for migrations and schema operations (optional)
14
18
  # Falls back to DATABASE_URL if not set
@@ -22,6 +26,8 @@ DATABASE_URL=postgresql://rebase:changeme@localhost:5432/rebase
22
26
  # ── Server ────────────────────────────────────────────────────────────────────
23
27
  PORT=3001
24
28
  NODE_ENV=development
29
+ # Allow connecting to localhost / 127.0.0.1 in production mode (for local testing of prod builds)
30
+ # ALLOW_LOCALHOST_IN_PRODUCTION=false
25
31
 
26
32
  # ── Logging ───────────────────────────────────────────────────────────────────
27
33
  # Levels: error, warn, info, debug
@@ -44,6 +50,7 @@ ALLOW_REGISTRATION=true
44
50
  # SMTP_USER=
45
51
  # SMTP_PASS=
46
52
  # SMTP_FROM=noreply@yourapp.com
53
+ # SMTP_NAME=
47
54
  # APP_NAME=Your App Name
48
55
 
49
56
  # ── URLs ──────────────────────────────────────────────────────────────────────
@@ -90,7 +97,24 @@ VITE_API_URL=http://localhost:3001
90
97
  # For native GCS SDK or other providers (Azure Blob, etc.), implement the
91
98
  # StorageController interface and pass it directly in your backend config.
92
99
 
100
+ # ── Backups (optional) ────────────────────────────────────────────────────────
101
+ # Manual backups: `rebase db backup --out ./backups` (or an s3://… URL).
102
+ # Scheduled backups: set BACKUP_SCHEDULE and add a cron file in backend/crons
103
+ # that default-exports createBackupCron (from @rebasepro/server-postgres).
104
+ # Backups contain secrets & PII — use a PRIVATE destination with encryption-at-rest.
105
+ # BACKUP_SCHEDULE=0 3 * * * # cron expression; unset ⇒ scheduled backups off
106
+ # BACKUP_DESTINATION=./backups # local path, or s3://bucket/prefix / gs://bucket/prefix
107
+ # BACKUP_RETENTION_DAYS=14 # delete backups older than N days (unset/0 ⇒ keep all)
108
+ # BACKUP_KEEP_MINIMUM=3 # always retain at least N most-recent backups
109
+ # PG_DUMP_PATH= # override pg_dump binary (must match server major version)
110
+ # PG_RESTORE_PATH= # override pg_restore binary
111
+
93
112
  # ── Admin Service Key (optional) ──────────────────────────────────────────────
94
113
  # When set, scripts authenticate with: Authorization: Bearer <key>
95
114
  # Generate with: node -e "console.log(require('crypto').randomBytes(48).toString('base64'))"
96
115
  # REBASE_SERVICE_KEY=
116
+
117
+ # Disable switching to database-level roles (e.g. 'admin') for Studio SQL execution (optional)
118
+ # Falls back to false. Useful for databases with application-only roles or managed setups.
119
+ # DISABLE_DB_ROLE_SWITCHING=true
120
+
@@ -0,0 +1,2 @@
1
+ # Rebase AI Rules
2
+ Please refer to and follow the instructions defined in [ai-instructions.md](../ai-instructions.md).
@@ -0,0 +1,2 @@
1
+ # Rebase AI Rules
2
+ Please refer to and follow the instructions defined in [ai-instructions.md](./ai-instructions.md).
@@ -0,0 +1,2 @@
1
+ # Rebase AI Rules
2
+ Please refer to and follow the instructions defined in [ai-instructions.md](./ai-instructions.md).
@@ -0,0 +1,2 @@
1
+ # Rebase AI Rules
2
+ Please refer to and follow the instructions defined in [ai-instructions.md](./ai-instructions.md).
@@ -23,15 +23,15 @@ 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)
27
- - A PostgreSQL database
26
+ - [pnpm](https://pnpm.io) or [npm](https://www.npmjs.com) (v7+)
27
+ - A PostgreSQL database (you can start the included database container via `docker compose up -d db`)
28
28
 
29
29
  #### Setup
30
30
 
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:
@@ -44,14 +44,14 @@ cp .env.example .env
44
44
  3. Generate schema and push to database:
45
45
 
46
46
  ```bash
47
- rebase schema generate
48
- rebase db push
47
+ pnpm run schema:generate # or: npm run schema:generate
48
+ pnpm run db:push # or: npm run db:push
49
49
  ```
50
50
 
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.
@@ -0,0 +1,17 @@
1
+ # Rebase AI Coding Rules
2
+
3
+ Rebase provides agent skills for AI coding assistants (Cursor, Claude Code, Windsurf, Gemini CLI, Antigravity, and more) with detailed guidelines, architecture, SDK APIs, and troubleshooting guides.
4
+
5
+ To install skills for your environment, run:
6
+
7
+ ```
8
+ rebase skills install
9
+ ```
10
+
11
+ ## Core Tenets (Quick Reference)
12
+
13
+ 1. **Schema-as-Code**: Always define or edit collections in `config/collections/` (e.g., `config/collections/posts.ts`). Never modify generated Drizzle schemas or PostgreSQL tables manually.
14
+ 2. **Two-Step Migrations**:
15
+ - Step 1: Run `rebase schema generate` to compile collections to the Drizzle schema.
16
+ - Step 2: Run `rebase db push` (development) or `rebase db generate && rebase db migrate` (production) to apply schema changes to the database.
17
+ 3. **Use the SDK**: Always use the Rebase SDK (`rebase.data.<slug>`) to fetch or modify data. Bypassing it with raw SQL or direct Drizzle/PG queries circumvents model validations, lifecycle hooks, and Row-Level Security (RLS).
@@ -14,12 +14,12 @@ ENV PATH="$PNPM_HOME:$PATH"
14
14
  RUN corepack enable
15
15
 
16
16
  # Native dependencies for bcrypt, pg, etc.
17
- RUN apk add --no-cache python3 make g++
17
+ RUN apk add --no-cache python3 make g++ curl ca-certificates
18
18
 
19
19
  WORKDIR /app
20
20
 
21
21
  # Copy workspace root files first (cache-friendly layer)
22
- COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
22
+ COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
23
23
 
24
24
  # Copy workspace packages
25
25
  COPY backend ./backend
@@ -33,7 +33,7 @@ RUN pnpm --filter "*-config" run build
33
33
  RUN pnpm --filter "*-backend" run build
34
34
 
35
35
  # Prune dev dependencies for a smaller runtime
36
- RUN pnpm install --frozen-lockfile --prod
36
+ RUN CI=true pnpm install --frozen-lockfile --prod
37
37
 
38
38
  # ── Stage 2: Production Runtime ──────────────────────────────────────
39
39
  FROM node:22-alpine AS runtime
@@ -41,6 +41,7 @@ FROM node:22-alpine AS runtime
41
41
  ENV PNPM_HOME="/pnpm"
42
42
  ENV PATH="$PNPM_HOME:$PATH"
43
43
  ENV NODE_ENV=production
44
+ ENV CI=true
44
45
 
45
46
  RUN corepack enable
46
47
 
@@ -50,7 +51,7 @@ RUN addgroup -g 1001 rebase && adduser -u 1001 -G rebase -s /bin/sh -D rebase
50
51
  WORKDIR /app
51
52
 
52
53
  # Copy only production artifacts
53
- COPY --from=builder /app/package.json /app/pnpm-lock.yaml /app/pnpm-workspace.yaml ./
54
+ COPY --from=builder /app/package.json /app/pnpm-lock.yaml /app/pnpm-workspace.yaml /app/.npmrc ./
54
55
  COPY --from=builder /app/node_modules ./node_modules
55
56
  COPY --from=builder /app/backend ./backend
56
57
  COPY --from=builder /app/config ./config