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

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 (74) 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 +39 -0
  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 +3785 -990
  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 -23
  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/.dockerignore +1 -1
  32. package/templates/template/.env.example +120 -0
  33. package/templates/template/.github/copilot-instructions.md +2 -0
  34. package/templates/template/.windsurfrules +2 -0
  35. package/templates/template/AGENTS.md +2 -0
  36. package/templates/template/CLAUDE.md +2 -0
  37. package/templates/template/README.md +20 -10
  38. package/templates/template/ai-instructions.md +17 -0
  39. package/templates/template/backend/Dockerfile +5 -4
  40. package/templates/template/backend/functions/hello.ts +36 -32
  41. package/templates/template/backend/package.json +11 -11
  42. package/templates/template/backend/src/env.ts +13 -42
  43. package/templates/template/backend/src/index.ts +54 -28
  44. package/templates/template/config/collections/authors.ts +2 -2
  45. package/templates/template/config/collections/index.ts +25 -4
  46. package/templates/template/config/collections/posts.ts +15 -35
  47. package/templates/template/config/collections/presets/blank/index.ts +3 -0
  48. package/templates/template/config/collections/presets/ecommerce/categories.ts +40 -0
  49. package/templates/template/config/collections/presets/ecommerce/index.ts +6 -0
  50. package/templates/template/config/collections/presets/ecommerce/orders.ts +66 -0
  51. package/templates/template/config/collections/presets/ecommerce/products.ts +64 -0
  52. package/templates/template/config/collections/tags.ts +3 -5
  53. package/templates/template/config/collections/users.ts +142 -0
  54. package/templates/template/config/index.ts +1 -1
  55. package/templates/template/docker-compose.yml +14 -39
  56. package/templates/template/frontend/Dockerfile +5 -3
  57. package/templates/template/frontend/package.json +8 -7
  58. package/templates/template/frontend/src/App.tsx +26 -105
  59. package/templates/template/frontend/src/main.tsx +4 -0
  60. package/templates/template/frontend/src/virtual.d.ts +6 -0
  61. package/templates/template/frontend/tsconfig.json +3 -2
  62. package/templates/template/frontend/vite.config.ts +47 -4
  63. package/templates/template/package.json +22 -8
  64. package/templates/template/pnpm-workspace.yaml +9 -0
  65. package/templates/template/scripts/example.ts +5 -2
  66. package/dist/auth.d.ts +0 -5
  67. package/dist/commands/cli.test.d.ts +0 -1
  68. package/dist/commands/dev.test.d.ts +0 -1
  69. package/dist/commands/init.test.d.ts +0 -1
  70. package/dist/index.cjs +0 -1203
  71. package/dist/index.cjs.map +0 -1
  72. package/dist/utils/project.test.d.ts +0 -1
  73. package/templates/template/.env.template +0 -62
  74. package/templates/template/backend/drizzle.config.ts +0 -22
@@ -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.eae7889",
3
+ "version": "0.0.1-canary.eb08332",
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,22 +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
- "jiti": "^2.4.2",
34
- "ncp": "^2.0.0",
35
- "pnpm": "^9.0.0",
36
- "@rebasepro/sdk-generator": "0.0.1-canary.eae7889",
37
- "@rebasepro/server-core": "0.0.1-canary.eae7889",
38
- "@rebasepro/types": "0.0.1-canary.eae7889"
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.eb08332",
35
+ "@rebasepro/client": "0.0.1-canary.eb08332",
36
+ "@rebasepro/server": "0.0.1-canary.eb08332",
37
+ "@rebasepro/types": "0.0.1-canary.eb08332",
38
+ "@rebasepro/codegen": "0.0.1-canary.eb08332",
39
+ "@rebasepro/server-postgres": "0.0.1-canary.eb08332"
39
40
  },
40
41
  "devDependencies": {
41
- "@types/node": "^20.19.17",
42
- "typescript": "^5.9.3",
43
- "vite": "^7.2.4",
44
- "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"
45
48
  },
46
49
  "files": [
47
50
  "bin/",
@@ -51,17 +54,17 @@
51
54
  "exports": {
52
55
  ".": {
53
56
  "types": "./dist/index.d.ts",
54
- "import": "./dist/index.es.js",
55
- "require": "./dist/index.cjs"
57
+ "import": "./dist/index.es.js"
56
58
  }
57
59
  },
58
- "exclude": [
59
- "node_modules",
60
- "templates/template/node_modules"
61
- ],
62
- "gitHead": "d935eefa5aa8d1009a2398cfac2c1e4ee9aeb6b6",
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "https://github.com/rebasepro/rebase.git",
63
+ "directory": "packages/cli"
64
+ },
63
65
  "scripts": {
64
66
  "test": "vitest run",
67
+ "test:e2e": "vitest run --config vitest.e2e.config.ts",
65
68
  "build": "vite build && tsc --emitDeclarationOnly -p tsconfig.json",
66
69
  "clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f"
67
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).
@@ -16,7 +16,7 @@ node_modules
16
16
  # Environment (secrets should be injected, not baked in)
17
17
  .env
18
18
  .env.local
19
- .env.*.local
19
+ .env.example
20
20
 
21
21
  # Docker
22
22
  docker-compose*.yml
