@rebasepro/cli 0.0.1-canary.0
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/LICENSE +201 -0
- package/README.md +54 -0
- package/bin/rebase.js +4 -0
- package/dist/auth.d.ts +5 -0
- package/dist/cli.d.ts +1 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/index.cjs +277 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.es.js +265 -0
- package/dist/index.es.js.map +1 -0
- package/package.json +59 -0
- package/templates/template/.env.template +31 -0
- package/templates/template/README.md +59 -0
- package/templates/template/backend/Dockerfile +25 -0
- package/templates/template/backend/drizzle.config.ts +22 -0
- package/templates/template/backend/package.json +36 -0
- package/templates/template/backend/scripts/db-generate.ts +60 -0
- package/templates/template/backend/src/index.ts +134 -0
- package/templates/template/backend/src/schema.generated.ts +8 -0
- package/templates/template/backend/tsconfig.json +19 -0
- package/templates/template/docker-compose.yml +48 -0
- package/templates/template/frontend/Dockerfile +28 -0
- package/templates/template/frontend/index.html +13 -0
- package/templates/template/frontend/package.json +52 -0
- package/templates/template/frontend/src/App.tsx +132 -0
- package/templates/template/frontend/src/index.css +2 -0
- package/templates/template/frontend/src/main.tsx +18 -0
- package/templates/template/frontend/tsconfig.json +20 -0
- package/templates/template/frontend/vite.config.ts +26 -0
- package/templates/template/package.json +32 -0
- package/templates/template/shared/collections/index.ts +3 -0
- package/templates/template/shared/collections/posts.ts +53 -0
- package/templates/template/shared/index.ts +6 -0
- package/templates/template/shared/package.json +28 -0
- package/templates/template/shared/tsconfig.json +20 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import cors from "cors";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { createServer } from "http";
|
|
6
|
+
import { createPostgresDatabaseConnection, initializeRebaseAPI, initializeRebaseBackend, serveSPA } from "@rebasepro/backend";
|
|
7
|
+
|
|
8
|
+
import { enums, relations, tables } from "./schema.generated";
|
|
9
|
+
|
|
10
|
+
import * as dotenv from "dotenv";
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = path.dirname(__filename);
|
|
14
|
+
|
|
15
|
+
// Load environment from project root
|
|
16
|
+
dotenv.config({ path: path.resolve(__dirname, "../../.env") });
|
|
17
|
+
|
|
18
|
+
const app = express();
|
|
19
|
+
const server = createServer(app);
|
|
20
|
+
|
|
21
|
+
// PostgreSQL connection
|
|
22
|
+
const databaseUrl = process.env.DATABASE_URL;
|
|
23
|
+
if (!databaseUrl) {
|
|
24
|
+
throw new Error("DATABASE_URL environment variable is not set");
|
|
25
|
+
}
|
|
26
|
+
const db = createPostgresDatabaseConnection(databaseUrl);
|
|
27
|
+
|
|
28
|
+
// Middleware
|
|
29
|
+
app.use(cors());
|
|
30
|
+
app.use(express.json({ limit: "10mb" }));
|
|
31
|
+
|
|
32
|
+
async function startServer() {
|
|
33
|
+
const jwtSecret = process.env.JWT_SECRET;
|
|
34
|
+
if (!jwtSecret) {
|
|
35
|
+
throw new Error("JWT_SECRET environment variable is not set");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Initialize Rebase Backend with auth
|
|
39
|
+
const backend = await initializeRebaseBackend({
|
|
40
|
+
collectionsDir: path.resolve(__dirname, "../../shared/collections"),
|
|
41
|
+
server,
|
|
42
|
+
app,
|
|
43
|
+
datasource: {
|
|
44
|
+
"(default)": {
|
|
45
|
+
connection: db,
|
|
46
|
+
schema: { tables, enums, relations },
|
|
47
|
+
adminConnectionString: process.env.ADMIN_CONNECTION_STRING || process.env.DATABASE_URL
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
auth: {
|
|
51
|
+
jwtSecret,
|
|
52
|
+
accessExpiresIn: process.env.JWT_ACCESS_EXPIRES_IN || "1h",
|
|
53
|
+
refreshExpiresIn: process.env.JWT_REFRESH_EXPIRES_IN || "30d",
|
|
54
|
+
google: process.env.GOOGLE_CLIENT_ID ? {
|
|
55
|
+
clientId: process.env.GOOGLE_CLIENT_ID
|
|
56
|
+
} : undefined,
|
|
57
|
+
seedDefaultRoles: true,
|
|
58
|
+
allowRegistration: process.env.ALLOW_REGISTRATION === "true",
|
|
59
|
+
email: process.env.SMTP_HOST ? {
|
|
60
|
+
from: process.env.SMTP_FROM || "noreply@example.com",
|
|
61
|
+
appName: process.env.APP_NAME || "Rebase",
|
|
62
|
+
resetPasswordUrl: process.env.FRONTEND_URL || "http://localhost:5173",
|
|
63
|
+
verifyEmailUrl: process.env.FRONTEND_URL || "http://localhost:5173",
|
|
64
|
+
smtp: {
|
|
65
|
+
host: process.env.SMTP_HOST,
|
|
66
|
+
port: parseInt(process.env.SMTP_PORT || "587"),
|
|
67
|
+
secure: process.env.SMTP_SECURE === "true",
|
|
68
|
+
auth: process.env.SMTP_USER ? {
|
|
69
|
+
user: process.env.SMTP_USER,
|
|
70
|
+
pass: process.env.SMTP_PASS || ""
|
|
71
|
+
} : undefined
|
|
72
|
+
}
|
|
73
|
+
} : undefined
|
|
74
|
+
},
|
|
75
|
+
storage: {
|
|
76
|
+
type: "local",
|
|
77
|
+
basePath: path.resolve(__dirname, "../../uploads")
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Initialize REST/GraphQL API
|
|
82
|
+
await initializeRebaseAPI(app, backend, {
|
|
83
|
+
basePath: "/api",
|
|
84
|
+
collectionsDir: path.resolve(__dirname, "../../shared/collections"),
|
|
85
|
+
enableGraphQL: true,
|
|
86
|
+
enableREST: true,
|
|
87
|
+
cors: {
|
|
88
|
+
origin: true,
|
|
89
|
+
credentials: true
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Serve SPA in production
|
|
94
|
+
if (process.env.NODE_ENV === "production") {
|
|
95
|
+
serveSPA(app, {
|
|
96
|
+
frontendPath: path.join(__dirname, "../../frontend/dist"),
|
|
97
|
+
excludePaths: ["/health"]
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
app.get("/health", (req, res) => {
|
|
102
|
+
res.json({
|
|
103
|
+
status: "ok",
|
|
104
|
+
timestamp: new Date().toISOString(),
|
|
105
|
+
environment: process.env.NODE_ENV
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Error handling
|
|
110
|
+
app.use((error: Error, _req: express.Request, res: express.Response, _next: express.NextFunction) => {
|
|
111
|
+
console.error("Unhandled error:", error);
|
|
112
|
+
res.status(500).json({
|
|
113
|
+
error: "Internal server error",
|
|
114
|
+
message: error.message
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const PORT = process.env.PORT || 3001;
|
|
119
|
+
|
|
120
|
+
server.listen(PORT, () => {
|
|
121
|
+
console.log(`🚀 Server running at http://localhost:${PORT}`);
|
|
122
|
+
console.log(` • REST API: http://localhost:${PORT}/api`);
|
|
123
|
+
console.log(` • GraphQL: http://localhost:${PORT}/api/graphql`);
|
|
124
|
+
console.log(` • Swagger docs: http://localhost:${PORT}/api/swagger`);
|
|
125
|
+
console.log(` • Health: http://localhost:${PORT}/health`);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
startServer().catch(err => {
|
|
130
|
+
console.error("Failed to start server:", err);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
export { app, server };
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
"jsx": "preserve"
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*", "../shared/**/*", "drizzle.config.ts"]
|
|
19
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
version: '3.8'
|
|
2
|
+
|
|
3
|
+
services:
|
|
4
|
+
db:
|
|
5
|
+
image: postgres:15-alpine
|
|
6
|
+
environment:
|
|
7
|
+
POSTGRES_USER: rebase
|
|
8
|
+
POSTGRES_PASSWORD: rebasepassword
|
|
9
|
+
POSTGRES_DB: rebase
|
|
10
|
+
ports:
|
|
11
|
+
- "5432:5432"
|
|
12
|
+
volumes:
|
|
13
|
+
- postgres_data:/var/lib/postgresql/data
|
|
14
|
+
healthcheck:
|
|
15
|
+
test: ["CMD-SHELL", "pg_isready -U rebase"]
|
|
16
|
+
interval: 5s
|
|
17
|
+
timeout: 5s
|
|
18
|
+
retries: 5
|
|
19
|
+
|
|
20
|
+
backend:
|
|
21
|
+
build:
|
|
22
|
+
context: .
|
|
23
|
+
dockerfile: backend/Dockerfile
|
|
24
|
+
ports:
|
|
25
|
+
- "3001:3001"
|
|
26
|
+
environment:
|
|
27
|
+
- DATABASE_URL=postgresql://rebase:rebasepassword@db:5432/rebase
|
|
28
|
+
- JWT_SECRET=super-secret-jwt-key
|
|
29
|
+
- NODE_ENV=development
|
|
30
|
+
depends_on:
|
|
31
|
+
db:
|
|
32
|
+
condition: service_healthy
|
|
33
|
+
volumes:
|
|
34
|
+
- ./backend/uploads:/app/backend/uploads
|
|
35
|
+
|
|
36
|
+
frontend:
|
|
37
|
+
build:
|
|
38
|
+
context: .
|
|
39
|
+
dockerfile: frontend/Dockerfile
|
|
40
|
+
ports:
|
|
41
|
+
- "5173:5173"
|
|
42
|
+
environment:
|
|
43
|
+
- VITE_API_URL=http://localhost:3001
|
|
44
|
+
depends_on:
|
|
45
|
+
- backend
|
|
46
|
+
|
|
47
|
+
volumes:
|
|
48
|
+
postgres_data:
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
FROM node:24-alpine AS base
|
|
2
|
+
ENV PNPM_HOME="/pnpm"
|
|
3
|
+
ENV PATH="$PNPM_HOME:$PATH"
|
|
4
|
+
RUN corepack enable
|
|
5
|
+
RUN apk add --no-cache python3 make g++
|
|
6
|
+
|
|
7
|
+
WORKDIR /app
|
|
8
|
+
|
|
9
|
+
# Copy root configurations
|
|
10
|
+
COPY package.json ./
|
|
11
|
+
|
|
12
|
+
# Copy internal workspaces
|
|
13
|
+
COPY frontend ./frontend
|
|
14
|
+
COPY shared ./shared
|
|
15
|
+
|
|
16
|
+
# Install dependencies
|
|
17
|
+
RUN pnpm install
|
|
18
|
+
|
|
19
|
+
# Build shared and frontend
|
|
20
|
+
RUN pnpm run build:shared
|
|
21
|
+
RUN pnpm run build:frontend
|
|
22
|
+
|
|
23
|
+
# Install a simple static server
|
|
24
|
+
RUN npm install -g serve
|
|
25
|
+
|
|
26
|
+
WORKDIR /app/frontend
|
|
27
|
+
EXPOSE 5173
|
|
28
|
+
CMD ["serve", "-s", "dist", "-l", "5173"]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>{{PROJECT_NAME}}</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="root" class="bg-surface-50 dark:bg-surface-900 text-surface-900 dark:text-white"></div>
|
|
11
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}-frontend",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
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",
|
|
16
|
+
"@fontsource/jetbrains-mono": "^5.2.5",
|
|
17
|
+
"{{PROJECT_NAME}}-shared": "workspace:*",
|
|
18
|
+
"react": "^19.0.0",
|
|
19
|
+
"react-dom": "^19.0.0",
|
|
20
|
+
"react-router": "^7.0.0",
|
|
21
|
+
"react-router-dom": "^7.0.0",
|
|
22
|
+
"typeface-rubik": "^1.1.13"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"dev": "vite --mode development",
|
|
26
|
+
"build": "vite build && tsc",
|
|
27
|
+
"preview": "vite build && vite preview"
|
|
28
|
+
},
|
|
29
|
+
"browserslist": {
|
|
30
|
+
"production": [
|
|
31
|
+
">0.2%",
|
|
32
|
+
"not dead",
|
|
33
|
+
"not op_mini all"
|
|
34
|
+
],
|
|
35
|
+
"development": [
|
|
36
|
+
"last 1 chrome version",
|
|
37
|
+
"last 1 firefox version",
|
|
38
|
+
"last 1 safari version"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@tailwindcss/typography": "^0.5.16",
|
|
43
|
+
"@tailwindcss/vite": "^4.1.12",
|
|
44
|
+
"@types/react": "^19.0.8",
|
|
45
|
+
"@types/react-dom": "^19.0.3",
|
|
46
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
47
|
+
"tailwindcss": "^4.1.3",
|
|
48
|
+
"typescript": "^5.9.2",
|
|
49
|
+
"vite": "^5.4.17",
|
|
50
|
+
"vite-plugin-svgr": "^4.3.0"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import React, { useCallback } from "react";
|
|
2
|
+
|
|
3
|
+
import "@fontsource/jetbrains-mono";
|
|
4
|
+
import "typeface-rubik";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
RebaseLoginView,
|
|
8
|
+
useBackendUserManagement,
|
|
9
|
+
useRebaseAuthController
|
|
10
|
+
} from "@rebasepro/auth";
|
|
11
|
+
import {
|
|
12
|
+
AppBar,
|
|
13
|
+
CircularProgressCenter,
|
|
14
|
+
Drawer,
|
|
15
|
+
Rebase,
|
|
16
|
+
RebaseRoute,
|
|
17
|
+
ModeControllerProvider,
|
|
18
|
+
NotFoundPage,
|
|
19
|
+
Scaffold,
|
|
20
|
+
SideDialogs,
|
|
21
|
+
RebaseRoutes,
|
|
22
|
+
SnackbarProvider,
|
|
23
|
+
ContentHomePage,
|
|
24
|
+
useBackendStorageSource,
|
|
25
|
+
useBuildCMSUrlController,
|
|
26
|
+
useBuildCollectionRegistryController,
|
|
27
|
+
useBuildLocalConfigurationPersistence,
|
|
28
|
+
useBuildModeController,
|
|
29
|
+
useBuildNavigationStateController
|
|
30
|
+
} from "@rebasepro/core";
|
|
31
|
+
import { usePostgresClientDataSource } from "@rebasepro/postgresql";
|
|
32
|
+
import { collections } from "virtual:rebase-collections";
|
|
33
|
+
import { Route, Outlet } from "react-router-dom";
|
|
34
|
+
|
|
35
|
+
// Configuration from environment
|
|
36
|
+
const API_URL = import.meta.env.VITE_API_URL || "http://localhost:3001";
|
|
37
|
+
const GOOGLE_CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID;
|
|
38
|
+
|
|
39
|
+
export function App() {
|
|
40
|
+
const modeController = useBuildModeController();
|
|
41
|
+
const userConfigPersistence = useBuildLocalConfigurationPersistence();
|
|
42
|
+
|
|
43
|
+
const authController = useRebaseAuthController({
|
|
44
|
+
apiUrl: API_URL,
|
|
45
|
+
googleClientId: GOOGLE_CLIENT_ID
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const storageSource = useBackendStorageSource({
|
|
49
|
+
apiUrl: API_URL,
|
|
50
|
+
getAuthToken: authController.getAuthToken
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const userManagement = useBackendUserManagement({
|
|
54
|
+
apiUrl: API_URL,
|
|
55
|
+
getAuthToken: authController.getAuthToken,
|
|
56
|
+
currentUser: authController.user
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const postgresDelegate = usePostgresClientDataSource({
|
|
60
|
+
websocketUrl: API_URL.replace(/^http/, "ws"),
|
|
61
|
+
getAuthToken: authController.initialLoading ? undefined : authController.getAuthToken
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const collectionsBuilder = useCallback(() => {
|
|
65
|
+
return [...collections];
|
|
66
|
+
}, []);
|
|
67
|
+
|
|
68
|
+
const collectionRegistryController = useBuildCollectionRegistryController({ userConfigPersistence });
|
|
69
|
+
const cmsUrlController = useBuildCMSUrlController({
|
|
70
|
+
basePath: "/",
|
|
71
|
+
baseCollectionPath: "/c",
|
|
72
|
+
collectionRegistryController
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const navigationStateController = useBuildNavigationStateController({
|
|
76
|
+
collections: collectionsBuilder,
|
|
77
|
+
authController,
|
|
78
|
+
dataSource: postgresDelegate,
|
|
79
|
+
collectionRegistryController,
|
|
80
|
+
cmsUrlController,
|
|
81
|
+
userManagement
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<SnackbarProvider>
|
|
86
|
+
<ModeControllerProvider value={modeController}>
|
|
87
|
+
<Rebase
|
|
88
|
+
collectionRegistryController={collectionRegistryController}
|
|
89
|
+
cmsUrlController={cmsUrlController}
|
|
90
|
+
navigationStateController={navigationStateController}
|
|
91
|
+
authController={authController}
|
|
92
|
+
userConfigPersistence={userConfigPersistence}
|
|
93
|
+
dataSource={postgresDelegate}
|
|
94
|
+
storageSource={storageSource}
|
|
95
|
+
>
|
|
96
|
+
{({ loading }) => {
|
|
97
|
+
if (loading || authController.initialLoading) {
|
|
98
|
+
return <CircularProgressCenter />;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!authController.user) {
|
|
102
|
+
return (
|
|
103
|
+
<RebaseLoginView
|
|
104
|
+
authController={authController}
|
|
105
|
+
googleEnabled={!!GOOGLE_CLIENT_ID}
|
|
106
|
+
googleClientId={GOOGLE_CLIENT_ID}
|
|
107
|
+
/>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<RebaseRoutes>
|
|
113
|
+
<Route element={
|
|
114
|
+
<Scaffold autoOpenDrawer={false}>
|
|
115
|
+
<AppBar />
|
|
116
|
+
<Drawer />
|
|
117
|
+
<Outlet />
|
|
118
|
+
<SideDialogs />
|
|
119
|
+
</Scaffold>
|
|
120
|
+
}>
|
|
121
|
+
<Route path={"/"} element={<ContentHomePage />} />
|
|
122
|
+
<Route path={"/c/*"} element={<RebaseRoute />} />
|
|
123
|
+
<Route path={"*"} element={<NotFoundPage />} />
|
|
124
|
+
</Route>
|
|
125
|
+
</RebaseRoutes>
|
|
126
|
+
);
|
|
127
|
+
}}
|
|
128
|
+
</Rebase>
|
|
129
|
+
</ModeControllerProvider>
|
|
130
|
+
</SnackbarProvider>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import ReactDOM from "react-dom/client";
|
|
3
|
+
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
|
4
|
+
import { App } from "./App";
|
|
5
|
+
import "./index.css";
|
|
6
|
+
|
|
7
|
+
const router = createBrowserRouter([
|
|
8
|
+
{
|
|
9
|
+
path: "/*",
|
|
10
|
+
element: <App />
|
|
11
|
+
}
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
|
15
|
+
<React.StrictMode>
|
|
16
|
+
<RouterProvider router={router} />
|
|
17
|
+
</React.StrictMode>
|
|
18
|
+
);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
|
6
|
+
"allowJs": true,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"allowSyntheticDefaultImports": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"module": "ESNext",
|
|
13
|
+
"moduleResolution": "bundler",
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"isolatedModules": true,
|
|
16
|
+
"noEmit": true,
|
|
17
|
+
"jsx": "react-jsx"
|
|
18
|
+
},
|
|
19
|
+
"include": ["./src", "./vite.config.ts"]
|
|
20
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { defineConfig } from "vite";
|
|
4
|
+
import react from "@vitejs/plugin-react";
|
|
5
|
+
import svgr from "vite-plugin-svgr";
|
|
6
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
7
|
+
import { rebaseCollectionsPlugin } from "@rebasepro/core/vitePlugin";
|
|
8
|
+
|
|
9
|
+
export default defineConfig({
|
|
10
|
+
esbuild: {
|
|
11
|
+
logOverride: { "this-is-undefined-in-esm": "silent" }
|
|
12
|
+
},
|
|
13
|
+
build: {
|
|
14
|
+
minify: true,
|
|
15
|
+
outDir: "./build",
|
|
16
|
+
target: "ESNEXT",
|
|
17
|
+
sourcemap: true
|
|
18
|
+
},
|
|
19
|
+
optimizeDeps: { include: ["react/jsx-runtime"] },
|
|
20
|
+
plugins: [
|
|
21
|
+
svgr(),
|
|
22
|
+
react({}),
|
|
23
|
+
tailwindcss(),
|
|
24
|
+
rebaseCollectionsPlugin({ collectionsDir: "../shared/collections" })
|
|
25
|
+
]
|
|
26
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Rebase application with PostgreSQL backend",
|
|
5
|
+
"private": true,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"workspaces": [
|
|
8
|
+
"frontend",
|
|
9
|
+
"backend",
|
|
10
|
+
"shared"
|
|
11
|
+
],
|
|
12
|
+
"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"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"concurrently": "^8.2.2",
|
|
27
|
+
"typescript": "^5.9.2"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=18.0.0"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { EntityCollection } from "@rebasepro/types";
|
|
2
|
+
|
|
3
|
+
const postsCollection: EntityCollection = {
|
|
4
|
+
name: "Posts",
|
|
5
|
+
singularName: "Post",
|
|
6
|
+
slug: "posts",
|
|
7
|
+
dbPath: "posts",
|
|
8
|
+
icon: "Article",
|
|
9
|
+
properties: {
|
|
10
|
+
id: {
|
|
11
|
+
name: "ID",
|
|
12
|
+
type: "number",
|
|
13
|
+
validation: {
|
|
14
|
+
required: true
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
title: {
|
|
18
|
+
name: "Title",
|
|
19
|
+
type: "string",
|
|
20
|
+
validation: {
|
|
21
|
+
required: true
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
content: {
|
|
25
|
+
name: "Content",
|
|
26
|
+
type: "string",
|
|
27
|
+
multiline: true
|
|
28
|
+
},
|
|
29
|
+
status: {
|
|
30
|
+
name: "Status",
|
|
31
|
+
type: "string",
|
|
32
|
+
enum: [
|
|
33
|
+
{
|
|
34
|
+
id: "draft",
|
|
35
|
+
label: "Draft",
|
|
36
|
+
color: "grayLight"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "review",
|
|
40
|
+
label: "In Review",
|
|
41
|
+
color: "orangeLight"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: "published",
|
|
45
|
+
label: "Published",
|
|
46
|
+
color: "greenLight"
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default postsCollection;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}-shared",
|
|
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": "^4.0.0"
|
|
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
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"allowSyntheticDefaultImports": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"jsx": "react-jsx",
|
|
11
|
+
"noEmit": false,
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"outDir": "./dist",
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"forceConsistentCasingInFileNames": true,
|
|
16
|
+
"resolveJsonModule": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["**/*.ts"],
|
|
19
|
+
"exclude": ["node_modules", "dist"]
|
|
20
|
+
}
|