rimecms 0.31.3 → 0.31.4
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 +6 -207
- package/dist/adapter-sqlite/auth.server.d.ts +1 -1
- package/dist/adapter-sqlite/generate-schema/templates.server.d.ts +2 -2
- package/dist/adapter-sqlite/generate-schema/templates.server.js +3 -1
- package/dist/adapter-sqlite/generate-schema/write.server.js +7 -3
- package/dist/core/config/auth/better-auth-hooks.server.d.ts +1 -1
- package/dist/core/config/auth/better-auth-hooks.server.js +1 -2
- package/dist/core/config/auth/better-auth-permissions.d.ts +27 -67
- package/dist/core/config/auth/better-auth.server.d.ts +649 -481
- package/dist/core/config/auth/better-auth.server.js +2 -1
- package/dist/core/config/server/write.server.js +5 -0
- package/dist/core/dev/cli/clear/index.server.js +5 -5
- package/dist/core/dev/cli/init/index.server.js +14 -28
- package/dist/core/dev/cli/init/templates.d.ts +12 -0
- package/dist/core/dev/cli/init/templates.js +47 -3
- package/dist/core/dev/constants.d.ts +15 -7
- package/dist/core/dev/constants.js +49 -10
- package/dist/core/dev/generate/routes/common.server.js +5 -2
- package/dist/core/dev/generate/sanitize/index.server.js +3 -3
- package/dist/core/dev/generate/types/index.server.js +3 -2
- package/dist/core/dev/vite/index.server.js +4 -8
- package/dist/core/ensure.server.d.ts +2 -2
- package/dist/core/ensure.server.js +17 -8
- package/dist/core/handlers/auth.server.js +2 -3
- package/dist/core/rime.server.d.ts +1302 -966
- package/dist/core/rime.server.js +6 -0
- package/dist/fields/number/component/number.css +0 -2
- package/dist/fields/relation/component/upload/upload.css +9 -0
- package/dist/fields/rich-text/component/drag-handle/drag-handle.css +0 -1
- package/dist/fields/rich-text/component/styles/rich-text.css +7 -0
- package/dist/fields/rich-text/core/extensions/drag-handle/helpers/findNextElementFromCursor.d.ts +1 -1
- package/dist/fields/rich-text/core/svelte/node-view-wrapper.svelte.d.ts +12 -5
- package/dist/panel/components/sections/collection/header/SelectUI.svelte.d.ts +3 -3
- package/dist/panel/components/sections/document/AuthAPIKeyDialog.svelte.d.ts +3 -3
- package/dist/panel/components/sections/live/Consumer.svelte.d.ts +11 -4
- package/dist/panel/components/sections/live/LiveEdit.svelte.d.ts +13 -6
- package/dist/panel/components/sections/live/LiveFloatingUI.svelte.d.ts +3 -3
- package/dist/panel/components/ui/calendar/calendar.css +0 -11
- package/dist/panel/components/ui/command/command-group.css +0 -1
- package/dist/panel/components/ui/label/label.css +1 -0
- package/dist/panel/components/ui/radio-group/radio-group.css +0 -2
- package/dist/panel/components/ui/scroll-area/scroll-area.css +4 -0
- package/dist/panel/components/ui/sheet/sheet.css +16 -0
- package/dist/panel/components/ui/tabs/tabs.css +0 -7
- package/dist/panel/style/index.css +0 -6
- package/dist/panel/util/auth.js +1 -1
- package/package.json +8 -6
- package/dist/panel/components/ui/dropdown-menu/index.d.ts +0 -23
package/README.md
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|

|
|
2
2
|

