rimecms 0.31.3 → 0.31.5
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/adapter-sqlite/transform.server.js +1 -1
- package/dist/core/collections/upload/util/path.d.ts +2 -1
- package/dist/core/collections/upload/util/path.js +3 -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/constant.d.ts +10 -0
- package/dist/core/constant.js +22 -0
- package/dist/core/dev/cli/build/templates.js +2 -0
- package/dist/core/dev/cli/clear/index.server.js +5 -5
- package/dist/core/dev/cli/init/index.server.js +15 -28
- package/dist/core/dev/cli/init/templates.d.ts +14 -0
- package/dist/core/dev/cli/init/templates.js +58 -3
- package/dist/core/dev/constants.d.ts +20 -7
- package/dist/core/dev/constants.js +58 -10
- package/dist/core/dev/generate/routes/common.server.js +36 -33
- package/dist/core/dev/generate/routes/index.server.d.ts +6 -3
- package/dist/core/dev/generate/routes/index.server.js +13 -7
- package/dist/core/dev/generate/routes/util.server.d.ts +14 -6
- package/dist/core/dev/generate/routes/util.server.js +17 -6
- 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 +18 -11
- package/dist/core/handlers/routes.server.d.ts +1 -1
- package/dist/core/handlers/routes.server.js +4 -3
- package/dist/core/operations/hooks/before-read/populate-url.server.js +2 -1
- package/dist/core/plugins/cache/handler.server.js +1 -1
- 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/collection/list/row/Row.svelte +2 -1
- package/dist/panel/components/sections/collection/tree/CollectionTreeNode.svelte +2 -1
- package/dist/panel/components/sections/document/AuthAPIKeyDialog.svelte.d.ts +3 -3
- package/dist/panel/components/sections/document/AuthFooter.svelte +2 -1
- package/dist/panel/components/sections/document/Versions.svelte +1 -1
- 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/card-resource/card-resource.svelte +2 -1
- 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/nav/Nav.svelte +1 -1
- package/dist/panel/components/ui/nav/NavItem.svelte +3 -2
- package/dist/panel/components/ui/nav/UserButton.svelte +3 -3
- 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/context/documentForm.svelte.js +5 -6
- package/dist/panel/navigation.d.ts +7 -2
- package/dist/panel/navigation.js +11 -6
- package/dist/panel/pages/area/actions.server.js +4 -3
- package/dist/panel/pages/area/load.server.js +3 -2
- package/dist/panel/pages/auth/forgot-password/ForgotPassword.svelte +2 -1
- package/dist/panel/pages/auth/reset-password/ResetPassword.svelte +2 -1
- package/dist/panel/pages/auth/sign-in/SignIn.svelte +3 -2
- package/dist/panel/pages/auth/sign-in/actions.server.js +2 -2
- package/dist/panel/pages/auth/sign-in/load.server.d.ts +1 -1
- package/dist/panel/pages/auth/sign-in/load.server.js +2 -2
- package/dist/panel/pages/collection/load.server.js +9 -4
- package/dist/panel/pages/collection-document/actions.server.js +5 -3
- package/dist/panel/pages/collection-document/load.server.js +10 -6
- package/dist/panel/pages/dashboard/load.server.js +5 -4
- package/dist/panel/pages/live/Live.svelte +3 -7
- package/dist/panel/style/index.css +0 -6
- package/dist/panel/util/auth.js +1 -1
- package/dist/panel/util/url.d.ts +30 -1
- package/dist/panel/util/url.js +36 -2
- package/package.json +8 -6
- package/dist/panel/components/ui/dropdown-menu/index.d.ts +0 -23
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { PACKAGE_NAME } from '../../../constant.server.js';
|
|
2
|
+
import path from 'node:path';
|
|
2
3
|
import { configImportPaths } from '../../constants.js';
|
|
4
|
+
const PANEL_LAYOUT_DIR = path.resolve(process.cwd(), 'src/routes/(rime)/[panel=panel]');
|
|
5
|
+
const LIVE_PAGE_DIR = path.resolve(process.cwd(), 'src/routes/(rime)/[panel=panel]/live-edit');
|
|
3
6
|
/**
|
|
4
7
|
* Main base layout
|
|
5
8
|
* /+layout.server.ts
|
|
@@ -79,7 +82,7 @@ export const load = async ({ locals }: ServerLoadEvent) => {
|
|
|
79
82
|
};`;
|
|
80
83
|
/**
|
|
81
84
|
* Login page template
|
|
82
|
-
* (rime)/panel/sign-in/+page.svelte
|
|
85
|
+
* (rime)/[panel=panel]/sign-in/+page.svelte
|
|
83
86
|
*/
|
|
84
87
|
const signInPage = () => `
|
|
85
88
|
<script>
|
|
@@ -102,7 +105,7 @@ export const actions = {
|
|
|
102
105
|
`;
|
|
103
106
|
/**
|
|
104
107
|
* Forgot password page template
|
|
105
|
-
* (rime)/forgot-password/+page.svelte
|
|
108
|
+
* (rime)/[panel=panel]/forgot-password/+page.svelte
|
|
106
109
|
*/
|
|
107
110
|
const forgotPasswordPage = () => `
|
|
108
111
|
<script>
|
|
@@ -112,7 +115,7 @@ const forgotPasswordPage = () => `
|
|
|
112
115
|
<ForgotPassword {data} />`;
|
|
113
116
|
/**
|
|
114
117
|
* Forgot password page server template
|
|
115
|
-
* (rime)/forgot-password/+page.server.ts
|
|
118
|
+
* (rime)/[panel=panel]/forgot-password/+page.server.ts
|
|
116
119
|
*/
|
|
117
120
|
const forgotPasswordPageServer = () => `
|
|
118
121
|
import { type ServerLoadEvent } from '@sveltejs/kit';
|
|
@@ -121,7 +124,7 @@ export const load = (event: ServerLoadEvent) => event.locals.routes.panel.load.f
|
|
|
121
124
|
`;
|
|
122
125
|
/**
|
|
123
126
|
* Reset password page template
|
|
124
|
-
* (rime)/reset-password/+page.svelte
|
|
127
|
+
* (rime)/[panel=panel]/reset-password/+page.svelte
|
|
125
128
|
*/
|
|
126
129
|
const resetPasswordPage = () => `
|
|
127
130
|
<script>
|
|
@@ -132,7 +135,7 @@ const resetPasswordPage = () => `
|
|
|
132
135
|
<ResetPassword {data} />`;
|
|
133
136
|
/**
|
|
134
137
|
* Reset password page server template
|
|
135
|
-
* (rime)/reset-password/+page.server.ts
|
|
138
|
+
* (rime)/[panel=panel]/reset-password/+page.server.ts
|
|
136
139
|
*/
|
|
137
140
|
const resetPasswordPageServer = () => `
|
|
138
141
|
import { type ServerLoadEvent } from '@sveltejs/kit';
|
|
@@ -141,12 +144,12 @@ export const load = (event: ServerLoadEvent) => event.locals.routes.panel.load.r
|
|
|
141
144
|
`;
|
|
142
145
|
/**
|
|
143
146
|
* Panel layout template
|
|
144
|
-
* (rime)/panel/+layout.svelte
|
|
147
|
+
* (rime)/[panel=panel]/+layout.svelte
|
|
145
148
|
*/
|
|
146
149
|
const panelLayout = () => `
|
|
147
150
|
<script>
|
|
148
151
|
import { Panel } from '${PACKAGE_NAME}/panel';
|
|
149
|
-
import config from '${configImportPaths().client}';
|
|
152
|
+
import config from '${configImportPaths(PANEL_LAYOUT_DIR).client}';
|
|
150
153
|
|
|
151
154
|
const { children, data } = $props();
|
|
152
155
|
|
|
@@ -161,7 +164,7 @@ const panelLayout = () => `
|
|
|
161
164
|
</Panel>`;
|
|
162
165
|
/**
|
|
163
166
|
* Panel layout server template
|
|
164
|
-
* (rime)/panel/+layout.server.ts
|
|
167
|
+
* (rime)/[panel=panel]/+layout.server.ts
|
|
165
168
|
*/
|
|
166
169
|
const panelLayoutServer = () => `
|
|
167
170
|
import { type ServerLoadEvent } from '@sveltejs/kit';
|
|
@@ -172,7 +175,7 @@ export const load = async ({ locals }: ServerLoadEvent) => {
|
|
|
172
175
|
};`;
|
|
173
176
|
/**
|
|
174
177
|
* Panel page template
|
|
175
|
-
* (rime)/panel/+page.svelte
|
|
178
|
+
* (rime)/[panel=panel]/+page.svelte
|
|
176
179
|
*/
|
|
177
180
|
const panelPage = () => `
|
|
178
181
|
<script>
|
|
@@ -183,7 +186,7 @@ const panelPage = () => `
|
|
|
183
186
|
<Dashboard entries={data.entries} user={data.user} />`;
|
|
184
187
|
/**
|
|
185
188
|
* Panel page load template
|
|
186
|
-
* (rime)/panel/+page.server.ts
|
|
189
|
+
* (rime)/[panel=panel]/+page.server.ts
|
|
187
190
|
*/
|
|
188
191
|
const panelPageServer = () => `
|
|
189
192
|
import { type ServerLoadEvent } from '@sveltejs/kit';
|
|
@@ -196,7 +199,7 @@ export const load = (event: ServerLoadEvent) => event.locals.routes.panel.load.d
|
|
|
196
199
|
const livePage = () => `
|
|
197
200
|
<script>
|
|
198
201
|
import { Live } from '${PACKAGE_NAME}/panel';
|
|
199
|
-
import config from '${configImportPaths().client}';
|
|
202
|
+
import config from '${configImportPaths(LIVE_PAGE_DIR).client}';
|
|
200
203
|
|
|
201
204
|
const { data } = $props();
|
|
202
205
|
</script>
|
|
@@ -226,7 +229,7 @@ export const load = (event: ServerLoadEvent) => event.locals.routes.panel.load.l
|
|
|
226
229
|
/****************************************************/
|
|
227
230
|
/**
|
|
228
231
|
* Collection list page
|
|
229
|
-
* (rime)/panel/[slug=collection]/+page.svelte
|
|
232
|
+
* (rime)/[panel=panel]/[slug=collection]/+page.svelte
|
|
230
233
|
*/
|
|
231
234
|
const collectionListPage = () => `
|
|
232
235
|
<script>
|
|
@@ -236,7 +239,7 @@ const collectionListPage = () => `
|
|
|
236
239
|
|
|
237
240
|
<Collection {data} slug={data.slug} />`;
|
|
238
241
|
/**
|
|
239
|
-
* (rime)/panel/[slug=collection]/+page.server.ts
|
|
242
|
+
* (rime)/[panel=panel]/[slug=collection]/+page.server.ts
|
|
240
243
|
*/
|
|
241
244
|
const collectionListPageServer = () => `
|
|
242
245
|
import { type ServerLoadEvent } from '@sveltejs/kit';
|
|
@@ -247,7 +250,7 @@ export const load = async (event: ServerLoadEvent) => {
|
|
|
247
250
|
};`;
|
|
248
251
|
/**
|
|
249
252
|
* Area document page
|
|
250
|
-
* (rime)/panel/[slug=area]/+page.svelte
|
|
253
|
+
* (rime)/[panel=panel]/[slug=area]/+page.svelte
|
|
251
254
|
*/
|
|
252
255
|
const areaDocPage = () => `
|
|
253
256
|
<script>
|
|
@@ -257,7 +260,7 @@ const areaDocPage = () => `
|
|
|
257
260
|
|
|
258
261
|
<Area {data} />`;
|
|
259
262
|
/**
|
|
260
|
-
* (rime)/panel/[slug=area]/+page.server.ts
|
|
263
|
+
* (rime)/[panel=panel]/[slug=area]/+page.server.ts
|
|
261
264
|
*/
|
|
262
265
|
const areaDocPageServer = () => `
|
|
263
266
|
import type { RequestEvent, ServerLoadEvent } from '@sveltejs/kit';
|
|
@@ -269,7 +272,7 @@ export const actions = {
|
|
|
269
272
|
};`;
|
|
270
273
|
/**
|
|
271
274
|
* Collection document page
|
|
272
|
-
* (rime)/panel/[slug=collection]/[id]/+page.svelte
|
|
275
|
+
* (rime)/[panel=panel]/[slug=collection]/[id]/+page.svelte
|
|
273
276
|
*/
|
|
274
277
|
const collectionDocPage = () => `
|
|
275
278
|
<script>
|
|
@@ -279,7 +282,7 @@ const collectionDocPage = () => `
|
|
|
279
282
|
|
|
280
283
|
<CollectionDoc {data} />`;
|
|
281
284
|
/**
|
|
282
|
-
* (rime)/panel/[slug=collection]/[id]/+page.server.ts
|
|
285
|
+
* (rime)/[panel=panel]/[slug=collection]/[id]/+page.server.ts
|
|
283
286
|
*/
|
|
284
287
|
const collectionDocPageServer = () => `
|
|
285
288
|
import type { RequestEvent, ServerLoadEvent } from '@sveltejs/kit';
|
|
@@ -292,7 +295,7 @@ export const actions = {
|
|
|
292
295
|
};`;
|
|
293
296
|
/**
|
|
294
297
|
* Collection document versions page
|
|
295
|
-
* (rime)/panel/[slug=collection]/[id]/versions/+page.svelte
|
|
298
|
+
* (rime)/[panel=panel]/[slug=collection]/[id]/versions/+page.svelte
|
|
296
299
|
*/
|
|
297
300
|
const collectionDocVersionsPage = () => `
|
|
298
301
|
<script>
|
|
@@ -302,7 +305,7 @@ const collectionDocVersionsPage = () => `
|
|
|
302
305
|
|
|
303
306
|
<CollectionDocVersions data={data} />`;
|
|
304
307
|
/**
|
|
305
|
-
* (rime)/panel/[slug=collection]/[id]/versions/+page.server.ts
|
|
308
|
+
* (rime)/[panel=panel]/[slug=collection]/[id]/versions/+page.server.ts
|
|
306
309
|
*/
|
|
307
310
|
const collectionDocVersionsPageServer = () => `
|
|
308
311
|
import { type ServerLoadEvent } from '@sveltejs/kit';
|
|
@@ -311,7 +314,7 @@ export const load = (event: ServerLoadEvent) =>
|
|
|
311
314
|
event.locals.routes.panel.load.documentVersions(event);`;
|
|
312
315
|
/**
|
|
313
316
|
* Area document versions page
|
|
314
|
-
* (rime)/panel/[slug=area]/versions/+page.svelte
|
|
317
|
+
* (rime)/[panel=panel]/[slug=area]/versions/+page.svelte
|
|
315
318
|
*/
|
|
316
319
|
const areaVersionsPage = () => `
|
|
317
320
|
<script>
|
|
@@ -321,7 +324,7 @@ const areaVersionsPage = () => `
|
|
|
321
324
|
|
|
322
325
|
<AreaVersionsDoc data={data} />`;
|
|
323
326
|
/**
|
|
324
|
-
* (rime)/panel/[slug=area]/versions/+page.server.ts
|
|
327
|
+
* (rime)/[panel=panel]/[slug=area]/versions/+page.server.ts
|
|
325
328
|
*/
|
|
326
329
|
const areaVersionsPageServer = () => `
|
|
327
330
|
import { type ServerLoadEvent } from '@sveltejs/kit';
|
|
@@ -436,45 +439,45 @@ export const commonRoutes = {
|
|
|
436
439
|
layoutServer: rootLayoutServer,
|
|
437
440
|
error: error
|
|
438
441
|
},
|
|
439
|
-
'(rime)/panel/sign-in': {
|
|
442
|
+
'(rime)/[panel=panel]/sign-in': {
|
|
440
443
|
'page@(rime)': signInPage,
|
|
441
444
|
pageServer: signInPageServer
|
|
442
445
|
},
|
|
443
|
-
'(rime)/forgot-password': {
|
|
444
|
-
page: forgotPasswordPage,
|
|
446
|
+
'(rime)/[panel=panel]/forgot-password': {
|
|
447
|
+
'page@(rime)': forgotPasswordPage,
|
|
445
448
|
pageServer: forgotPasswordPageServer
|
|
446
449
|
},
|
|
447
|
-
'(rime)/reset-password': {
|
|
448
|
-
page: resetPasswordPage,
|
|
450
|
+
'(rime)/[panel=panel]/reset-password': {
|
|
451
|
+
'page@(rime)': resetPasswordPage,
|
|
449
452
|
pageServer: resetPasswordPageServer
|
|
450
453
|
},
|
|
451
|
-
'(rime)/panel': {
|
|
454
|
+
'(rime)/[panel=panel]': {
|
|
452
455
|
layout: panelLayout,
|
|
453
456
|
layoutServer: panelLayoutServer,
|
|
454
457
|
page: panelPage,
|
|
455
458
|
pageServer: panelPageServer
|
|
456
459
|
},
|
|
457
|
-
'(rime)/panel/live-edit': {
|
|
460
|
+
'(rime)/[panel=panel]/live-edit': {
|
|
458
461
|
'page@(rime)': livePage,
|
|
459
462
|
pageServer: livePageServer
|
|
460
463
|
},
|
|
461
|
-
'(rime)/panel/[slug=collection]': {
|
|
464
|
+
'(rime)/[panel=panel]/[slug=collection]': {
|
|
462
465
|
page: collectionListPage,
|
|
463
466
|
pageServer: collectionListPageServer
|
|
464
467
|
},
|
|
465
|
-
'(rime)/panel/[slug=collection]/[id]': {
|
|
468
|
+
'(rime)/[panel=panel]/[slug=collection]/[id]': {
|
|
466
469
|
page: collectionDocPage,
|
|
467
470
|
pageServer: collectionDocPageServer
|
|
468
471
|
},
|
|
469
|
-
'(rime)/panel/[slug=collection]/[id]/versions': {
|
|
472
|
+
'(rime)/[panel=panel]/[slug=collection]/[id]/versions': {
|
|
470
473
|
page: collectionDocVersionsPage,
|
|
471
474
|
pageServer: collectionDocVersionsPageServer
|
|
472
475
|
},
|
|
473
|
-
'(rime)/panel/[slug=area]': {
|
|
476
|
+
'(rime)/[panel=panel]/[slug=area]': {
|
|
474
477
|
page: areaDocPage,
|
|
475
478
|
pageServer: areaDocPageServer
|
|
476
479
|
},
|
|
477
|
-
'(rime)/panel/[slug=area]/versions': {
|
|
480
|
+
'(rime)/[panel=panel]/[slug=area]/versions': {
|
|
478
481
|
page: areaVersionsPage,
|
|
479
482
|
pageServer: areaVersionsPageServer
|
|
480
483
|
},
|
|
@@ -2,11 +2,14 @@ import type { Config } from '../../../../types.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Main function to generate browser routes based on configuration.
|
|
4
4
|
* commonRoutes is a fixed set of files (layout, sign-in, dashboard, the
|
|
5
|
-
* matcher-disambiguated
|
|
5
|
+
* matcher-disambiguated [panel=panel]/[slug=collection|area]/... and
|
|
6
6
|
* /api/[slug=collection|area]/... dynamic routes) — it no longer varies with
|
|
7
7
|
* how many collections/areas are configured, so there's no per-collection/area
|
|
8
|
-
* loop here anymore. The
|
|
9
|
-
*
|
|
8
|
+
* loop here anymore. The folder is always the literal `[panel=panel]` segment;
|
|
9
|
+
* only src/params/panel.ts's matcher content varies with RIME_PANEL_ROUTE, so
|
|
10
|
+
* the URL itself can be hidden from admin-path scanners without ever renaming
|
|
11
|
+
* a directory. Same idea backs src/params/collection.ts and area.ts, which
|
|
12
|
+
* bake in the actual slug list — all three are rewritten here.
|
|
10
13
|
*/
|
|
11
14
|
declare function generateRoutes<T extends Config>(config: T): void;
|
|
12
15
|
export default generateRoutes;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PANEL_ROUTE } from '../../constants.js';
|
|
1
2
|
import { logger } from '../../../logger/index.server.js';
|
|
2
3
|
import fs from 'fs';
|
|
3
4
|
import path from 'path';
|
|
@@ -8,11 +9,14 @@ const projectRoot = process.cwd();
|
|
|
8
9
|
/**
|
|
9
10
|
* Main function to generate browser routes based on configuration.
|
|
10
11
|
* commonRoutes is a fixed set of files (layout, sign-in, dashboard, the
|
|
11
|
-
* matcher-disambiguated
|
|
12
|
+
* matcher-disambiguated [panel=panel]/[slug=collection|area]/... and
|
|
12
13
|
* /api/[slug=collection|area]/... dynamic routes) — it no longer varies with
|
|
13
14
|
* how many collections/areas are configured, so there's no per-collection/area
|
|
14
|
-
* loop here anymore. The
|
|
15
|
-
*
|
|
15
|
+
* loop here anymore. The folder is always the literal `[panel=panel]` segment;
|
|
16
|
+
* only src/params/panel.ts's matcher content varies with RIME_PANEL_ROUTE, so
|
|
17
|
+
* the URL itself can be hidden from admin-path scanners without ever renaming
|
|
18
|
+
* a directory. Same idea backs src/params/collection.ts and area.ts, which
|
|
19
|
+
* bake in the actual slug list — all three are rewritten here.
|
|
16
20
|
*/
|
|
17
21
|
function generateRoutes(config) {
|
|
18
22
|
logger.info('Routes generation...');
|
|
@@ -23,7 +27,7 @@ function generateRoutes(config) {
|
|
|
23
27
|
// 2. Ensure base directories exist
|
|
24
28
|
const rootRoutes = path.resolve(projectRoot, 'src', 'routes');
|
|
25
29
|
const rimeRoutes = path.join(rootRoutes, '(rime)');
|
|
26
|
-
const panelRoute = path.join(rimeRoutes, 'panel');
|
|
30
|
+
const panelRoute = path.join(rimeRoutes, '[panel=panel]');
|
|
27
31
|
const paramsDir = path.resolve(projectRoot, 'src', 'params');
|
|
28
32
|
fs.rmSync(rimeRoutes, { recursive: true, force: true });
|
|
29
33
|
ensureDir(rootRoutes);
|
|
@@ -44,8 +48,10 @@ function generateRoutes(config) {
|
|
|
44
48
|
writeRouteFile(rootRoutes, pattern, fileType, templateFn());
|
|
45
49
|
}
|
|
46
50
|
}
|
|
47
|
-
// 4. Write the [
|
|
48
|
-
//
|
|
51
|
+
// 4. Write the [panel=panel] param matcher — always present, unlike collection/area — plus
|
|
52
|
+
// the [slug=collection]/[slug=area] matchers, only when needed, removing any stale matcher
|
|
53
|
+
// left over from a previous config that did have collections/areas.
|
|
54
|
+
fs.writeFileSync(path.join(paramsDir, 'panel.ts'), paramMatcher([PANEL_ROUTE]));
|
|
49
55
|
const collectionMatcherPath = path.join(paramsDir, 'collection.ts');
|
|
50
56
|
if (hasCollections) {
|
|
51
57
|
fs.writeFileSync(collectionMatcherPath, paramMatcher((config.collections || []).map((c) => c.kebab)));
|
|
@@ -64,7 +70,7 @@ function generateRoutes(config) {
|
|
|
64
70
|
const customRoutes = config.panel?.routes;
|
|
65
71
|
if (customRoutes) {
|
|
66
72
|
for (const [route, routeConfig] of Object.entries(customRoutes)) {
|
|
67
|
-
const routePath = path.join('(rime)', 'panel', route);
|
|
73
|
+
const routePath = path.join('(rime)', '[panel=panel]', route);
|
|
68
74
|
writeRouteFile(rootRoutes, routePath, 'page', customRoute(routeConfig));
|
|
69
75
|
}
|
|
70
76
|
}
|
|
@@ -8,10 +8,18 @@ export type Routes = Record<string, RouteDefinition>;
|
|
|
8
8
|
/**
|
|
9
9
|
* Check if routes need to be regenerated based on config changes.
|
|
10
10
|
* Panel/API routes are a fixed set of dynamic-segment files (file count never
|
|
11
|
-
* grows with schema size), but the [slug=collection]/[slug=area]
|
|
12
|
-
* matchers under src/params/ bake in the actual
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* grows with schema size), but the [panel=panel]/[slug=collection]/[slug=area]
|
|
12
|
+
* param matchers under src/params/ bake in the actual accepted value(s), so
|
|
13
|
+
* changing RIME_PANEL_ROUTE or RIME_CONFIG_DIR, or adding/removing/renaming a
|
|
14
|
+
* collection/area, still needs a regen to keep those matchers in sync — same
|
|
15
|
+
* trigger as custom routes and panel CSS. Both PANEL_ROUTE and CONFIG_DIR must
|
|
16
|
+
* stay in this memo: they're read once at process start, so a changed value
|
|
17
|
+
* only takes effect after a restart, and only if the restart's regen actually
|
|
18
|
+
* notices the change. CONFIG_DIR specifically is baked into the panel/live
|
|
19
|
+
* layout's config import path (see configImportPaths() calls in
|
|
20
|
+
* common.server.ts) — leaving it out would silently keep that import stale
|
|
21
|
+
* instead of erroring, the same failure mode RIME_CONFIG_DIR hit once for
|
|
22
|
+
* hooks.server.ts (see regenerateHooks() in cli/init/templates.ts).
|
|
15
23
|
* @returns true if routes should be regenerated, false otherwise
|
|
16
24
|
*/
|
|
17
25
|
export declare function shouldRegenerateRoutes<T extends Config>(config: T): boolean;
|
|
@@ -33,10 +41,10 @@ export declare function ensureDir(dirPath: string): void;
|
|
|
33
41
|
* @example
|
|
34
42
|
* // Write a page file for a collection
|
|
35
43
|
* const basePath = '/path/to/src/routes';
|
|
36
|
-
* const routePath = '(rime)/panel/news';
|
|
44
|
+
* const routePath = '(rime)/[panel=panel]/news';
|
|
37
45
|
* const fileType = 'page';
|
|
38
46
|
* const content = '<script>\n import { Collection } from "rime/panel"\n</script>...';
|
|
39
47
|
* writeRouteFile(basePath, routePath, fileType, content);
|
|
40
|
-
* // Creates /path/to/src/routes/(rime)/panel/news/+page.svelte with the provided content
|
|
48
|
+
* // Creates /path/to/src/routes/(rime)/[panel=panel]/news/+page.svelte with the provided content
|
|
41
49
|
*/
|
|
42
50
|
export declare function writeRouteFile(basePath: string, routePath: string, fileType: string, content: string): void;
|
|
@@ -1,18 +1,29 @@
|
|
|
1
1
|
import cache from '../../cache/index.server.js';
|
|
2
|
+
import { CONFIG_DIR, PANEL_ROUTE } from '../../constants.js';
|
|
2
3
|
import { slugify } from '../../../../util/string.js';
|
|
3
4
|
import fs from 'fs';
|
|
4
5
|
import path from 'path';
|
|
5
6
|
/**
|
|
6
7
|
* Check if routes need to be regenerated based on config changes.
|
|
7
8
|
* Panel/API routes are a fixed set of dynamic-segment files (file count never
|
|
8
|
-
* grows with schema size), but the [slug=collection]/[slug=area]
|
|
9
|
-
* matchers under src/params/ bake in the actual
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* grows with schema size), but the [panel=panel]/[slug=collection]/[slug=area]
|
|
10
|
+
* param matchers under src/params/ bake in the actual accepted value(s), so
|
|
11
|
+
* changing RIME_PANEL_ROUTE or RIME_CONFIG_DIR, or adding/removing/renaming a
|
|
12
|
+
* collection/area, still needs a regen to keep those matchers in sync — same
|
|
13
|
+
* trigger as custom routes and panel CSS. Both PANEL_ROUTE and CONFIG_DIR must
|
|
14
|
+
* stay in this memo: they're read once at process start, so a changed value
|
|
15
|
+
* only takes effect after a restart, and only if the restart's regen actually
|
|
16
|
+
* notices the change. CONFIG_DIR specifically is baked into the panel/live
|
|
17
|
+
* layout's config import path (see configImportPaths() calls in
|
|
18
|
+
* common.server.ts) — leaving it out would silently keep that import stale
|
|
19
|
+
* instead of erroring, the same failure mode RIME_CONFIG_DIR hit once for
|
|
20
|
+
* hooks.server.ts (see regenerateHooks() in cli/init/templates.ts).
|
|
12
21
|
* @returns true if routes should be regenerated, false otherwise
|
|
13
22
|
*/
|
|
14
23
|
export function shouldRegenerateRoutes(config) {
|
|
15
24
|
const memo = `
|
|
25
|
+
panel:${PANEL_ROUTE}
|
|
26
|
+
config:${CONFIG_DIR}
|
|
16
27
|
custom:${config.panel?.routes
|
|
17
28
|
? Object.entries(config.panel.routes)
|
|
18
29
|
.map(([k, v]) => `${k}-${slugify(v.component.toString())}`)
|
|
@@ -51,11 +62,11 @@ export function ensureDir(dirPath) {
|
|
|
51
62
|
* @example
|
|
52
63
|
* // Write a page file for a collection
|
|
53
64
|
* const basePath = '/path/to/src/routes';
|
|
54
|
-
* const routePath = '(rime)/panel/news';
|
|
65
|
+
* const routePath = '(rime)/[panel=panel]/news';
|
|
55
66
|
* const fileType = 'page';
|
|
56
67
|
* const content = '<script>\n import { Collection } from "rime/panel"\n</script>...';
|
|
57
68
|
* writeRouteFile(basePath, routePath, fileType, content);
|
|
58
|
-
* // Creates /path/to/src/routes/(rime)/panel/news/+page.svelte with the provided content
|
|
69
|
+
* // Creates /path/to/src/routes/(rime)/[panel=panel]/news/+page.svelte with the provided content
|
|
59
70
|
*/
|
|
60
71
|
export function writeRouteFile(basePath, routePath, fileType, content) {
|
|
61
72
|
const dir = path.join(basePath, routePath);
|
|
@@ -5,7 +5,7 @@ import { babelParse } from 'ast-kit';
|
|
|
5
5
|
import fs from 'node:fs';
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
import { logger } from '../../../logger/index.server.js';
|
|
8
|
-
import {
|
|
8
|
+
import { CONFIG_DIR, GENERATED_DIR, OUTPUT_DIR } from '../../constants.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* $ prefix-based sanitizer that rules:
|
|
@@ -22,8 +22,8 @@ const TOP_LEVEL_CONFIG = 'rime.config.server.ts';
|
|
|
22
22
|
|
|
23
23
|
export async function sanitize() {
|
|
24
24
|
const root = process.cwd();
|
|
25
|
-
const configDir = path.resolve(root,
|
|
26
|
-
const outputDir = path.resolve(root,
|
|
25
|
+
const configDir = path.resolve(root, CONFIG_DIR);
|
|
26
|
+
const outputDir = path.resolve(root, GENERATED_DIR);
|
|
27
27
|
|
|
28
28
|
logger.info('Sanitizing config...');
|
|
29
29
|
|
|
@@ -12,7 +12,7 @@ import { trycatchSync } from '../../../../util/function.js';
|
|
|
12
12
|
import { capitalize, toPascalCase } from '../../../../util/string.js';
|
|
13
13
|
import fs from 'node:fs';
|
|
14
14
|
import path from 'node:path';
|
|
15
|
-
import { isInstalledDependency,
|
|
15
|
+
import { GENERATED_DIR, isInstalledDependency, relativeImportSpecifier } from '../../constants.js';
|
|
16
16
|
const IS_RIME_REPO = !isInstalledDependency(import.meta.url);
|
|
17
17
|
// Relation type
|
|
18
18
|
const relationValueType = `
|
|
@@ -259,7 +259,8 @@ export async function generateTypesString(config) {
|
|
|
259
259
|
const blocksTypeNames = `export type BlockTypes = ${registeredBlocks.map((name) => `'${name}'`).join('|')}\n`;
|
|
260
260
|
const anyBlock = `export type AnyBlock = ${registeredBlocks.map((name) => `Block${toPascalCase(name)}`).join('|')}\n`;
|
|
261
261
|
const typeImports = `import type { ${Array.from(imports).join(', ')} } from '${PACKAGE_NAME}/types'`;
|
|
262
|
-
|
|
262
|
+
// app.generated.d.ts always sits at src/app.generated.d.ts (see generateTypes() below).
|
|
263
|
+
const rimeConfigServerPath = relativeImportSpecifier(path.resolve(process.cwd(), 'src'), path.resolve(process.cwd(), GENERATED_DIR, 'rime.config.server.ts'));
|
|
263
264
|
const locals = `declare global {
|
|
264
265
|
namespace App {
|
|
265
266
|
interface Locals {
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import dotenv from 'dotenv';
|
|
2
1
|
import { existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
2
|
import path from 'node:path';
|
|
4
3
|
import { RIME_DEV_CACHE_DIR } from '../../constant.server.js';
|
|
5
4
|
import { ensureHasInit } from '../../ensure.server.js';
|
|
6
5
|
import { logger } from '../../logger/index.server.js';
|
|
7
6
|
import { getPackageInfoByKey } from '../cli/util/package.server.js';
|
|
8
|
-
import {
|
|
7
|
+
import { CONFIG_DIR, GENERATED_DIR, generatedConfigServerPath, isInstalledDependency, schemaPath } from '../constants.js';
|
|
9
8
|
import { findInstalledPackageRoot, findModulePair, scanModulePairs } from '../generate/runtime/index.server.js';
|
|
10
9
|
import { parseExportNames } from '../generate/runtime/parse-exports.server.js';
|
|
11
10
|
import { sanitize } from '../generate/sanitize/index.server.js';
|
|
12
|
-
dotenv.config({ override: true });
|
|
13
11
|
const dev = process.env.NODE_ENV === 'development';
|
|
14
12
|
/** Picks the client or server side of a module.(server.)ts pair. When the requested side
|
|
15
13
|
* wasn't authored (e.g. a collection's $url/$hooks, real only server-side, imported anyway by
|
|
@@ -132,9 +130,8 @@ export function rime() {
|
|
|
132
130
|
try {
|
|
133
131
|
// ssrLoadModule wants the real .ts file path, not a $lib/*.js-style import
|
|
134
132
|
// specifier — different consumer than configImportPaths() (used for generated
|
|
135
|
-
// source code)
|
|
136
|
-
const
|
|
137
|
-
const mod = await server.ssrLoadModule(serverConfigPath);
|
|
133
|
+
// source code).
|
|
134
|
+
const mod = await server.ssrLoadModule(generatedConfigServerPath());
|
|
138
135
|
// The config's default export is the createRime() promise; ssrLoadModule
|
|
139
136
|
// only awaits the module's synchronous evaluation, so we must await it
|
|
140
137
|
// directly to observe init errors (e.g. invalid config) here instead of
|
|
@@ -153,8 +150,7 @@ export function rime() {
|
|
|
153
150
|
}
|
|
154
151
|
}
|
|
155
152
|
server.watcher.on('change', (modulePath) => {
|
|
156
|
-
const isConfigChange = modulePath.includes(
|
|
157
|
-
!modulePath.includes(`src/lib/${OUTPUT_DIR}`);
|
|
153
|
+
const isConfigChange = modulePath.includes(CONFIG_DIR) && !modulePath.includes(GENERATED_DIR);
|
|
158
154
|
if (!isConfigChange)
|
|
159
155
|
return;
|
|
160
156
|
if (reloadTimer)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { BuiltCollection } from '../types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Ensure sanitize config exists — the generated server config inside
|
|
3
|
+
* Ensure sanitize config exists — the generated server config inside the generated config dir.
|
|
4
4
|
*/
|
|
5
5
|
export declare function ensureGeneratedConfig(): string;
|
|
6
6
|
/**
|
|
7
|
-
* Ensure user config exists — the
|
|
7
|
+
* Ensure user config exists — the CONFIG_DIR folder convention.
|
|
8
8
|
*/
|
|
9
9
|
export declare function ensureUserConfigExist(): void;
|
|
10
10
|
/**
|
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
import { existsSync, mkdirSync } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { CONFIG_DIR, GENERATED_DIR, generatedConfigServerPath, schemaPath } from './dev/constants.js';
|
|
4
4
|
const projectRoot = process.cwd();
|
|
5
5
|
/**
|
|
6
|
-
* Ensure sanitize config exists — the generated server config inside
|
|
6
|
+
* Ensure sanitize config exists — the generated server config inside the generated config dir.
|
|
7
7
|
*/
|
|
8
8
|
export function ensureGeneratedConfig() {
|
|
9
|
-
const configGeneratedPath = path.resolve(projectRoot,
|
|
9
|
+
const configGeneratedPath = path.resolve(projectRoot, GENERATED_DIR, 'rime.config.server.ts');
|
|
10
10
|
if (!existsSync(configGeneratedPath)) {
|
|
11
11
|
throw new Error('Unable to find generated config');
|
|
12
12
|
}
|
|
13
|
-
return
|
|
13
|
+
return generatedConfigServerPath();
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Ensure user config exists — the
|
|
16
|
+
* Ensure user config exists — the CONFIG_DIR folder convention.
|
|
17
17
|
*/
|
|
18
18
|
export function ensureUserConfigExist() {
|
|
19
|
-
const folderConfig = path.resolve(projectRoot,
|
|
20
|
-
if (
|
|
21
|
-
|
|
19
|
+
const folderConfig = path.resolve(projectRoot, CONFIG_DIR, 'rime.config.server.ts');
|
|
20
|
+
if (existsSync(folderConfig))
|
|
21
|
+
return;
|
|
22
|
+
// Every project set up before RIME_CONFIG_DIR existed has its config here — if it's there
|
|
23
|
+
// but not at CONFIG_DIR, this is almost certainly an upgrade whose .env predates the env
|
|
24
|
+
// var, not a missing init, so say that instead of the generic message.
|
|
25
|
+
const LEGACY_DEFAULT = 'src/lib/+rime';
|
|
26
|
+
if (CONFIG_DIR !== LEGACY_DEFAULT &&
|
|
27
|
+
existsSync(path.resolve(projectRoot, LEGACY_DEFAULT, 'rime.config.server.ts'))) {
|
|
28
|
+
throw new Error(`Unable to find config at ${CONFIG_DIR} — found one at ${LEGACY_DEFAULT} instead. ` +
|
|
29
|
+
`Set RIME_CONFIG_DIR=${LEGACY_DEFAULT} in your .env to keep using it there, or move it to ${CONFIG_DIR} to match the current default.`);
|
|
22
30
|
}
|
|
31
|
+
throw new Error('Unable to find config, did you run rime init');
|
|
23
32
|
}
|
|
24
33
|
/**
|
|
25
34
|
* Ensure schema exists (see adapter-sqlite/generate-schema/write.server.ts, which writes to
|
|
@@ -1,16 +1,24 @@
|
|
|
1
|
+
import { isPublicPanelAuthRoute } from '../constant.js';
|
|
1
2
|
import { RimeError } from '../errors/index.js';
|
|
2
3
|
import { error, redirect } from '@sveltejs/kit';
|
|
3
4
|
import { BETTER_AUTH_ROLES } from '../collections/auth/constant.server.js';
|
|
4
5
|
import { logger } from '../logger/index.server.js';
|
|
5
6
|
const dev = process.env.NODE_ENV === 'development';
|
|
6
7
|
/**
|
|
7
|
-
* Analyzes the current route to determine authentication requirements
|
|
8
|
+
* Analyzes the current route to determine authentication requirements.
|
|
9
|
+
* isPanel/isPublicAuthRoute are derived from the matched route, not the
|
|
10
|
+
* pathname — event.params.panel only resolves when the request matched the
|
|
11
|
+
* [panel=panel] matcher, and event.route.id's literal folder names never
|
|
12
|
+
* carry the configured RIME_PANEL_ROUTE value — so neither check needs to
|
|
13
|
+
* know the actual (hideable) panel segment. sign-in/forgot-password/reset-password
|
|
14
|
+
* all live under [panel=panel] too but must stay reachable without a session,
|
|
15
|
+
* hence the isPublicAuthRoute carve-out.
|
|
8
16
|
*/
|
|
9
|
-
function analyzeRoute(
|
|
10
|
-
const
|
|
11
|
-
const isPanel =
|
|
12
|
-
const isAPI = pathname.startsWith('/api');
|
|
13
|
-
return {
|
|
17
|
+
function analyzeRoute(event) {
|
|
18
|
+
const isPublicAuthRoute = isPublicPanelAuthRoute(event.route.id);
|
|
19
|
+
const isPanel = event.params.panel !== undefined && !isPublicAuthRoute;
|
|
20
|
+
const isAPI = event.url.pathname.startsWith('/api');
|
|
21
|
+
return { isPublicAuthRoute, isPanel, isAPI };
|
|
14
22
|
}
|
|
15
23
|
/**
|
|
16
24
|
* Ensures panel is properly set up before allowing access
|
|
@@ -31,7 +39,7 @@ async function authenticateRequest(headers, auth) {
|
|
|
31
39
|
*/
|
|
32
40
|
function handleUnauthenticated(event, resolve, routeInfo) {
|
|
33
41
|
if (routeInfo.isPanel) {
|
|
34
|
-
throw redirect(303,
|
|
42
|
+
throw redirect(303, `/${event.params.panel}/sign-in`);
|
|
35
43
|
}
|
|
36
44
|
event.locals.user = undefined;
|
|
37
45
|
event.locals.session = undefined;
|
|
@@ -70,12 +78,11 @@ async function handleApiKeyAuth(headers, user, auth) {
|
|
|
70
78
|
const result = await auth.api.verifyApiKey({
|
|
71
79
|
body: { key: apiKey }
|
|
72
80
|
});
|
|
73
|
-
if (!result.valid || !result.key ||
|
|
81
|
+
if (!result.valid || !result.key || !result.key.permissions) {
|
|
74
82
|
logger.error(RimeError.UNAUTHORIZED, 'Invalid api key');
|
|
75
83
|
throw error(401, RimeError.UNAUTHORIZED);
|
|
76
84
|
}
|
|
77
|
-
|
|
78
|
-
user.roles = permissions.roles;
|
|
85
|
+
user.roles = result.key.permissions.roles;
|
|
79
86
|
}
|
|
80
87
|
/**
|
|
81
88
|
* Builds complete user data by combining auth and CMS information
|
|
@@ -133,7 +140,7 @@ function cleanupUser(userData, routeInfo) {
|
|
|
133
140
|
*/
|
|
134
141
|
export const handleAuth = async ({ event, resolve }) => {
|
|
135
142
|
const rime = event.locals.rime;
|
|
136
|
-
const routeInfo = analyzeRoute(event
|
|
143
|
+
const routeInfo = analyzeRoute(event);
|
|
137
144
|
// Ensure auth is set up
|
|
138
145
|
if (routeInfo.isPanel) {
|
|
139
146
|
await ensureFirstAuthSetup(rime);
|
|
@@ -31,7 +31,7 @@ export declare const routeHandlers: {
|
|
|
31
31
|
aria: import("../../types.js").Route[];
|
|
32
32
|
}>;
|
|
33
33
|
live: typeof liveLoad;
|
|
34
|
-
signIn: ({ locals }: ServerLoadEvent) => Promise<{
|
|
34
|
+
signIn: ({ locals, params }: ServerLoadEvent) => Promise<{
|
|
35
35
|
forgotPasswordEnabled: boolean;
|
|
36
36
|
image: string | null;
|
|
37
37
|
form: {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isPublicPanelAuthRoute } from '../constant.js';
|
|
1
2
|
import { prototypeKebabToSlug } from '../naming.js';
|
|
2
3
|
import buildNavigation from '../../panel/navigation.js';
|
|
3
4
|
import { areaFormActions } from '../../panel/pages/area/actions.server.js';
|
|
@@ -56,9 +57,9 @@ export const routeHandlers = {
|
|
|
56
57
|
};
|
|
57
58
|
export const handleRoutes = async ({ event, resolve }) => {
|
|
58
59
|
const { rime, user } = event.locals;
|
|
59
|
-
const
|
|
60
|
+
const IS_PUBLIC_AUTH_ROUTE = isPublicPanelAuthRoute(event.route.id);
|
|
60
61
|
const IS_API_ROUTE = event.url.pathname.startsWith('/api');
|
|
61
|
-
const IS_PANEL_ROUTE = event.
|
|
62
|
+
const IS_PANEL_ROUTE = event.params.panel !== undefined && !IS_PUBLIC_AUTH_ROUTE;
|
|
62
63
|
// event.params.slug comes straight from the URL, always kebab-case (see
|
|
63
64
|
// src/params/collection.ts, area.ts). Collection/area slugs themselves are
|
|
64
65
|
// camelCase, so rewrite once here — every downstream handler (panel
|
|
@@ -72,7 +73,7 @@ export const handleRoutes = async ({ event, resolve }) => {
|
|
|
72
73
|
}
|
|
73
74
|
// build panel navigation
|
|
74
75
|
if (IS_PANEL_ROUTE && event.request.method === 'GET') {
|
|
75
|
-
event.locals.navigation = buildNavigation(rime.config.raw, user);
|
|
76
|
+
event.locals.navigation = buildNavigation(rime.config.raw, user, event.params.panel);
|
|
76
77
|
}
|
|
77
78
|
event.locals.routes = routeHandlers;
|
|
78
79
|
// Handle custom routes from config and plugins
|