@@ -0,0 +1,120 @@
1
+ # ╔══════════════════════════════════════════════════════════════════════════════╗
2
+ # ║ Rebase Environment Configuration ║
3
+ # ║ Copy this file to .env and fill in the values ║
4
+ # ╚══════════════════════════════════════════════════════════════════════════════╝
5
+
6
+ # ── Database ──────────────────────────────────────────────────────────────────
7
+ # Database connection string (required)
8
+ # You can use PostgreSQL (postgresql://) or MongoDB (mongodb:// or mongodb+srv://).
9
+ # The backend will automatically detect the database type.
10
+ DATABASE_URL=postgresql://rebase:changeme@localhost:5432/rebase?options=-c%20search_path=public
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
16
+
17
+ # Separate admin connection string for migrations and schema operations (optional)
18
+ # Falls back to DATABASE_URL if not set
19
+ # ADMIN_CONNECTION_STRING=postgresql://postgres:your-password@localhost:5432/rebase
20
+
21
+ # Connection pool tuning (optional — sensible defaults are built-in)
22
+ # DB_POOL_MAX=20
23
+ # DB_POOL_IDLE_TIMEOUT=30000
24
+ # DB_POOL_CONNECT_TIMEOUT=10000
25
+
26
+ # ── Server ────────────────────────────────────────────────────────────────────
27
+ PORT=3001
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
31
+
32
+ # ── Logging ───────────────────────────────────────────────────────────────────
33
+ # Levels: error, warn, info, debug
34
+ LOG_LEVEL=info
35
+
36
+ # ── JWT Authentication (required) ─────────────────────────────────────────────
37
+ # Must be at least 32 characters. Generate with:
38
+ # node -e "console.log(require('crypto').randomBytes(48).toString('base64'))"
39
+ JWT_SECRET=
40
+ JWT_ACCESS_EXPIRES_IN=1h
41
+ JWT_REFRESH_EXPIRES_IN=30d
42
+
43
+ # ── Registration ──────────────────────────────────────────────────────────────
44
+ ALLOW_REGISTRATION=true
45
+
46
+ # ── Email (optional — required for password reset / verification) ─────────────
47
+ # SMTP_HOST=smtp.example.com
48
+ # SMTP_PORT=587
49
+ # SMTP_SECURE=false
50
+ # SMTP_USER=
51
+ # SMTP_PASS=
52
+ # SMTP_FROM=noreply@yourapp.com
53
+ # SMTP_NAME=
54
+ # APP_NAME=Your App Name
55
+
56
+ # ── URLs ──────────────────────────────────────────────────────────────────────
57
+ # Canonical frontend URL (used in password-reset / verification emails)
58
+ FRONTEND_URL=http://localhost:5173
59
+
60
+ # Allowed CORS origins in production (comma-separated)
61
+ # CORS_ORIGINS=https://yourdomain.com
62
+
63
+ # ── OAuth Providers (optional — uncomment to enable) ──────────────────────────
64
+ # GOOGLE_CLIENT_ID=
65
+
66
+ # ── Frontend (Vite) ──────────────────────────────────────────────────────────
67
+ VITE_API_URL=http://localhost:3001
68
+ # VITE_GOOGLE_CLIENT_ID=
69
+
70
+ # ── Storage ───────────────────────────────────────────────────────────────────
71
+ # Set STORAGE_TYPE to choose a storage backend. Default is "local" (filesystem).
72
+ #
73
+ # Supported values: local, s3
74
+ #
75
+ # STORAGE_TYPE=local
76
+
77
+ # --- Local filesystem (default — great for dev and single-server deployments) --
78
+ # STORAGE_PATH=./uploads
79
+
80
+ # --- S3-compatible (AWS S3, Cloudflare R2, MinIO, Hetzner Object Storage, Backblaze B2) ---
81
+ # STORAGE_TYPE=s3
82
+ # S3_BUCKET=my-app-uploads
83
+ # S3_REGION=us-east-1
84
+ # S3_ACCESS_KEY_ID=
85
+ # S3_SECRET_ACCESS_KEY=
86
+ # S3_ENDPOINT= # Required for R2, MinIO, Hetzner (e.g. https://fsn1.your-objectstorage.com)
87
+ # S3_FORCE_PATH_STYLE= # Set to "true" for MinIO
88
+
89
+ # --- GCS via S3 interop (Cloud Run, GKE, etc.) ---
90
+ # Use GCS HMAC keys: https://cloud.google.com/storage/docs/interoperability
91
+ # STORAGE_TYPE=s3
92
+ # S3_BUCKET=my-gcs-bucket
93
+ # S3_ENDPOINT=https://storage.googleapis.com
94
+ # S3_ACCESS_KEY_ID=GOOG... # HMAC access key
95
+ # S3_SECRET_ACCESS_KEY=... # HMAC secret
96
+ #
97
+ # For native GCS SDK or other providers (Azure Blob, etc.), implement the
98
+ # StorageController interface and pass it directly in your backend config.
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
+
112
+ # ── Admin Service Key (optional) ──────────────────────────────────────────────
113
+ # When set, scripts authenticate with: Authorization: Bearer <key>
114
+ # Generate with: node -e "console.log(require('crypto').randomBytes(48).toString('base64'))"
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).