|
|
3
3
|
|
|
4
|
-
Headless CMS powered by SvelteKit.
|
|
4
|
+
Headless CMS powered by SvelteKit. [Read the doc](https://github.com/bienbiendev/rime-doc/tree/master/docs)
|
|
5
5
|
|
|
6
6
|

|
|
7
7
|

|
|
8
8
|
[](https://github.com/bienbiendev/rime/blob/main/LICENSE)
|
|
9
9
|
|
|
10
|
-

|
|
10
|
+

|
|
13
11
|
|
|
14
12
|
## Features
|
|
15
13
|
|
|
16
14
|
- Easy configuration
|
|
17
15
|
- TypeScript
|
|
18
|
-
- Built-in authentication
|
|
16
|
+
- Built-in authentication with configurable better-auth.
|
|
19
17
|
- Auto-generated:
|
|
20
18
|
- API endpoints
|
|
21
19
|
- Types
|
|
@@ -26,210 +24,11 @@ Headless CMS powered by SvelteKit.
|
|
|
26
24
|
- Media management
|
|
27
25
|
- Fine grained access control
|
|
28
26
|
- i18n support
|
|
29
|
-
- Document
|
|
27
|
+
- Document versions
|
|
30
28
|
- Optional SMTP integration
|
|
31
|
-
|
|
32
|
-
### Content Management
|
|
33
|
-
|
|
34
|
-
Fields types:
|
|
35
|
-
|
|
36
|
-
- Blocks
|
|
37
|
-
- Tree (nested array)
|
|
38
|
-
- Tabs
|
|
39
|
-
- Rich Text (TipTap)
|
|
40
|
-
- Relation
|
|
41
|
-
- Link
|
|
42
|
-
- Slug
|
|
43
|
-
- Email
|
|
44
|
-
- Group
|
|
45
|
-
- Select/Radio/Checkbox
|
|
46
|
-
- Number
|
|
47
|
-
- And more...
|
|
48
|
-
|
|
49
|
-
## Quick Start
|
|
50
|
-
|
|
51
|
-
### 1. Create a SvelteKit Project
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
npx sv create my-app
|
|
55
|
-
cd my-app
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
> [!NOTE]
|
|
59
|
-
> Select TypeScript when prompted
|
|
60
|
-
|
|
61
|
-
### 2. Install Rime
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
npm install rimecms
|
|
65
|
-
npx rime init
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
The `rime init` command will automatically:
|
|
69
|
-
|
|
70
|
-
- Create/populate `.env` file
|
|
71
|
-
- Create `src/lib/+rime/rime.config.ts` config file
|
|
72
|
-
- Create a `db/` folder
|
|
73
|
-
- Add a `drizzle.config.ts`
|
|
74
|
-
- Create `src/hooks.server.ts` with the required initialization code
|
|
75
|
-
- Add the Rime plugin to `vite.config.ts`
|
|
76
|
-
- Install dependencies.
|
|
77
|
-
- Push initial schema
|
|
78
|
-
|
|
79
|
-
### 3. Create the first admin user
|
|
80
|
-
|
|
81
|
-
```bash
|
|
82
|
-
npm run dev
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
curl -v POST http://localhost:5173/api/init \
|
|
87
|
-
-H "Content-Type: application/json" \
|
|
88
|
-
-d '{"email": "you@website.com", "password": "super-Secret+2000", "name": "Admin"}'
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
## Configuration Example
|
|
92
|
-
|
|
93
|
-
```typescript
|
|
94
|
-
// ./src/lib/+rime/rime.config.server.ts
|
|
95
|
-
import { rime, Collection, Area } from '$rime/config';
|
|
96
|
-
import { adapterSqlite } from 'rimecms/adapter-sqlite';
|
|
97
|
-
import { Settings2 } from '@lucide/svelte';
|
|
98
|
-
import { relation, link, richText, text, toggle } from 'rimecms/fields';
|
|
99
|
-
import { access } from "rimecms/util";
|
|
100
|
-
|
|
101
|
-
const Pages = Collection.create('pages', {
|
|
102
|
-
fields: [
|
|
103
|
-
text('title').isTitle().required(),
|
|
104
|
-
relation('parent').to('pages'),
|
|
105
|
-
richText('intro')
|
|
106
|
-
],
|
|
107
|
-
access: {
|
|
108
|
-
read: () => true,
|
|
109
|
-
create: (user) => access.isAdmin(user),
|
|
110
|
-
update: (user) => access.hasRoles(user, 'admin', 'editor')
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
const Settings = Area.create('settings', {
|
|
115
|
-
icon: Settings2,
|
|
116
|
-
fields: [
|
|
117
|
-
toggle('maintenance'),
|
|
118
|
-
link('about'),
|
|
119
|
-
relation('logo').to('medias')
|
|
120
|
-
],
|
|
121
|
-
access: {
|
|
122
|
-
read: () => true
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const Medias = Collection.create('medias', {
|
|
127
|
-
label: {
|
|
128
|
-
singular: 'Media',
|
|
129
|
-
plural: 'Medias',
|
|
130
|
-
},
|
|
131
|
-
upload: true,
|
|
132
|
-
fields: [
|
|
133
|
-
text('alt')
|
|
134
|
-
]
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
// Properties prefixed with "$" are server-only props, they will be stripped
|
|
138
|
-
// in the generated client config
|
|
139
|
-
export default rime({
|
|
140
|
-
$adapter: adapterSqlite('my-db.sqlite'),
|
|
141
|
-
collections: [Pages, Medias],
|
|
142
|
-
areas: [Settings],
|
|
143
|
-
staff: {
|
|
144
|
-
roles: [{ value: 'admin', label: 'Administrator' }, { value: 'editor' }],
|
|
145
|
-
fields: [
|
|
146
|
-
text('website')
|
|
147
|
-
]
|
|
148
|
-
},
|
|
149
|
-
panel: {
|
|
150
|
-
$access: (user) => access.hasRoles(user, 'admin', 'editor'),
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
> [!NOTE]
|
|
157
|
-
> Icons must be imported from `@lucide/svelte` (other icon packages are not tested, but should work if a size prop is available on icon component)
|
|
158
|
-
> Detailed configuration documentation is in development. Feel free to open issues for questions!
|
|
159
|
-
|
|
160
|
-
## Retrieve your data
|
|
161
|
-
|
|
162
|
-
### In routes handlers :
|
|
163
|
-
|
|
164
|
-
```ts
|
|
165
|
-
export const load = async (event: LayoutServerLoadEvent) => {
|
|
166
|
-
const { rime } = event.locals;
|
|
167
|
-
// Get an Area document
|
|
168
|
-
const menu = await rime.area('menu').find();
|
|
169
|
-
// Get all pages documents
|
|
170
|
-
const pages = await rime.collection('pages').findAll({ locale: 'en' });
|
|
171
|
-
// Get a page byId
|
|
172
|
-
const home = await rime.collection('pages').findById({ locale: 'en', id: 'some-id' });
|
|
173
|
-
// Get a user with a query
|
|
174
|
-
const [user] = await rime.collection('users').find({
|
|
175
|
-
query: `where[email][equals]=some@email.com` // qs query or ParsedQsQuery
|
|
176
|
-
});
|
|
177
|
-
// Get some config values
|
|
178
|
-
const languages = rime.config.getLocalesCodes();
|
|
179
|
-
const collections = rime.config.collections;
|
|
180
|
-
//...
|
|
181
|
-
};
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
### From the API :
|
|
185
|
-
|
|
186
|
-
```ts
|
|
187
|
-
const { docs } = await fetch('http://localhost:5173/api/pages').then((r) => r.json());
|
|
188
|
-
const { docs } = await fetch('http://localhost:5173/api/pages?sort=title&limit=1').then((r) =>
|
|
189
|
-
r.json()
|
|
190
|
-
);
|
|
191
|
-
const { docs } = await fetch(
|
|
192
|
-
'http://localhost:5173/api/pages?where[author][equals]=some-id&locale=en`;'
|
|
193
|
-
).then((r) => r.json());
|
|
194
|
-
const { docs } = await fetch(
|
|
195
|
-
'http://localhost:5173/api/pages?where[author.email][equals]=some@email.com&locale=en`;'
|
|
196
|
-
).then((r) => r.json());
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
## DEPLOYING
|
|
200
|
-
|
|
201
|
-
For now I am using it with @svelte/adapter-node, other adapter not tested and probably not working.
|
|
202
|
-
|
|
203
|
-
With the node adapter :
|
|
204
|
-
|
|
205
|
-
```sh
|
|
206
|
-
npx rime build
|
|
207
|
-
npx rime build -d # to copy the database directory
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
It's doing bascically `vite build` under the hood and create the server file inside an app directory, plus giving some info on how to run it.
|
|
211
|
-
|
|
212
|
-
## ROADMAP
|
|
213
|
-
|
|
214
|
-
- [x] switch from lucia to better-auth
|
|
215
|
-
- [x] Document locked while being edited by another user
|
|
216
|
-
- [x] Panel i18n
|
|
217
|
-
- [x] Document status
|
|
218
|
-
- [x] Tree field
|
|
219
|
-
- [x] more tiptap integration
|
|
220
|
-
- [x] more flexible better-auth integration
|
|
221
|
-
- [x] Document version
|
|
222
|
-
- [x] collection nested
|
|
223
|
-
- [x] more better-auth integration
|
|
224
|
-
- [x] Handle relation poperties in queries
|
|
225
|
-
- [~] Documentation
|
|
226
|
-
- [ ] Live Edit system in practice
|
|
227
|
-
- [ ] configurable files storage adapter (local, s3, etc)
|
|
228
|
-
- [ ] other storage adapter (postgress, turso, etc)
|
|
229
|
-
- [ ] auto-saved draft
|
|
230
|
-
- [ ] Put bin commands in a separate package ex: @rime/kit
|
|
29
|
+
- Many built-in fields type
|
|
231
30
|
|
|
232
31
|
## Acknowledgments
|
|
233
32
|
|
|
234
33
|
- Built with components from @huntabyte's bits-ui
|
|
235
|
-
- Inspired by Kirby CMS and Payload CMS
|
|
34
|
+
- Inspired by Kirby CMS and Payload CMS
|
|
@@ -11,7 +11,7 @@ declare const createAuthFacade: (args: {
|
|
|
11
11
|
db: LibSQLDatabase<GetRegisterType<"Schema">>;
|
|
12
12
|
schema: GetRegisterType<"Schema">;
|
|
13
13
|
}) => {
|
|
14
|
-
betterAuthAdapter: (options: import("better-auth
|
|
14
|
+
betterAuthAdapter: (options: import("better-auth").BetterAuthOptions) => import("better-auth").DBAdapter<import("better-auth").BetterAuthOptions>;
|
|
15
15
|
hasAuthUser: () => Promise<boolean>;
|
|
16
16
|
getAuthUserId: ({ slug, id }: {
|
|
17
17
|
slug: CollectionSlug;
|
|
@@ -170,8 +170,8 @@ export declare const templateExportTables: (tables: string[]) => string;
|
|
|
170
170
|
* Generates authentication tables for the schema
|
|
171
171
|
* Creates tables for users, sessions, accounts, and verifications
|
|
172
172
|
*/
|
|
173
|
-
export declare const templateAuth = "\nexport const authUsers = sqliteTable('auth_users', {\n\tid: text('id').primaryKey(),\n\tname: text('name').notNull(),\n\temail: text('email').notNull().unique(),\n\temailVerified: integer('email_verified', { mode: 'boolean' }).notNull(),\n\timage: text('image'),\n\tcreatedAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n\tupdatedAt: integer('updated_at', { mode: 'timestamp_ms' }).notNull(),\n\trole: text('role'),\n\tbanned: integer('banned', { mode: 'boolean' }),\n\tbanReason: text('ban_reason'),\n\tbanExpires: integer('ban_expires', { mode: 'timestamp_ms' }),\n\ttype: text('type').notNull()\n });\n\nexport const authSessions = sqliteTable('auth_sessions', {\n\tid: text('id').primaryKey(),\n\texpiresAt: integer('expires_at', { mode: 'timestamp_ms' }).notNull(),\n\ttoken: text('token').notNull().unique(),\n\tcreatedAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n\tupdatedAt: integer('updated_at', { mode: 'timestamp_ms' }).notNull(),\n\tipAddress: text('ip_address'),\n\tuserAgent: text('user_agent'),\n\tuserId: text('user_id')\n\t\t.notNull()\n\t\t.references(() => authUsers.id, { onDelete: 'cascade' }),\n\timpersonatedBy: text('impersonated_by')\n });\n\nexport const authAccounts = sqliteTable('auth_accounts', {\n\tid: text('id').primaryKey(),\n\taccountId: text('account_id').notNull(),\n\tproviderId: text('provider_id').notNull(),\n\tuserId: text('user_id')\n\t\t.notNull()\n\t\t.references(() => authUsers.id, { onDelete: 'cascade' }),\n\taccessToken: text('access_token'),\n\trefreshToken: text('refresh_token'),\n\tidToken: text('id_token'),\n\taccessTokenExpiresAt: integer('access_token_expires_at', { mode: 'timestamp_ms' }),\n\trefreshTokenExpiresAt: integer('refresh_token_expires_at', { mode: 'timestamp_ms' }),\n\tscope: text('scope'),\n\tpassword: text('password'),\n\tcreatedAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n\tupdatedAt: integer('updated_at', { mode: 'timestamp_ms' }).notNull()\n });\n\nexport const authVerifications = sqliteTable('auth_verifications', {\n\tid: text('id').primaryKey(),\n\tidentifier: text('identifier').notNull(),\n\tvalue: text('value').notNull(),\n\texpiresAt: integer('expires_at', { mode: 'timestamp_ms' }).notNull(),\n\tcreatedAt: integer('created_at', { mode: 'timestamp_ms' }),\n\tupdatedAt: integer('updated_at', { mode: 'timestamp_ms' })\n });\n";
|
|
174
|
-
export declare const templateAPIKey = "\nexport const apikey = sqliteTable(\"apikey\", {\n\tid: text('id').primaryKey(),\n\tname: text('name'),\n\tstart: text('start'),\n\tprefix: text('prefix'),\n\tkey: text('key').notNull(),\n\
|
|
173
|
+
export declare const templateAuth = "\nexport const authUsers = sqliteTable('auth_users', {\n\tid: text('id').primaryKey(),\n\tname: text('name').notNull(),\n\temail: text('email').notNull().unique(),\n\temailVerified: integer('email_verified', { mode: 'boolean' }).notNull(),\n\timage: text('image'),\n\tcreatedAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n\tupdatedAt: integer('updated_at', { mode: 'timestamp_ms' }).notNull(),\n\trole: text('role'),\n\tbanned: integer('banned', { mode: 'boolean' }),\n\tbanReason: text('ban_reason'),\n\tbanExpires: integer('ban_expires', { mode: 'timestamp_ms' }),\n\ttype: text('type').notNull()\n });\n\nexport const authSessions = sqliteTable('auth_sessions', {\n\tid: text('id').primaryKey(),\n\texpiresAt: integer('expires_at', { mode: 'timestamp_ms' }).notNull(),\n\ttoken: text('token').notNull().unique(),\n\tcreatedAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n\tupdatedAt: integer('updated_at', { mode: 'timestamp_ms' }).notNull(),\n\tipAddress: text('ip_address'),\n\tuserAgent: text('user_agent'),\n\tuserId: text('user_id')\n\t\t.notNull()\n\t\t.references(() => authUsers.id, { onDelete: 'cascade' }),\n\timpersonatedBy: text('impersonated_by')\n });\n\nexport const authAccounts = sqliteTable('auth_accounts', {\n\tid: text('id').primaryKey(),\n\taccountId: text('account_id').notNull(),\n\tissuer: text('issuer').notNull(),\n\tproviderId: text('provider_id').notNull(),\n\tuserId: text('user_id')\n\t\t.notNull()\n\t\t.references(() => authUsers.id, { onDelete: 'cascade' }),\n\taccessToken: text('access_token'),\n\trefreshToken: text('refresh_token'),\n\tidToken: text('id_token'),\n\taccessTokenExpiresAt: integer('access_token_expires_at', { mode: 'timestamp_ms' }),\n\trefreshTokenExpiresAt: integer('refresh_token_expires_at', { mode: 'timestamp_ms' }),\n\tscope: text('scope'),\n\tpassword: text('password'),\n\tcreatedAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n\tupdatedAt: integer('updated_at', { mode: 'timestamp_ms' }).notNull()\n });\n\nexport const authVerifications = sqliteTable('auth_verifications', {\n\tid: text('id').primaryKey(),\n\tidentifier: text('identifier').notNull(),\n\tvalue: text('value').notNull(),\n\texpiresAt: integer('expires_at', { mode: 'timestamp_ms' }).notNull(),\n\tcreatedAt: integer('created_at', { mode: 'timestamp_ms' }),\n\tupdatedAt: integer('updated_at', { mode: 'timestamp_ms' })\n });\n";
|
|
174
|
+
export declare const templateAPIKey = "\nexport const apikey = sqliteTable(\"apikey\", {\n\tid: text('id').primaryKey(),\n\tname: text('name'),\n\tstart: text('start'),\n\tprefix: text('prefix'),\n\tkey: text('key').notNull(),\n\treferenceId: text('reference_id').notNull().references(()=> authUsers.id, { onDelete: 'cascade' }),\n\tconfigId: text('config_id').notNull().default('default'),\n\trefillInterval: integer('refill_interval'),\n\trefillAmount: integer('refill_amount'),\n\tlastRefillAt: integer('last_refill_at', { mode: 'timestamp' }),\n\tenabled: integer('enabled', { mode: 'boolean' }).default(true),\n\trateLimitEnabled: integer('rate_limit_enabled', { mode: 'boolean' }).default(true),\n\trateLimitTimeWindow: integer('rate_limit_time_window').default(86400000),\n\trateLimitMax: integer('rate_limit_max').default(10),\n\trequestCount: integer('request_count'),\n\tremaining: integer('remaining'),\n\tlastRequest: integer('last_request', { mode: 'timestamp' }),\n\texpiresAt: integer('expires_at', { mode: 'timestamp' }),\n\tcreatedAt: integer('created_at', { mode: 'timestamp' }).notNull(),\n\tupdatedAt: integer('updated_at', { mode: 'timestamp' }).notNull(),\n\tpermissions: text('permissions'),\n\tmetadata: text('metadata')\n});\n";
|
|
175
175
|
/**
|
|
176
176
|
* Generates the final schema export with all tables and relations
|
|
177
177
|
* Creates a schema object and exports it with proper TypeScript types
|
|
@@ -277,6 +277,7 @@ export const authSessions = sqliteTable('auth_sessions', {
|
|
|
277
277
|
export const authAccounts = sqliteTable('auth_accounts', {
|
|
278
278
|
id: text('id').primaryKey(),
|
|
279
279
|
accountId: text('account_id').notNull(),
|
|
280
|
+
issuer: text('issuer').notNull(),
|
|
280
281
|
providerId: text('provider_id').notNull(),
|
|
281
282
|
userId: text('user_id')
|
|
282
283
|
.notNull()
|
|
@@ -308,7 +309,8 @@ export const apikey = sqliteTable("apikey", {
|
|
|
308
309
|
start: text('start'),
|
|
309
310
|
prefix: text('prefix'),
|
|
310
311
|
key: text('key').notNull(),
|
|
311
|
-
|
|
312
|
+
referenceId: text('reference_id').notNull().references(()=> authUsers.id, { onDelete: 'cascade' }),
|
|
313
|
+
configId: text('config_id').notNull().default('default'),
|
|
312
314
|
refillInterval: integer('refill_interval'),
|
|
313
315
|
refillAmount: integer('refill_amount'),
|
|
314
316
|
lastRefillAt: integer('last_refill_at', { mode: 'timestamp' }),
|
|
@@ -6,11 +6,15 @@ import fs from 'fs';
|
|
|
6
6
|
import { spawnSync } from 'node:child_process';
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
const write = (schema) => {
|
|
9
|
+
const outputFile = schemaPath();
|
|
10
|
+
// The output path is part of what "unchanged" means here, not just the schema string — a
|
|
11
|
+
// RIME_CONFIG_DIR change can leave the schema content byte-identical while the file it needs
|
|
12
|
+
// to land at moves, and drizzle-kit still needs to re-run against the new location.
|
|
13
|
+
const cacheValue = `${outputFile}\n${schema}`;
|
|
9
14
|
const cachedSchema = cache.get('schema');
|
|
10
|
-
if (cachedSchema && cachedSchema ===
|
|
15
|
+
if (cachedSchema && cachedSchema === cacheValue) {
|
|
11
16
|
return;
|
|
12
17
|
}
|
|
13
|
-
const outputFile = schemaPath();
|
|
14
18
|
const outputDir = path.dirname(outputFile);
|
|
15
19
|
if (!fs.existsSync(outputDir)) {
|
|
16
20
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
@@ -45,6 +49,6 @@ const write = (schema) => {
|
|
|
45
49
|
// Only mark the schema as in sync once generate + migrate both actually
|
|
46
50
|
// succeeded — otherwise a future run with an unchanged schema string would
|
|
47
51
|
// skip re-running drizzle-kit and the DB would stay silently out of sync.
|
|
48
|
-
cache.set('schema',
|
|
52
|
+
cache.set('schema', cacheValue);
|
|
49
53
|
};
|
|
50
54
|
export default write;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AuthMiddleware } from 'better-auth/
|
|
1
|
+
import { type AuthMiddleware } from 'better-auth/api';
|
|
2
2
|
/****************************************************/
|
|
3
3
|
export declare const betterAuthBeforeHook: AuthMiddleware;
|
|
4
4
|
export declare const betterAuthAfterHook: AuthMiddleware;
|
|
@@ -4,8 +4,7 @@ import { BETTER_AUTH_ROLES } from '../../collections/auth/constant.server.js';
|
|
|
4
4
|
import { logger } from '../../logger/index.server.js';
|
|
5
5
|
import { trycatch } from '../../../util/function.js';
|
|
6
6
|
import { omit } from '../../../util/object.js';
|
|
7
|
-
import { APIError } from 'better-auth/api';
|
|
8
|
-
import { createAuthMiddleware } from 'better-auth/plugins';
|
|
7
|
+
import { APIError, createAuthMiddleware } from 'better-auth/api';
|
|
9
8
|
import { eq } from 'drizzle-orm';
|
|
10
9
|
/****************************************************/
|
|
11
10
|
/* After hooks
|
|
@@ -1,73 +1,33 @@
|
|
|
1
1
|
export declare const accessControl: {
|
|
2
|
-
newRole<
|
|
3
|
-
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update"];
|
|
2
|
+
newRole<const TRoleStatements extends import("better-auth/plugins").Statements>(statements: import("better-auth/plugins").RoleInput<{
|
|
3
|
+
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "impersonate-admins", "delete", "set-password", "set-email", "get", "update"];
|
|
4
4
|
readonly session: readonly ["list", "revoke", "delete"];
|
|
5
|
-
}>): {
|
|
6
|
-
|
|
7
|
-
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update"];
|
|
8
|
-
readonly session: readonly ["list", "revoke", "delete"];
|
|
9
|
-
}>[key] | {
|
|
10
|
-
actions: import("better-auth/plugins/access").Subset<K, {
|
|
11
|
-
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update"];
|
|
12
|
-
readonly session: readonly ["list", "revoke", "delete"];
|
|
13
|
-
}>[key];
|
|
14
|
-
connector: "OR" | "AND";
|
|
15
|
-
} | undefined; } : never, connector?: "OR" | "AND"): import("better-auth/plugins/access").AuthorizeResponse;
|
|
16
|
-
statements: import("better-auth/plugins/access").Subset<K, {
|
|
17
|
-
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update"];
|
|
18
|
-
readonly session: readonly ["list", "revoke", "delete"];
|
|
19
|
-
}>;
|
|
20
|
-
};
|
|
21
|
-
statements: {
|
|
22
|
-
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update"];
|
|
23
|
-
readonly session: readonly ["list", "revoke", "delete"];
|
|
24
|
-
};
|
|
25
|
-
};
|
|
26
|
-
export declare const admin: {
|
|
27
|
-
authorize<K_1 extends "user" | "session">(request: K_1 extends infer T extends K ? { [key in T]?: import("better-auth/plugins/access").Subset<"user" | "session", {
|
|
28
|
-
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update"];
|
|
29
|
-
readonly session: readonly ["list", "revoke", "delete"];
|
|
30
|
-
}>[key] | {
|
|
31
|
-
actions: import("better-auth/plugins/access").Subset<"user" | "session", {
|
|
32
|
-
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update"];
|
|
33
|
-
readonly session: readonly ["list", "revoke", "delete"];
|
|
34
|
-
}>[key];
|
|
35
|
-
connector: "OR" | "AND";
|
|
36
|
-
} | undefined; } : never, connector?: "OR" | "AND"): import("better-auth/plugins/access").AuthorizeResponse;
|
|
37
|
-
statements: import("better-auth/plugins/access").Subset<"user" | "session", {
|
|
38
|
-
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update"];
|
|
5
|
+
}, TRoleStatements>): import("better-auth/plugins").Role<import("better-auth/plugins").ExactRoleStatements<TRoleStatements>, {
|
|
6
|
+
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "impersonate-admins", "delete", "set-password", "set-email", "get", "update"];
|
|
39
7
|
readonly session: readonly ["list", "revoke", "delete"];
|
|
40
8
|
}>;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
authorize<K_1 extends "user">(request: K_1 extends infer T extends K ? { [key in T]?: import("better-auth/plugins/access").Subset<"user", {
|
|
44
|
-
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update"];
|
|
45
|
-
readonly session: readonly ["list", "revoke", "delete"];
|
|
46
|
-
}>[key] | {
|
|
47
|
-
actions: import("better-auth/plugins/access").Subset<"user", {
|
|
48
|
-
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update"];
|
|
49
|
-
readonly session: readonly ["list", "revoke", "delete"];
|
|
50
|
-
}>[key];
|
|
51
|
-
connector: "OR" | "AND";
|
|
52
|
-
} | undefined; } : never, connector?: "OR" | "AND"): import("better-auth/plugins/access").AuthorizeResponse;
|
|
53
|
-
statements: import("better-auth/plugins/access").Subset<"user", {
|
|
54
|
-
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update"];
|
|
55
|
-
readonly session: readonly ["list", "revoke", "delete"];
|
|
56
|
-
}>;
|
|
57
|
-
};
|
|
58
|
-
export declare const user: {
|
|
59
|
-
authorize<K_1 extends "user" | "session">(request: K_1 extends infer T extends K ? { [key in T]?: import("better-auth/plugins/access").Subset<"user" | "session", {
|
|
60
|
-
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update"];
|
|
61
|
-
readonly session: readonly ["list", "revoke", "delete"];
|
|
62
|
-
}>[key] | {
|
|
63
|
-
actions: import("better-auth/plugins/access").Subset<"user" | "session", {
|
|
64
|
-
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update"];
|
|
65
|
-
readonly session: readonly ["list", "revoke", "delete"];
|
|
66
|
-
}>[key];
|
|
67
|
-
connector: "OR" | "AND";
|
|
68
|
-
} | undefined; } : never, connector?: "OR" | "AND"): import("better-auth/plugins/access").AuthorizeResponse;
|
|
69
|
-
statements: import("better-auth/plugins/access").Subset<"user" | "session", {
|
|
70
|
-
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update"];
|
|
9
|
+
statements: {
|
|
10
|
+
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "impersonate-admins", "delete", "set-password", "set-email", "get", "update"];
|
|
71
11
|
readonly session: readonly ["list", "revoke", "delete"];
|
|
72
|
-
}
|
|
12
|
+
};
|
|
73
13
|
};
|
|
14
|
+
export declare const admin: import("better-auth/plugins").Role<import("better-auth/plugins").ExactRoleStatements<import("better-auth/plugins").ExactRoleStatements<{
|
|
15
|
+
readonly user: ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "set-email", "get", "update"];
|
|
16
|
+
readonly session: ["list", "revoke", "delete"];
|
|
17
|
+
}>>, {
|
|
18
|
+
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "impersonate-admins", "delete", "set-password", "set-email", "get", "update"];
|
|
19
|
+
readonly session: readonly ["list", "revoke", "delete"];
|
|
20
|
+
}>;
|
|
21
|
+
export declare const staff: import("better-auth/plugins").Role<import("better-auth/plugins").ExactRoleStatements<{
|
|
22
|
+
readonly user: ["create", "list", "delete"];
|
|
23
|
+
}>, {
|
|
24
|
+
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "impersonate-admins", "delete", "set-password", "set-email", "get", "update"];
|
|
25
|
+
readonly session: readonly ["list", "revoke", "delete"];
|
|
26
|
+
}>;
|
|
27
|
+
export declare const user: import("better-auth/plugins").Role<import("better-auth/plugins").ExactRoleStatements<import("better-auth/plugins").ExactRoleStatements<{
|
|
28
|
+
readonly user: [];
|
|
29
|
+
readonly session: [];
|
|
30
|
+
}>>, {
|
|
31
|
+
readonly user: readonly ["create", "list", "set-role", "ban", "impersonate", "impersonate-admins", "delete", "set-password", "set-email", "get", "update"];
|
|
32
|
+
readonly session: readonly ["list", "revoke", "delete"];
|
|
33
|
+
}>;
|