@rebasepro/common 0.4.0 → 0.5.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/README.md +73 -220
- package/dist/index.es.js +11 -11
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +11 -11
- package/dist/index.umd.js.map +1 -1
- package/dist/util/permissions.d.ts +14 -6
- package/package.json +3 -3
- package/src/collections/CollectionRegistry.ts +1 -1
- package/src/util/permissions.ts +25 -21
package/README.md
CHANGED
|
@@ -1,242 +1,95 @@
|
|
|
1
|
-
|
|
2
|
-
<a href="https://rebase.pro">
|
|
3
|
-
<img src="https://rebase.pro/img/logo_small.png" width="240px" alt="Rebase logo" />
|
|
4
|
-
</a>
|
|
5
|
-
</p>
|
|
1
|
+
# @rebasepro/common
|
|
6
2
|
|
|
7
|
-
|
|
8
|
-
<h3 align="center">The Open-Source Headless CMS & Admin Panel for Postgres</h3>
|
|
9
|
-
<p align="center">
|
|
10
|
-
<strong>Ship production-ready backends and radically extensible back-office apps in minutes.</strong><br/>
|
|
11
|
-
Own your data, own your code. The absolute easiest way to build on PostgreSQL.
|
|
12
|
-
</p>
|
|
3
|
+
Shared utilities, collection registry, data driver adapter, and fluent query builder used across Rebase packages.
|
|
13
4
|
|
|
14
|
-
|
|
15
|
-
<a href="https://demo.rebase.pro">Live Demo</a> •
|
|
16
|
-
<a href="https://rebase.pro/docs">Documentation</a> •
|
|
17
|
-
<a href="https://rebase.pro/features">Features</a> •
|
|
18
|
-
<a href="https://github.com/rebasepro/rebase">GitHub</a> •
|
|
19
|
-
<a href="https://discord.gg/fxy7xsQm3m">Discord</a>
|
|
20
|
-
</p>
|
|
21
|
-
|
|
22
|
-
<p align="center">
|
|
23
|
-
<a href="https://www.npmjs.com/package/@rebasepro/core"><img src="https://img.shields.io/npm/v/@rebasepro/core.svg?style=flat-square&color=orange" alt="NPM Version" /></a>
|
|
24
|
-
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-purple.svg?style=flat-square" alt="License: MIT" /></a>
|
|
25
|
-
<a href="https://www.npmjs.com/package/@rebasepro/core"><img src="https://img.shields.io/npm/dw/@rebasepro/core?style=flat-square&color=blue" alt="NPM Downloads" /></a>
|
|
26
|
-
<a href="https://discord.gg/fxy7xsQm3m"><img src="https://img.shields.io/discord/1013768502458470442?style=flat-square&logo=discord&logoColor=white&label=Discord" alt="Discord" /></a>
|
|
27
|
-
</p>
|
|
28
|
-
|
|
29
|
-
<br/>
|
|
30
|
-
|
|
31
|
-
<p align="center">
|
|
32
|
-
<img src="https://rebase.pro/img/demo_products.png" width="800px" alt="Rebase Dashboard" />
|
|
33
|
-
</p>
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## What is Rebase?
|
|
38
|
-
|
|
39
|
-
Rebase is a **developer-first**, open-source headless CMS and admin panel framework built with **React** and **TypeScript**. It gives you a complete backend-as-a-service layer on top of PostgreSQL — including authentication, S3-compatible storage, a full admin UI, and auto-generated APIs — while letting you extend every layer with custom React components, serverless functions, and scripts.
|
|
40
|
-
|
|
41
|
-
### ✨ Key Highlights
|
|
42
|
-
|
|
43
|
-
- 🔓 **No Vendor Lock-in** — Self-host anywhere. Full control over your infrastructure, code, and database.
|
|
44
|
-
- ⚡ **Instant Setup** — `npx @rebasepro/cli init` scaffolds a production-ready project in seconds.
|
|
45
|
-
- 🗄️ **PostgreSQL First** — First-class Postgres support with Drizzle ORM, schema introspection, and automatic migrations.
|
|
46
|
-
- 🧩 **Radical Extensibility** — Not constrained to pre-built widgets. If you can build it in React, you can build it in Rebase.
|
|
47
|
-
- 🎨 **Premium UI** — Fast, accessible design system built on Tailwind CSS v4 and Radix UI.
|
|
48
|
-
- 🤖 **AI-Ready** — MCP server for AI-assisted database management, plus data enhancement and insights plugins.
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
## ⚡ Quick Start
|
|
53
|
-
|
|
54
|
-
Scaffold a complete, self-hosted Rebase application connected to your database:
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
npx @rebasepro/cli init my-rebase-app
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
Configure your database in `.env`, then start everything:
|
|
5
|
+
## Installation
|
|
61
6
|
|
|
62
7
|
```bash
|
|
63
|
-
|
|
64
|
-
npm run dev
|
|
8
|
+
pnpm add @rebasepro/common
|
|
65
9
|
```
|
|
66
10
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
---
|
|
11
|
+
## What This Package Does
|
|
70
12
|
|
|
71
|
-
|
|
13
|
+
`@rebasepro/common` is the lowest-level shared logic layer in the Rebase frontend stack. It provides:
|
|
72
14
|
|
|
73
|
-
|
|
15
|
+
- **Collection utilities** — collection registry, default collection definitions, path resolution, navigation helpers
|
|
16
|
+
- **Data driver adapter** — `buildRebaseData()` bridges any `DataDriver` implementation into a `RebaseData` proxy with typed collection accessors
|
|
17
|
+
- **Query builder** — fluent `QueryBuilder` class plus `or()`, `and()`, `cond()` helpers for composing complex queries
|
|
18
|
+
- **Entity/property utilities** — entity resolution, enum helpers, permission checks, reference/relation helpers, storage path utils, callback utilities
|
|
74
19
|
|
|
75
|
-
|
|
20
|
+
This package has no React dependency — it's pure TypeScript and can be used in both client and server contexts.
|
|
76
21
|
|
|
77
|
-
|
|
78
|
-
- **Card grid** — Visual overview with image previews
|
|
79
|
-
- **List view** — Compact, scannable layout
|
|
80
|
-
- **Custom views** — Build any React component as a collection view
|
|
22
|
+
## Key Exports
|
|
81
23
|
|
|
82
|
-
###
|
|
24
|
+
### Data
|
|
83
25
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
### 🔐 Authentication & Access Control
|
|
87
|
-
|
|
88
|
-
Built-in authentication with multiple providers:
|
|
89
|
-
|
|
90
|
-
- **Email/Password** — With password reset flow
|
|
91
|
-
- **Google OAuth** — One-click sign-in
|
|
92
|
-
- **Anonymous** — For guest access
|
|
93
|
-
|
|
94
|
-
Granular **role-based access control (RBAC)** with customizable permissions per collection, field, and action.
|
|
95
|
-
|
|
96
|
-
### 📦 S3-Compatible Storage
|
|
97
|
-
|
|
98
|
-
Native S3-compatible file storage with:
|
|
99
|
-
|
|
100
|
-
- Drag-and-drop uploads with progress tracking
|
|
101
|
-
- Automatic image resizing and optimization
|
|
102
|
-
- File metadata management
|
|
103
|
-
- Storage browser in Studio
|
|
104
|
-
|
|
105
|
-
### 🛠️ Studio — Developer Toolbox
|
|
106
|
-
|
|
107
|
-
A full developer environment built into the admin panel:
|
|
108
|
-
|
|
109
|
-
| Tool | Description |
|
|
26
|
+
| Export | Description |
|
|
110
27
|
|---|---|
|
|
111
|
-
|
|
|
112
|
-
|
|
|
113
|
-
|
|
|
114
|
-
|
|
|
115
|
-
|
|
|
116
|
-
| **Cron Jobs** | Schedule and monitor recurring tasks |
|
|
117
|
-
| **Storage Browser** | Browse and manage files in your S3-compatible storage |
|
|
118
|
-
|
|
119
|
-
### ⚡ Extensible API & Edge Functions
|
|
120
|
-
|
|
121
|
-
Drop custom Hono routes or scheduled tasks into the `functions/` and `crons/` directories. Rebase auto-loads them with database access and JWT authentication middleware injected automatically.
|
|
28
|
+
| `buildRebaseData(driver)` | Wraps a `DataDriver` in a `Proxy`-based `RebaseData` object. Property access like `data.products` returns a `CollectionAccessor` for that collection slug (camelCase → snake_case). |
|
|
29
|
+
| `QueryBuilder<M>` | Fluent query builder with `.where()`, `.orderBy()`, `.limit()`, `.offset()`, `.search()`, `.include()`, `.find()`, and `.listen()` |
|
|
30
|
+
| `or(...conditions)` | Create an OR logical condition |
|
|
31
|
+
| `and(...conditions)` | Create an AND logical condition |
|
|
32
|
+
| `cond(column, op, value)` | Create a single filter condition |
|
|
122
33
|
|
|
123
|
-
###
|
|
34
|
+
### Collections
|
|
124
35
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
```bash
|
|
128
|
-
npx @rebasepro/cli generate-sdk
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
### 🤖 MCP Server
|
|
132
|
-
|
|
133
|
-
A built-in **Model Context Protocol** server that enables AI assistants to:
|
|
134
|
-
|
|
135
|
-
- Query and manage your database schema
|
|
136
|
-
- Create, read, update, and delete documents
|
|
137
|
-
- Manage users and roles
|
|
138
|
-
- Introspect your data model
|
|
139
|
-
|
|
140
|
-
### 🔍 Schema Inference & Introspection
|
|
141
|
-
|
|
142
|
-
Point Rebase at an existing PostgreSQL database and automatically generate collection definitions from your tables — including types, relations, validation constraints, and more.
|
|
143
|
-
|
|
144
|
-
### 📥📤 Import & Export
|
|
145
|
-
|
|
146
|
-
Import data from **CSV, JSON, and Excel** with an intuitive field mapper. Export your data in multiple formats with configurable column selection.
|
|
147
|
-
|
|
148
|
-
### 🧩 Plugins
|
|
149
|
-
|
|
150
|
-
Extend the admin experience with first-party plugins:
|
|
151
|
-
|
|
152
|
-
- **Data Enhancement** — AI-powered field suggestions and auto-fill
|
|
153
|
-
- **Insights** — Analytics dashboards and usage metrics
|
|
154
|
-
|
|
155
|
-
### 📜 Standalone Scripting
|
|
156
|
-
|
|
157
|
-
Write standalone data manipulation scripts that connect directly to your running backend using the `@rebasepro/client` SDK. The CLI persists the dev server URL to `.rebase-dev-url` for zero-config local development.
|
|
158
|
-
|
|
159
|
-
### 🧩 Custom Views & React Extensibility
|
|
160
|
-
|
|
161
|
-
Build entirely custom views — dashboards, previews, charts — and drop them into the main navigation or as entity-level tabs. Use built-in hooks to interact with Rebase's internal state.
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
## 🛠️ Core Technologies
|
|
166
|
-
|
|
167
|
-
Built entirely on modern, battle-tested web standards:
|
|
168
|
-
|
|
169
|
-
| Technology | What we use it for |
|
|
36
|
+
| Export | Description |
|
|
170
37
|
|---|---|
|
|
171
|
-
|
|
|
172
|
-
|
|
|
173
|
-
| 🌊 **Tailwind CSS v4** | Utility-first styling |
|
|
174
|
-
| 🔌 **WebSockets** | Real-time synchronization |
|
|
175
|
-
| 🗄️ **Drizzle ORM** | Type-safe SQL migrations and queries |
|
|
176
|
-
| 🧱 **Radix UI** | Accessible UI primitives |
|
|
177
|
-
| 📝 **TipTap v3** | Rich text editing |
|
|
178
|
-
| 🌐 **Hono** | Ultrafast HTTP server framework |
|
|
179
|
-
|
|
180
|
-
---
|
|
38
|
+
| `CollectionRegistry` | Registry for managing collection definitions |
|
|
39
|
+
| Default collections | Pre-built collection configurations |
|
|
181
40
|
|
|
182
|
-
|
|
41
|
+
### Utilities
|
|
183
42
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
| Package | Description |
|
|
43
|
+
| Module | Contents |
|
|
187
44
|
|---|---|
|
|
188
|
-
|
|
|
189
|
-
|
|
|
190
|
-
|
|
|
191
|
-
|
|
|
192
|
-
|
|
|
193
|
-
|
|
|
194
|
-
|
|
|
195
|
-
|
|
|
196
|
-
|
|
|
197
|
-
|
|
|
198
|
-
|
|
|
199
|
-
|
|
|
200
|
-
|
|
|
201
|
-
|
|
|
202
|
-
|
|
|
203
|
-
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
45
|
+
| `collections` | Collection config helpers |
|
|
46
|
+
| `common` | General-purpose utilities |
|
|
47
|
+
| `entities` | Entity value resolution |
|
|
48
|
+
| `enums` | Enum type helpers |
|
|
49
|
+
| `paths` | Path parsing and manipulation |
|
|
50
|
+
| `resolutions` | Property and collection resolution |
|
|
51
|
+
| `permissions` | Permission evaluation |
|
|
52
|
+
| `references` | Reference property helpers |
|
|
53
|
+
| `relations` | Relation property helpers |
|
|
54
|
+
| `navigation_from_path` | Build navigation tree from a path |
|
|
55
|
+
| `parent_references_from_path` | Extract parent references |
|
|
56
|
+
| `builders` | Collection/property builder utilities |
|
|
57
|
+
| `storage` | Storage path utilities |
|
|
58
|
+
| `callbacks` | Callback composition utilities |
|
|
59
|
+
| `conditions` | Conditional logic helpers |
|
|
60
|
+
| `navigation_utils` | Navigation tree utilities |
|
|
61
|
+
|
|
62
|
+
## Quick Start
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { buildRebaseData, QueryBuilder, or, cond } from "@rebasepro/common";
|
|
66
|
+
|
|
67
|
+
// Wrap a DataDriver into a proxy-based data accessor
|
|
68
|
+
const data = buildRebaseData(myDriver);
|
|
69
|
+
|
|
70
|
+
// Access collections by name (camelCase auto-converts to snake_case)
|
|
71
|
+
const { data: products } = await data.products.find({ limit: 10 });
|
|
72
|
+
const entity = await data.products.findById("abc-123");
|
|
73
|
+
|
|
74
|
+
// Fluent query builder
|
|
75
|
+
const { data: results } = await data.products
|
|
76
|
+
.where("status", "==", "published")
|
|
77
|
+
.orderBy("created_at", "desc")
|
|
78
|
+
.limit(20)
|
|
79
|
+
.find();
|
|
80
|
+
|
|
81
|
+
// Complex logical queries
|
|
82
|
+
const { data: filtered } = await data.products
|
|
83
|
+
.where(or(
|
|
84
|
+
cond("category", "==", "electronics"),
|
|
85
|
+
cond("price", ">=", 100)
|
|
86
|
+
))
|
|
87
|
+
.find();
|
|
218
88
|
```
|
|
219
89
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
## Demo
|
|
223
|
-
|
|
224
|
-
Explore a live interactive sandbox with all features — data resets periodically:
|
|
225
|
-
|
|
226
|
-
**👉 [demo.rebase.pro](https://demo.rebase.pro)**
|
|
227
|
-
|
|
228
|
-
---
|
|
229
|
-
|
|
230
|
-
## Support & Community
|
|
231
|
-
|
|
232
|
-
- 📖 [Documentation](https://rebase.pro/docs)
|
|
233
|
-
- 💬 [Discord Community](https://discord.gg/fxy7xsQm3m)
|
|
234
|
-
- 🐛 [GitHub Issues](https://github.com/rebasepro/rebase/issues)
|
|
235
|
-
- 📝 [Changelog](./CHANGELOG.md)
|
|
236
|
-
|
|
237
|
-
---
|
|
238
|
-
|
|
239
|
-
## License
|
|
90
|
+
## Related Packages
|
|
240
91
|
|
|
241
|
-
|
|
242
|
-
|
|
92
|
+
- [`@rebasepro/types`](../types) — `DataDriver`, `RebaseData`, `CollectionAccessor`, `Entity`, `FindResponse`, etc.
|
|
93
|
+
- [`@rebasepro/utils`](../utils) — Low-level utilities (`toSnakeCase`, etc.)
|
|
94
|
+
- [`@rebasepro/core`](../core) — Runtime layer that consumes `@rebasepro/common`
|
|
95
|
+
- [`@rebasepro/client`](../client) — HTTP client that re-exports and extends the `QueryBuilder`
|
package/dist/index.es.js
CHANGED
|
@@ -907,14 +907,14 @@ function evaluateRule(rule, auth, entity) {
|
|
|
907
907
|
if (rule.withCheck && !evaluateAST(rule.withCheck, auth, entity)) return false;
|
|
908
908
|
return true;
|
|
909
909
|
}
|
|
910
|
-
function checkOperation(collection,
|
|
910
|
+
function checkOperation(collection, authContext, entity, targetOperation) {
|
|
911
911
|
const securityRules = getDataSourceCapabilities(collection.driver).supportsRLS ? collection.securityRules : void 0;
|
|
912
912
|
if (!securityRules || securityRules.length === 0) {
|
|
913
913
|
return true;
|
|
914
914
|
}
|
|
915
915
|
const applicableRules = securityRules.filter((r) => r.operation === targetOperation || r.operation === "all" || r.operations?.includes(targetOperation) || r.operations?.includes("all"));
|
|
916
916
|
if (applicableRules.length === 0) return false;
|
|
917
|
-
const userRoleIds =
|
|
917
|
+
const userRoleIds = authContext.user?.roles ?? [];
|
|
918
918
|
const userRoles = [...userRoleIds, "public"];
|
|
919
919
|
const roleApplicableRules = applicableRules.filter((rule) => {
|
|
920
920
|
if (!rule.roles || rule.roles.length === 0) return true;
|
|
@@ -925,7 +925,7 @@ function checkOperation(collection, authController, entity, targetOperation) {
|
|
|
925
925
|
let deniedByRestrictive = false;
|
|
926
926
|
for (const rule of roleApplicableRules) {
|
|
927
927
|
const mode = rule.mode || "permissive";
|
|
928
|
-
const passed = evaluateRule(rule,
|
|
928
|
+
const passed = evaluateRule(rule, authContext, entity);
|
|
929
929
|
if (mode === "restrictive" && !passed) {
|
|
930
930
|
deniedByRestrictive = true;
|
|
931
931
|
break;
|
|
@@ -942,17 +942,17 @@ function checkOperation(collection, authController, entity, targetOperation) {
|
|
|
942
942
|
return false;
|
|
943
943
|
}
|
|
944
944
|
}
|
|
945
|
-
function canReadCollection(collection,
|
|
946
|
-
return checkOperation(collection,
|
|
945
|
+
function canReadCollection(collection, authContext) {
|
|
946
|
+
return checkOperation(collection, authContext, null, "select");
|
|
947
947
|
}
|
|
948
|
-
function canEditEntity(collection,
|
|
949
|
-
return checkOperation(collection,
|
|
948
|
+
function canEditEntity(collection, authContext, path, entity) {
|
|
949
|
+
return checkOperation(collection, authContext, entity, "update");
|
|
950
950
|
}
|
|
951
|
-
function canCreateEntity(collection,
|
|
952
|
-
return checkOperation(collection,
|
|
951
|
+
function canCreateEntity(collection, authContext, path, entity) {
|
|
952
|
+
return checkOperation(collection, authContext, entity, "insert");
|
|
953
953
|
}
|
|
954
|
-
function canDeleteEntity(collection,
|
|
955
|
-
return checkOperation(collection,
|
|
954
|
+
function canDeleteEntity(collection, authContext, path, entity) {
|
|
955
|
+
return checkOperation(collection, authContext, entity, "delete");
|
|
956
956
|
}
|
|
957
957
|
function getEntityImagePreviewPropertyKey(collection) {
|
|
958
958
|
for (const key in collection.properties) {
|