@rebasepro/cli 0.1.0 → 0.2.1
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 +17 -196
- package/dist/index.cjs +158 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +142 -28
- package/dist/index.es.js.map +1 -1
- package/package.json +13 -11
- package/templates/template/.cursorrules +2 -0
- package/templates/template/.env.example +7 -0
- package/templates/template/.github/copilot-instructions.md +2 -0
- package/templates/template/.windsurfrules +2 -0
- package/templates/template/README.md +2 -2
- package/templates/template/ai-instructions.md +14 -0
- package/templates/template/backend/Dockerfile +1 -1
- package/templates/template/backend/drizzle.config.ts +11 -5
- package/templates/template/backend/package.json +4 -3
- package/templates/template/backend/src/env.ts +2 -43
- package/templates/template/backend/src/index.ts +10 -12
- package/templates/template/config/collections/index.ts +6 -4
- package/templates/template/config/collections/posts.ts +3 -17
- package/templates/template/config/collections/roles.ts +72 -0
- package/templates/template/config/collections/users.ts +141 -0
- package/templates/template/config/index.ts +1 -1
- package/templates/template/config/package.json +2 -1
- package/templates/template/docker-compose.yml +1 -1
- package/templates/template/frontend/package.json +3 -1
- package/templates/template/frontend/src/App.tsx +3 -3
- package/templates/template/frontend/src/virtual.d.ts +6 -0
- package/templates/template/frontend/tsconfig.json +3 -2
- package/templates/template/frontend/vite.config.ts +1 -1
- package/templates/template/pnpm-workspace.yaml +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/cli",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Developer tools for Rebase projects",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.es.js",
|
|
@@ -26,20 +26,21 @@
|
|
|
26
26
|
"license": "MIT",
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"arg": "^5.0.2",
|
|
29
|
-
"chalk": "^
|
|
30
|
-
"dotenv": "^16.
|
|
31
|
-
"execa": "^
|
|
29
|
+
"chalk": "^5.6.2",
|
|
30
|
+
"dotenv": "^16.6.1",
|
|
31
|
+
"execa": "^9.6.1",
|
|
32
32
|
"inquirer": "12.11.1",
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"@rebasepro/
|
|
36
|
-
"@rebasepro/types": "0.1
|
|
37
|
-
"@rebasepro/server-core": "0.1.0"
|
|
33
|
+
"jiti": "^2.7.0",
|
|
34
|
+
"@rebasepro/sdk-generator": "0.2.1",
|
|
35
|
+
"@rebasepro/server-core": "0.2.1",
|
|
36
|
+
"@rebasepro/types": "0.2.1"
|
|
38
37
|
},
|
|
39
38
|
"devDependencies": {
|
|
40
|
-
"@types/node": "^20.19.
|
|
39
|
+
"@types/node": "^20.19.41",
|
|
40
|
+
"@types/pg": "^8.20.0",
|
|
41
|
+
"pg": "^8.21.0",
|
|
41
42
|
"typescript": "^5.9.3",
|
|
42
|
-
"vite": "^7.
|
|
43
|
+
"vite": "^7.3.3",
|
|
43
44
|
"vitest": "4.1.5"
|
|
44
45
|
},
|
|
45
46
|
"files": [
|
|
@@ -61,6 +62,7 @@
|
|
|
61
62
|
"gitHead": "d935eefa5aa8d1009a2398cfac2c1e4ee9aeb6b6",
|
|
62
63
|
"scripts": {
|
|
63
64
|
"test": "vitest run",
|
|
65
|
+
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
|
64
66
|
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.json",
|
|
65
67
|
"clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f"
|
|
66
68
|
}
|
|
@@ -22,6 +22,8 @@ DATABASE_URL=postgresql://rebase:changeme@localhost:5432/rebase
|
|
|
22
22
|
# ── Server ────────────────────────────────────────────────────────────────────
|
|
23
23
|
PORT=3001
|
|
24
24
|
NODE_ENV=development
|
|
25
|
+
# Allow connecting to localhost / 127.0.0.1 in production mode (for local testing of prod builds)
|
|
26
|
+
# ALLOW_LOCALHOST_IN_PRODUCTION=false
|
|
25
27
|
|
|
26
28
|
# ── Logging ───────────────────────────────────────────────────────────────────
|
|
27
29
|
# Levels: error, warn, info, debug
|
|
@@ -94,3 +96,8 @@ VITE_API_URL=http://localhost:3001
|
|
|
94
96
|
# When set, scripts authenticate with: Authorization: Bearer <key>
|
|
95
97
|
# Generate with: node -e "console.log(require('crypto').randomBytes(48).toString('base64'))"
|
|
96
98
|
# REBASE_SERVICE_KEY=
|
|
99
|
+
|
|
100
|
+
# Disable switching to database-level roles (e.g. 'admin') for Studio SQL execution (optional)
|
|
101
|
+
# Falls back to false. Useful for databases with application-only roles or managed setups.
|
|
102
|
+
# DISABLE_DB_ROLE_SWITCHING=true
|
|
103
|
+
|
|
@@ -44,8 +44,8 @@ cp .env.example .env
|
|
|
44
44
|
3. Generate schema and push to database:
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
|
|
48
|
-
|
|
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:
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Rebase AI Coding Rules
|
|
2
|
+
|
|
3
|
+
For the most up-to-date, comprehensive guidelines, architecture details, SDK APIs, and troubleshooting guides, please refer to the official Rebase LLM documentation:
|
|
4
|
+
👉 https://rebase.pro/llms.txt
|
|
5
|
+
|
|
6
|
+
If you are running in an agentic environment (like Antigravity or a Gemini CLI extension), the assistant will automatically load the active Rebase agent skills.
|
|
7
|
+
|
|
8
|
+
## Core Tenets (Quick Reference)
|
|
9
|
+
|
|
10
|
+
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.
|
|
11
|
+
2. **Two-Step Migrations**:
|
|
12
|
+
- Step 1: Run `rebase schema generate` to compile collections to the Drizzle schema.
|
|
13
|
+
- Step 2: Run `rebase db push` (development) or `rebase db generate && rebase db migrate` (production) to apply schema changes to the database.
|
|
14
|
+
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).
|
|
@@ -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
|
|
@@ -3,7 +3,8 @@ import path from "path";
|
|
|
3
3
|
import { fileURLToPath } from "url";
|
|
4
4
|
import { defineConfig } from "drizzle-kit";
|
|
5
5
|
import { tables } from "./src/schema.generated";
|
|
6
|
-
import { getTableName
|
|
6
|
+
import { getTableName } from "drizzle-orm";
|
|
7
|
+
import { getTableConfig, PgTable } from "drizzle-orm/pg-core";
|
|
7
8
|
|
|
8
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
10
|
const __dirname = path.dirname(__filename);
|
|
@@ -18,7 +19,13 @@ if (!process.env.DATABASE_URL) {
|
|
|
18
19
|
// Extract table names from the generated schema.
|
|
19
20
|
// This ensures drizzle-kit ONLY manages tables defined in the schema.
|
|
20
21
|
// Any tables in the database that are NOT part of the Rebase schema are left untouched.
|
|
21
|
-
const tableNames = Object.values(tables).map(table => getTableName(table as
|
|
22
|
+
const tableNames = Object.values(tables).map(table => getTableName(table as PgTable));
|
|
23
|
+
|
|
24
|
+
// Dynamically extract all schemas defined in the generated tables to ensure Drizzle Kit manages them.
|
|
25
|
+
const schemas = Array.from(new Set(
|
|
26
|
+
Object.values(tables)
|
|
27
|
+
.map(table => getTableConfig(table as PgTable).schema || "public")
|
|
28
|
+
));
|
|
22
29
|
|
|
23
30
|
export default defineConfig({
|
|
24
31
|
schema: "./src/schema.generated.ts",
|
|
@@ -30,9 +37,8 @@ export default defineConfig({
|
|
|
30
37
|
// Only manage tables defined in the generated schema.
|
|
31
38
|
// Unmapped tables in the database are completely ignored.
|
|
32
39
|
tablesFilter: tableNames,
|
|
33
|
-
// Restrict drizzle-kit to the
|
|
34
|
-
|
|
35
|
-
schemaFilter: ["public"],
|
|
40
|
+
// Restrict drizzle-kit to the schemas defined in our collections
|
|
41
|
+
schemaFilter: schemas.length > 0 ? schemas : ["public"],
|
|
36
42
|
// Prevent drizzle-kit from managing roles not defined in the schema
|
|
37
43
|
entities: {
|
|
38
44
|
roles: false
|
|
@@ -6,19 +6,20 @@
|
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"dev": "tsx watch --watch=\"../config/**/*\" src/index.ts",
|
|
9
|
-
"build": "
|
|
10
|
-
"start": "
|
|
9
|
+
"build": "rebase schema generate --collections ../config/collections && tsc",
|
|
10
|
+
"start": "node dist/backend/src/index.js"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"{{PROJECT_NAME}}-config": "*",
|
|
14
14
|
"@rebasepro/server-core": "workspace:*",
|
|
15
15
|
"@rebasepro/server-postgresql": "workspace:*",
|
|
16
|
+
"@rebasepro/admin": "workspace:*",
|
|
16
17
|
"drizzle-orm": "^0.44.4",
|
|
17
18
|
"hono": "^4.12.10",
|
|
18
19
|
"@hono/node-server": "^1.19.12",
|
|
19
20
|
"pg": "^8.11.3",
|
|
20
21
|
"ws": "^8.16.0",
|
|
21
|
-
"
|
|
22
|
+
"react-compiler-runtime": "^1.0.0",
|
|
22
23
|
"dotenv": "^16.0.0"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
@@ -1,52 +1,11 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
1
|
import * as dotenv from "dotenv";
|
|
3
2
|
import path from "path";
|
|
4
3
|
import { fileURLToPath } from "url";
|
|
4
|
+
import { loadEnv } from "@rebasepro/server-core";
|
|
5
5
|
|
|
6
6
|
const __filename = fileURLToPath(import.meta.url);
|
|
7
7
|
const __dirname = path.dirname(__filename);
|
|
8
8
|
|
|
9
9
|
dotenv.config({ path: path.resolve(__dirname, "../../.env") });
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
|
|
13
|
-
PORT: z.string().default("3001").transform(Number),
|
|
14
|
-
DATABASE_URL: z.string().url("DATABASE_URL must be a valid URL"),
|
|
15
|
-
ADMIN_CONNECTION_STRING: z.string().url().optional(),
|
|
16
|
-
JWT_SECRET: z.string().min(32, "JWT_SECRET must be at least 32 characters long"),
|
|
17
|
-
JWT_ACCESS_EXPIRES_IN: z.string().default("1h"),
|
|
18
|
-
JWT_REFRESH_EXPIRES_IN: z.string().default("30d"),
|
|
19
|
-
GOOGLE_CLIENT_ID: z.string().optional(),
|
|
20
|
-
ALLOW_REGISTRATION: z.enum(["true", "false", ""]).default("false").transform(v => v === "true"),
|
|
21
|
-
CORS_ORIGINS: z.string().optional(),
|
|
22
|
-
FRONTEND_URL: z.string().optional(),
|
|
23
|
-
DB_POOL_MAX: z.string().default("20").transform(Number),
|
|
24
|
-
DB_POOL_IDLE_TIMEOUT: z.string().default("30000").transform(Number),
|
|
25
|
-
DB_POOL_CONNECT_TIMEOUT: z.string().default("10000").transform(Number),
|
|
26
|
-
FORCE_LOCAL_STORAGE: z.enum(["true", "false", ""]).optional().transform(v => v === "true"),
|
|
27
|
-
STORAGE_TYPE: z.enum(["local", "s3"]).default("local"),
|
|
28
|
-
STORAGE_PATH: z.string().optional(),
|
|
29
|
-
S3_BUCKET: z.string().optional(),
|
|
30
|
-
S3_REGION: z.string().optional(),
|
|
31
|
-
S3_ACCESS_KEY_ID: z.string().optional(),
|
|
32
|
-
S3_SECRET_ACCESS_KEY: z.string().optional(),
|
|
33
|
-
S3_ENDPOINT: z.string().url().optional(),
|
|
34
|
-
S3_FORCE_PATH_STYLE: z.enum(["true", "false", ""]).optional().transform(v => v === "true"),
|
|
35
|
-
/**
|
|
36
|
-
* Service key for admin-level script / server-to-server authentication.
|
|
37
|
-
* When set, scripts can send `Authorization: Bearer <key>` to get admin access.
|
|
38
|
-
* Generate with: node -e "console.log(require('crypto').randomBytes(48).toString('base64'))"
|
|
39
|
-
*/
|
|
40
|
-
REBASE_SERVICE_KEY: z.string().min(32, "REBASE_SERVICE_KEY must be at least 32 characters").optional()
|
|
41
|
-
}).superRefine((data, ctx) => {
|
|
42
|
-
if (data.NODE_ENV === "production" && !data.CORS_ORIGINS && !data.FRONTEND_URL) {
|
|
43
|
-
ctx.addIssue({
|
|
44
|
-
code: z.ZodIssueCode.custom,
|
|
45
|
-
message: "CORS_ORIGINS or FRONTEND_URL must be set in production to secure the API.",
|
|
46
|
-
path: ["CORS_ORIGINS"]
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// Parse and export
|
|
52
|
-
export const env = envSchema.parse(process.env);
|
|
11
|
+
export const env = loadEnv();
|
|
@@ -13,15 +13,15 @@ import {
|
|
|
13
13
|
cleanupDevPortFile,
|
|
14
14
|
logger
|
|
15
15
|
} from "@rebasepro/server-core";
|
|
16
|
-
import { createPostgresDatabaseConnection,
|
|
17
|
-
import { enums, relations, tables } from "./schema.generated";
|
|
18
|
-
import { env } from "./env";
|
|
16
|
+
import { createPostgresDatabaseConnection, createPostgresAdapter } from "@rebasepro/server-postgresql";
|
|
17
|
+
import { enums, relations, tables } from "./schema.generated.js";
|
|
18
|
+
import { env } from "./env.js";
|
|
19
19
|
|
|
20
20
|
const __filename = fileURLToPath(import.meta.url);
|
|
21
21
|
const __dirname = path.dirname(__filename);
|
|
22
22
|
|
|
23
23
|
// ─── App ─────────────────────────────────────────────────────────────
|
|
24
|
-
const app = new Hono<HonoEnv>();
|
|
24
|
+
const app: Hono<HonoEnv> = new Hono<HonoEnv>();
|
|
25
25
|
|
|
26
26
|
const isProduction = env.NODE_ENV === "production";
|
|
27
27
|
const allowedOrigins = isProduction
|
|
@@ -54,16 +54,14 @@ async function startServer() {
|
|
|
54
54
|
functionsDir: path.resolve(__dirname, "../functions"),
|
|
55
55
|
server,
|
|
56
56
|
app,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
schema: { tables,
|
|
57
|
+
database: createPostgresAdapter({
|
|
58
|
+
connection: db,
|
|
59
|
+
schema: { tables,
|
|
61
60
|
enums,
|
|
62
61
|
relations },
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
],
|
|
62
|
+
adminConnectionString: env.ADMIN_CONNECTION_STRING || databaseUrl,
|
|
63
|
+
connectionString
|
|
64
|
+
}),
|
|
67
65
|
auth: {
|
|
68
66
|
jwtSecret,
|
|
69
67
|
accessExpiresIn: env.JWT_ACCESS_EXPIRES_IN,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import postsCollection from "./posts";
|
|
2
|
-
import authorsCollection from "./authors";
|
|
3
|
-
import tagsCollection from "./tags";
|
|
1
|
+
import postsCollection from "./posts.js";
|
|
2
|
+
import authorsCollection from "./authors.js";
|
|
3
|
+
import tagsCollection from "./tags.js";
|
|
4
|
+
import usersCollection from "./users.js";
|
|
5
|
+
import rolesCollection from "./roles.js";
|
|
4
6
|
|
|
5
|
-
export const collections = [postsCollection, authorsCollection, tagsCollection];
|
|
7
|
+
export const collections = [postsCollection, authorsCollection, tagsCollection, usersCollection, rolesCollection];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EntityCollection } from "@rebasepro/types";
|
|
2
|
-
import authorsCollection from "./authors";
|
|
3
|
-
import tagsCollection from "./tags";
|
|
2
|
+
import authorsCollection from "./authors.js";
|
|
3
|
+
import tagsCollection from "./tags.js";
|
|
4
4
|
|
|
5
5
|
const postsCollection: EntityCollection = {
|
|
6
6
|
name: "Posts",
|
|
@@ -71,21 +71,7 @@ const postsCollection: EntityCollection = {
|
|
|
71
71
|
target: () => tagsCollection
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
-
}
|
|
75
|
-
relations: [
|
|
76
|
-
{
|
|
77
|
-
relationName: "author",
|
|
78
|
-
target: () => authorsCollection,
|
|
79
|
-
cardinality: "one",
|
|
80
|
-
direction: "owning"
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
relationName: "tags",
|
|
84
|
-
target: () => tagsCollection,
|
|
85
|
-
cardinality: "many",
|
|
86
|
-
direction: "owning"
|
|
87
|
-
}
|
|
88
|
-
]
|
|
74
|
+
}
|
|
89
75
|
};
|
|
90
76
|
|
|
91
77
|
export default postsCollection;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { PostgresCollection, EntityCollection } from "@rebasepro/types";
|
|
2
|
+
|
|
3
|
+
const rolesCollection: PostgresCollection = {
|
|
4
|
+
name: "Roles",
|
|
5
|
+
singularName: "Role",
|
|
6
|
+
slug: "roles",
|
|
7
|
+
table: "roles",
|
|
8
|
+
schema: "rebase",
|
|
9
|
+
icon: "Shield",
|
|
10
|
+
group: "Settings",
|
|
11
|
+
properties: {
|
|
12
|
+
id: {
|
|
13
|
+
name: "ID",
|
|
14
|
+
type: "string",
|
|
15
|
+
isId: "manual",
|
|
16
|
+
validation: {
|
|
17
|
+
required: true
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
name: {
|
|
21
|
+
name: "Name",
|
|
22
|
+
type: "string",
|
|
23
|
+
validation: {
|
|
24
|
+
required: true
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
isAdmin: {
|
|
28
|
+
name: "Is Admin",
|
|
29
|
+
type: "boolean",
|
|
30
|
+
columnName: "is_admin",
|
|
31
|
+
defaultValue: false
|
|
32
|
+
},
|
|
33
|
+
defaultPermissions: {
|
|
34
|
+
name: "Default Permissions",
|
|
35
|
+
type: "map",
|
|
36
|
+
columnName: "default_permissions",
|
|
37
|
+
properties: {
|
|
38
|
+
read: { name: "Read", type: "boolean" },
|
|
39
|
+
create: { name: "Create", type: "boolean" },
|
|
40
|
+
edit: { name: "Edit", type: "boolean" },
|
|
41
|
+
delete: { name: "Delete", type: "boolean" }
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
collectionPermissions: {
|
|
45
|
+
name: "Collection Permissions",
|
|
46
|
+
type: "map",
|
|
47
|
+
columnName: "collection_permissions"
|
|
48
|
+
},
|
|
49
|
+
config: {
|
|
50
|
+
name: "Config",
|
|
51
|
+
type: "map",
|
|
52
|
+
columnName: "config",
|
|
53
|
+
properties: {
|
|
54
|
+
createCollections: { name: "Create Collections", type: "boolean" },
|
|
55
|
+
editCollections: { name: "Edit Collections", type: "string" },
|
|
56
|
+
deleteCollections: { name: "Delete Collections", type: "string" }
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
rolesCollection.securityRules = [
|
|
63
|
+
{
|
|
64
|
+
name: "roles_public_access",
|
|
65
|
+
mode: "permissive",
|
|
66
|
+
operation: "all",
|
|
67
|
+
pgRoles: ["public"],
|
|
68
|
+
using: "true"
|
|
69
|
+
}
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
export default rolesCollection;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { EntityCollection } from "@rebasepro/types";
|
|
2
|
+
import { resetPasswordAction, deleteEntityAction, RolesFilterSelect, UserRolesSelectField } from "@rebasepro/admin";
|
|
3
|
+
import rolesCollection from "./roles.js";
|
|
4
|
+
|
|
5
|
+
const usersCollection: EntityCollection = {
|
|
6
|
+
name: "Users",
|
|
7
|
+
singularName: "User",
|
|
8
|
+
slug: "users",
|
|
9
|
+
table: "users",
|
|
10
|
+
schema: "rebase",
|
|
11
|
+
icon: "Users",
|
|
12
|
+
group: "Settings",
|
|
13
|
+
openEntityMode: "dialog",
|
|
14
|
+
disableDefaultActions: ["copy"],
|
|
15
|
+
Actions: [RolesFilterSelect],
|
|
16
|
+
entityActions: [
|
|
17
|
+
resetPasswordAction,
|
|
18
|
+
{
|
|
19
|
+
...deleteEntityAction,
|
|
20
|
+
collapsed: false
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
sort: ["createdAt", "desc"],
|
|
24
|
+
properties: {
|
|
25
|
+
id: {
|
|
26
|
+
name: "ID",
|
|
27
|
+
type: "string",
|
|
28
|
+
isId: "uuid",
|
|
29
|
+
ui: {
|
|
30
|
+
readOnly: true
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
email: {
|
|
34
|
+
name: "Email",
|
|
35
|
+
type: "string",
|
|
36
|
+
validation: {
|
|
37
|
+
required: true,
|
|
38
|
+
unique: true
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
displayName: {
|
|
42
|
+
name: "Name",
|
|
43
|
+
type: "string",
|
|
44
|
+
validation: {
|
|
45
|
+
required: true
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
photoURL: {
|
|
49
|
+
name: "Photo URL",
|
|
50
|
+
type: "string",
|
|
51
|
+
url: "image"
|
|
52
|
+
},
|
|
53
|
+
roles: {
|
|
54
|
+
name: "Roles",
|
|
55
|
+
type: "relation",
|
|
56
|
+
target: () => rolesCollection,
|
|
57
|
+
cardinality: "many",
|
|
58
|
+
direction: "owning",
|
|
59
|
+
through: {
|
|
60
|
+
table: "user_roles",
|
|
61
|
+
sourceColumn: "user_id",
|
|
62
|
+
targetColumn: "role_id"
|
|
63
|
+
},
|
|
64
|
+
ui: {
|
|
65
|
+
Field: UserRolesSelectField
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
passwordHash: {
|
|
69
|
+
name: "Password Hash",
|
|
70
|
+
type: "string",
|
|
71
|
+
columnName: "password_hash",
|
|
72
|
+
ui: {
|
|
73
|
+
hideFromCollection: true,
|
|
74
|
+
disabled: { hidden: true }
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
emailVerified: {
|
|
78
|
+
name: "Email Verified",
|
|
79
|
+
type: "boolean",
|
|
80
|
+
columnName: "email_verified",
|
|
81
|
+
defaultValue: false,
|
|
82
|
+
ui: {
|
|
83
|
+
hideFromCollection: true,
|
|
84
|
+
disabled: { hidden: true }
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
emailVerificationToken: {
|
|
88
|
+
name: "Email Verification Token",
|
|
89
|
+
type: "string",
|
|
90
|
+
columnName: "email_verification_token",
|
|
91
|
+
ui: {
|
|
92
|
+
hideFromCollection: true,
|
|
93
|
+
disabled: { hidden: true }
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
emailVerificationSentAt: {
|
|
97
|
+
name: "Email Verification Sent At",
|
|
98
|
+
type: "date",
|
|
99
|
+
columnName: "email_verification_sent_at",
|
|
100
|
+
ui: {
|
|
101
|
+
hideFromCollection: true,
|
|
102
|
+
disabled: { hidden: true }
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
metadata: {
|
|
106
|
+
name: "Metadata",
|
|
107
|
+
type: "map",
|
|
108
|
+
defaultValue: {},
|
|
109
|
+
ui: {
|
|
110
|
+
hideFromCollection: true,
|
|
111
|
+
disabled: { hidden: true }
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
createdAt: {
|
|
115
|
+
name: "Created At",
|
|
116
|
+
type: "date",
|
|
117
|
+
ui: {
|
|
118
|
+
readOnly: true
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
updatedAt: {
|
|
122
|
+
name: "Updated At",
|
|
123
|
+
type: "date",
|
|
124
|
+
columnName: "updated_at",
|
|
125
|
+
autoValue: "on_update",
|
|
126
|
+
ui: {
|
|
127
|
+
hideFromCollection: true,
|
|
128
|
+
disabled: { hidden: true }
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
propertiesOrder: [
|
|
133
|
+
"id",
|
|
134
|
+
"email",
|
|
135
|
+
"displayName",
|
|
136
|
+
"roles",
|
|
137
|
+
"createdAt"
|
|
138
|
+
]
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export default usersCollection;
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"react-dom": "^19.0.0",
|
|
19
19
|
"react-router": "^7.0.0",
|
|
20
20
|
"react-router-dom": "^7.0.0",
|
|
21
|
-
"
|
|
21
|
+
"react-compiler-runtime": "^1.0.0",
|
|
22
|
+
"@fontsource/rubik": "^5.2.5"
|
|
22
23
|
},
|
|
23
24
|
"scripts": {
|
|
24
25
|
"dev": "vite --mode development",
|
|
@@ -40,6 +41,7 @@
|
|
|
40
41
|
"devDependencies": {
|
|
41
42
|
"@tailwindcss/typography": "^0.5.16",
|
|
42
43
|
"@tailwindcss/vite": "^4.1.12",
|
|
44
|
+
"@types/node": "^20.19.41",
|
|
43
45
|
"@types/react": "^19.0.8",
|
|
44
46
|
"@types/react-dom": "^19.0.3",
|
|
45
47
|
"@vitejs/plugin-react": "^4.3.4",
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
3
|
import "@fontsource/jetbrains-mono";
|
|
4
|
-
import "
|
|
4
|
+
import "@fontsource/rubik";
|
|
5
5
|
|
|
6
|
-
import { useRebaseAuthController, useBackendUserManagement
|
|
7
|
-
import { Rebase } from "@rebasepro/core";
|
|
6
|
+
import { useRebaseAuthController, useBackendUserManagement } from "@rebasepro/auth";
|
|
7
|
+
import { Rebase, RebaseAuth } from "@rebasepro/core";
|
|
8
8
|
import { RebaseCMS, RebaseShell } from "@rebasepro/admin";
|
|
9
9
|
import { RebaseStudio } from "@rebasepro/studio";
|
|
10
10
|
import { createRebaseClient } from "@rebasepro/client";
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"resolveJsonModule": true,
|
|
15
15
|
"isolatedModules": true,
|
|
16
16
|
"noEmit": true,
|
|
17
|
-
"jsx": "react-jsx"
|
|
17
|
+
"jsx": "react-jsx",
|
|
18
|
+
"types": ["vite/client", "node"]
|
|
18
19
|
},
|
|
19
|
-
"include": ["
|
|
20
|
+
"include": ["src/**/*", "vite.config.ts"]
|
|
20
21
|
}
|
|
@@ -20,7 +20,7 @@ export default defineConfig({
|
|
|
20
20
|
output: {
|
|
21
21
|
manualChunks(id) {
|
|
22
22
|
// Heavy vendor libraries — split into individually cached chunks
|
|
23
|
-
if (id.includes("
|
|
23
|
+
if (id.includes("exceljs")) return "vendor-exceljs";
|
|
24
24
|
if (id.includes("prosemirror")) return "vendor-prosemirror";
|
|
25
25
|
if (id.includes("monaco-editor") || id.includes("@monaco-editor")) return "vendor-monaco";
|
|
26
26
|
if (id.includes("@xyflow") || id.includes("dagre")) return "vendor-xyflow";
|