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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { dev } from '$app/environment';
|
|
2
2
|
import { env } from '$env/dynamic/public';
|
|
3
|
-
import {
|
|
3
|
+
import { apiKey } from '@better-auth/api-key';
|
|
4
|
+
import { admin as adminPlugin } from 'better-auth/plugins';
|
|
4
5
|
import { betterAuthAfterHook, betterAuthBeforeHook } from './better-auth-hooks.server.js';
|
|
5
6
|
import { accessControl, admin, staff, user } from './better-auth-permissions.js';
|
|
6
7
|
export function getBaseAuthConfig(ctx) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { flatten } from 'flat';
|
|
2
2
|
import cache from '../../dev/cache/index.server.js';
|
|
3
|
+
import { CONFIG_DIR } from '../../dev/constants.js';
|
|
3
4
|
/**
|
|
4
5
|
* We actually need to serialize config values that will trigger
|
|
5
6
|
* types, routes, or schema generations, meaning that for now
|
|
@@ -59,6 +60,10 @@ const writeMemo = (config) => {
|
|
|
59
60
|
throw new Error(`Config error : Unable to parse value for key ${key}: ${err.message}`);
|
|
60
61
|
}
|
|
61
62
|
})
|
|
63
|
+
// Not part of the user's config object, but generated output (routes, schema, hooks) is
|
|
64
|
+
// relative to it — a RIME_CONFIG_DIR change must invalidate the memo just like a config
|
|
65
|
+
// change does, even when the config content itself is byte-identical.
|
|
66
|
+
.concat(`CONFIG_DIR:${CONFIG_DIR}`)
|
|
62
67
|
.join('\n');
|
|
63
68
|
const cached = cache.get('config');
|
|
64
69
|
if (cached !== memoStr) {
|
|
@@ -2,14 +2,14 @@ import { RIME_DEV_CACHE_DIR } from '../../../constant.server.js';
|
|
|
2
2
|
import { logger } from '../../../logger/index.server.js';
|
|
3
3
|
import { rmSync } from 'node:fs';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
-
import {
|
|
5
|
+
import { CONFIG_DIR, GENERATED_DIR } from '../../constants.js';
|
|
6
6
|
import { prompt } from '../util/prompt.server.js';
|
|
7
7
|
const clearMessage = `Are you sure you want to delete all related rime files (Y/n):
|
|
8
8
|
- ./static/medias
|
|
9
9
|
- ./db
|
|
10
10
|
- ./src/routes/(rime)
|
|
11
|
-
-
|
|
12
|
-
-
|
|
11
|
+
- ./${CONFIG_DIR}
|
|
12
|
+
- ./${GENERATED_DIR}
|
|
13
13
|
- ./src/app.generated.d.ts
|
|
14
14
|
- ./src/rime.generated.d.ts
|
|
15
15
|
- ./src/rime.modules.generated.d.ts
|
|
@@ -28,8 +28,8 @@ export const clear = async (args) => {
|
|
|
28
28
|
// Remove directories
|
|
29
29
|
rmSync(RIME_DEV_CACHE_DIR, { recursive: true, force: true });
|
|
30
30
|
rmSync(path.join('src', 'routes', '(rime)'), { recursive: true, force: true });
|
|
31
|
-
rmSync(
|
|
32
|
-
rmSync(
|
|
31
|
+
rmSync(CONFIG_DIR, { recursive: true, force: true });
|
|
32
|
+
rmSync(GENERATED_DIR, { recursive: true, force: true });
|
|
33
33
|
rmSync(path.join('db'), { recursive: true, force: true });
|
|
34
34
|
rmSync(path.join('static', 'medias'), { recursive: true, force: true });
|
|
35
35
|
// Remove files
|
|
@@ -9,7 +9,7 @@ import { cp, mkdir } from 'fs/promises';
|
|
|
9
9
|
import fs from 'node:fs';
|
|
10
10
|
import path from 'path';
|
|
11
11
|
import { fileURLToPath } from 'url';
|
|
12
|
-
import {
|
|
12
|
+
import { CONFIG_DIR, OUTPUT_DIR } from '../../constants.js';
|
|
13
13
|
import { generate } from '../generate/index.server.js';
|
|
14
14
|
import { installDependencies } from '../util/package-manager.server.js';
|
|
15
15
|
import { getPackageInfoByKey } from '../util/package.server.js';
|
|
@@ -25,6 +25,7 @@ export const init = async ({ force, name: incomingName, skipInstall }) => {
|
|
|
25
25
|
const envUpdates = {
|
|
26
26
|
BETTER_AUTH_SECRET: randomId(32),
|
|
27
27
|
PUBLIC_RIME_URL: 'http://localhost:5173',
|
|
28
|
+
RIME_CONFIG_DIR: CONFIG_DIR,
|
|
28
29
|
'# RIME_SMTP_USER': 'user@mail.com',
|
|
29
30
|
'# RIME_SMTP_PASSWORD': 'supersecret',
|
|
30
31
|
'# RIME_SMTP_PORT': '465',
|
|
@@ -53,7 +54,7 @@ export const init = async ({ force, name: incomingName, skipInstall }) => {
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
function setConfig(name) {
|
|
56
|
-
const configDirPath = path.resolve(root,
|
|
57
|
+
const configDirPath = path.resolve(root, CONFIG_DIR);
|
|
57
58
|
const configPath = path.join(configDirPath, 'rime.config.server.ts');
|
|
58
59
|
if (!existsSync(configPath)) {
|
|
59
60
|
if (!existsSync(configDirPath)) {
|
|
@@ -83,21 +84,24 @@ export const init = async ({ force, name: incomingName, skipInstall }) => {
|
|
|
83
84
|
return;
|
|
84
85
|
}
|
|
85
86
|
let gitignoreContent = readFileSync(gitignorePath, 'utf-8');
|
|
87
|
+
// OUTPUT_DIR is derived from RIME_CONFIG_DIR, so its first character isn't always '+' —
|
|
88
|
+
// escape every regex metacharacter generically instead of hand-picking one to backslash.
|
|
89
|
+
const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
86
90
|
const updates = [
|
|
87
|
-
'
|
|
91
|
+
'.cache',
|
|
88
92
|
'/logs',
|
|
89
93
|
'/db',
|
|
90
|
-
|
|
94
|
+
OUTPUT_DIR,
|
|
91
95
|
'src/app.generated.d.ts',
|
|
92
96
|
'src/rime.generated.d.ts'
|
|
93
97
|
];
|
|
94
98
|
if (!gitignoreContent.includes('# rime'))
|
|
95
99
|
gitignoreContent += '\n# rime';
|
|
96
100
|
for (const line of updates) {
|
|
97
|
-
const exists = gitignoreContent.match(new RegExp(`^${line}`, 'm'));
|
|
101
|
+
const exists = gitignoreContent.match(new RegExp(`^${escapeRegExp(line)}`, 'm'));
|
|
98
102
|
if (!exists) {
|
|
99
103
|
// Add new value if doesn't exist
|
|
100
|
-
gitignoreContent += `\n${line
|
|
104
|
+
gitignoreContent += `\n${line}`;
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
107
|
writeFileSync(gitignorePath, gitignoreContent);
|
|
@@ -108,10 +112,11 @@ export const init = async ({ force, name: incomingName, skipInstall }) => {
|
|
|
108
112
|
if (!existsSync(drizzleConfigPath)) {
|
|
109
113
|
writeFileSync(drizzleConfigPath, templates.drizzleConfig(name.toString()));
|
|
110
114
|
logger.info('[✓] Drizzle config added');
|
|
115
|
+
return;
|
|
111
116
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
117
|
+
logger.info(templates.regenerateDrizzleConfig(root)
|
|
118
|
+
? '[✓] Drizzle config schema path updated'
|
|
119
|
+
: '[✓] Drizzle config already exists (skip)');
|
|
115
120
|
}
|
|
116
121
|
function configureVite() {
|
|
117
122
|
const configPath = path.resolve(root, 'vite.config.ts');
|
|
@@ -182,23 +187,6 @@ export const init = async ({ force, name: incomingName, skipInstall }) => {
|
|
|
182
187
|
}
|
|
183
188
|
return null;
|
|
184
189
|
}
|
|
185
|
-
function setHooks() {
|
|
186
|
-
const hooksPath = path.join(root, 'src', 'hooks.server.ts');
|
|
187
|
-
const srcDir = path.join(root, 'src');
|
|
188
|
-
// Check if file exists
|
|
189
|
-
if (!existsSync(hooksPath)) {
|
|
190
|
-
// Ensure src directory exists
|
|
191
|
-
if (!existsSync(srcDir)) {
|
|
192
|
-
mkdirSync(srcDir, { recursive: true });
|
|
193
|
-
}
|
|
194
|
-
// Create hooks.server.ts with template content
|
|
195
|
-
writeFileSync(hooksPath, templates.hooks(), 'utf-8');
|
|
196
|
-
logger.info('[✓] hooks.server.ts created');
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
logger.info('[✓] hooks.server.ts already exists (skip)');
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
190
|
async function copyAssets() {
|
|
203
191
|
try {
|
|
204
192
|
const currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -219,7 +207,6 @@ export const init = async ({ force, name: incomingName, skipInstall }) => {
|
|
|
219
207
|
setConfig(name);
|
|
220
208
|
setDatabase();
|
|
221
209
|
setDrizzle(name);
|
|
222
|
-
setHooks();
|
|
223
210
|
configureVite();
|
|
224
211
|
await copyAssets();
|
|
225
212
|
!skipInstall && installDependencies();
|
|
@@ -244,7 +231,6 @@ export const init = async ({ force, name: incomingName, skipInstall }) => {
|
|
|
244
231
|
setConfig(name);
|
|
245
232
|
setDatabase();
|
|
246
233
|
setDrizzle(name);
|
|
247
|
-
setHooks();
|
|
248
234
|
configureVite();
|
|
249
235
|
await copyAssets();
|
|
250
236
|
!skipInstall && installDependencies();
|
|
@@ -2,3 +2,15 @@ export declare const env: () => string;
|
|
|
2
2
|
export declare const defaultConfig: (name: string) => string;
|
|
3
3
|
export declare const drizzleConfig: (name: string) => string;
|
|
4
4
|
export declare const hooks: () => string;
|
|
5
|
+
/** Writes src/hooks.server.ts if missing, or rewrites it if its content would differ from
|
|
6
|
+
* what's expected now (e.g. after RIME_CONFIG_DIR changes the import path) — called both at
|
|
7
|
+
* `rime init` and whenever the dev server detects a config change, so it never goes stale
|
|
8
|
+
* between the two. Returns whether it wrote anything. */
|
|
9
|
+
export declare function regenerateHooks(root?: string): boolean;
|
|
10
|
+
/** Patches drizzle.config.ts's schema path line if it's stale (e.g. after RIME_CONFIG_DIR
|
|
11
|
+
* changes) — only that one line, since the rest of the file may carry real customizations
|
|
12
|
+
* (verbose, custom fields, etc.). Must run before generateSchema()'s own drizzle-kit
|
|
13
|
+
* generate/migrate shell-out, which reads this file from disk. No-op if the file doesn't
|
|
14
|
+
* exist — creating it from scratch needs a project name, which is `rime init`'s job
|
|
15
|
+
* (setDrizzle() in init/index.server.ts). Returns whether it patched anything. */
|
|
16
|
+
export declare function regenerateDrizzleConfig(root?: string): boolean;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { randomId } from '../../../../util/random.js';
|
|
2
|
-
import {
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { CONFIG_DIR, GENERATED_DIR, configImportPaths } from '../../constants.js';
|
|
3
5
|
const PACKAGE = 'rimecms';
|
|
4
6
|
export const env = () => `BETTER_AUTH_SECRET=${randomId(32)}
|
|
5
7
|
PUBLIC_RIME_URL=http://localhost:5173
|
|
8
|
+
RIME_CONFIG_DIR=${CONFIG_DIR}
|
|
6
9
|
|
|
7
10
|
# RIME_CACHE_ENABLED=false
|
|
8
11
|
# RIME_SMTP_USER=user@mail.com
|
|
@@ -40,7 +43,7 @@ export const drizzleConfig = (name) => `
|
|
|
40
43
|
import { defineConfig, type Config } from 'drizzle-kit';
|
|
41
44
|
|
|
42
45
|
export const config: Config = {
|
|
43
|
-
schema: '
|
|
46
|
+
schema: './${GENERATED_DIR}/schema.server.ts',
|
|
44
47
|
out: './db',
|
|
45
48
|
strict: false,
|
|
46
49
|
dialect: 'sqlite',
|
|
@@ -53,9 +56,50 @@ export default defineConfig(config);
|
|
|
53
56
|
`;
|
|
54
57
|
// Regenerated fresh by rime init every time (setHooks() only skips if the file already
|
|
55
58
|
// exists, and `rime clear`/useConfig.js delete it first) — safe to make mode-aware.
|
|
59
|
+
const HOOKS_DIR = path.resolve(process.cwd(), 'src');
|
|
56
60
|
export const hooks = () => `import { sequence } from '@sveltejs/kit/hooks';
|
|
57
61
|
import { handlers } from '${PACKAGE}/server';
|
|
58
|
-
import config from '
|
|
62
|
+
import config from '${configImportPaths(HOOKS_DIR).server}';
|
|
59
63
|
|
|
60
64
|
export const handle = sequence(...(await handlers(config)));
|
|
61
65
|
`;
|
|
66
|
+
/** Writes src/hooks.server.ts if missing, or rewrites it if its content would differ from
|
|
67
|
+
* what's expected now (e.g. after RIME_CONFIG_DIR changes the import path) — called both at
|
|
68
|
+
* `rime init` and whenever the dev server detects a config change, so it never goes stale
|
|
69
|
+
* between the two. Returns whether it wrote anything. */
|
|
70
|
+
export function regenerateHooks(root = process.cwd()) {
|
|
71
|
+
const hooksPath = path.join(root, 'src', 'hooks.server.ts');
|
|
72
|
+
const srcDir = path.join(root, 'src');
|
|
73
|
+
const content = hooks();
|
|
74
|
+
if (!existsSync(hooksPath)) {
|
|
75
|
+
if (!existsSync(srcDir)) {
|
|
76
|
+
mkdirSync(srcDir, { recursive: true });
|
|
77
|
+
}
|
|
78
|
+
writeFileSync(hooksPath, content, 'utf-8');
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
if (readFileSync(hooksPath, 'utf-8') !== content) {
|
|
82
|
+
writeFileSync(hooksPath, content, 'utf-8');
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
const DRIZZLE_SCHEMA_LINE_REGEX = /^\s*schema:\s*['"][^'"]*['"],?\s*$/m;
|
|
88
|
+
/** Patches drizzle.config.ts's schema path line if it's stale (e.g. after RIME_CONFIG_DIR
|
|
89
|
+
* changes) — only that one line, since the rest of the file may carry real customizations
|
|
90
|
+
* (verbose, custom fields, etc.). Must run before generateSchema()'s own drizzle-kit
|
|
91
|
+
* generate/migrate shell-out, which reads this file from disk. No-op if the file doesn't
|
|
92
|
+
* exist — creating it from scratch needs a project name, which is `rime init`'s job
|
|
93
|
+
* (setDrizzle() in init/index.server.ts). Returns whether it patched anything. */
|
|
94
|
+
export function regenerateDrizzleConfig(root = process.cwd()) {
|
|
95
|
+
const drizzleConfigPath = path.join(root, 'drizzle.config.ts');
|
|
96
|
+
if (!existsSync(drizzleConfigPath))
|
|
97
|
+
return false;
|
|
98
|
+
const expectedSchemaLine = ` schema: './${GENERATED_DIR}/schema.server.ts',`;
|
|
99
|
+
const content = readFileSync(drizzleConfigPath, 'utf-8');
|
|
100
|
+
if (DRIZZLE_SCHEMA_LINE_REGEX.test(content) && !content.includes(expectedSchemaLine)) {
|
|
101
|
+
writeFileSync(drizzleConfigPath, content.replace(DRIZZLE_SCHEMA_LINE_REGEX, expectedSchemaLine));
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
export declare const
|
|
2
|
-
export declare const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
export declare const CONFIG_DIR: string;
|
|
2
|
+
export declare const GENERATED_DIR: string;
|
|
3
|
+
export declare const INPUT_DIR: string;
|
|
4
|
+
export declare const OUTPUT_DIR: string;
|
|
5
|
+
/** Turns an absolute path into an import specifier relative to `fromDir`, always prefixed
|
|
6
|
+
* with `./` or `../` so it never gets mistaken for a bare package specifier. */
|
|
7
|
+
export declare function relativeImportSpecifier(fromDir: string, toAbsolutePath: string): string;
|
|
8
|
+
export declare function generatedConfigServerPath(): string;
|
|
9
|
+
/** Where the panel/live route templates (common.server.ts) and the generated hooks.server.ts
|
|
10
|
+
* should import the client/server config from — a relative import specifier computed from
|
|
11
|
+
* `fromDir` (the absolute directory of the file doing the importing), so it resolves whether
|
|
12
|
+
* GENERATED_DIR lives under src/lib or elsewhere. One source of truth instead of hardcoding the
|
|
13
|
+
* path (or relying on the $lib alias, which only ever points at src/lib) at each call site. */
|
|
14
|
+
export declare function configImportPaths(fromDir: string): {
|
|
7
15
|
client: string;
|
|
8
16
|
server: string;
|
|
9
17
|
};
|
|
10
18
|
/** Same idea as configImportPaths — one source of truth for where the generated schema
|
|
11
19
|
* lives instead of hardcoding the path at each call site. */
|
|
12
|
-
export declare function schemaPath(
|
|
20
|
+
export declare function schemaPath(projectRoot?: string): string;
|
|
13
21
|
/**
|
|
14
22
|
* True when `metaUrl` (pass the caller's own `import.meta.url` — this can't be one shared
|
|
15
23
|
* value, it depends on which file is asking) is running from inside an installed `rimecms`
|
|
@@ -1,19 +1,58 @@
|
|
|
1
|
+
import dotenv from 'dotenv';
|
|
1
2
|
import path from 'node:path';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
// Must run before RIME_CONFIG_DIR is read below. ES import hoisting evaluates this module's
|
|
4
|
+
// top-level code before any *importing* file's own top-level statements — including a
|
|
5
|
+
// dotenv.config() call there — so loading .env here, first, is the only way every entry point
|
|
6
|
+
// (CLI, dev-server, drizzle.config.ts, etc.) reliably sees it. override:true so .env is the
|
|
7
|
+
// explicit source of truth, not whatever a shell plugin (autoenv, direnv, ...) already exported
|
|
8
|
+
// from some other project's .env. The only dotenv.config() call in the codebase — a second one
|
|
9
|
+
// elsewhere would race this one.
|
|
10
|
+
dotenv.config({ override: true });
|
|
11
|
+
const root = process.cwd();
|
|
12
|
+
const SRC_ROOT = path.resolve(root, 'src');
|
|
13
|
+
export const CONFIG_DIR = process.env.RIME_CONFIG_DIR || 'src/+rime';
|
|
14
|
+
export const GENERATED_DIR = `${CONFIG_DIR}.generated`;
|
|
15
|
+
export const INPUT_DIR = path.basename(CONFIG_DIR);
|
|
16
|
+
export const OUTPUT_DIR = `${INPUT_DIR}.generated`;
|
|
17
|
+
const RESERVED_DIRS = new Set(['lib', 'routes', 'static', 'params'].map((d) => path.resolve(SRC_ROOT, d)));
|
|
18
|
+
for (const dir of [CONFIG_DIR, GENERATED_DIR]) {
|
|
19
|
+
const resolved = path.resolve(root, dir);
|
|
20
|
+
if (resolved === SRC_ROOT || !resolved.startsWith(SRC_ROOT + path.sep)) {
|
|
21
|
+
throw new Error(`RIME_CONFIG_DIR must resolve to a subdirectory of ${SRC_ROOT} (got "${dir}")`);
|
|
22
|
+
}
|
|
23
|
+
if (RESERVED_DIRS.has(resolved)) {
|
|
24
|
+
throw new Error(`RIME_CONFIG_DIR must not be src/lib, src/routes, src/static, or src/params (got "${dir}")`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** Turns an absolute path into an import specifier relative to `fromDir`, always prefixed
|
|
28
|
+
* with `./` or `../` so it never gets mistaken for a bare package specifier. */
|
|
29
|
+
export function relativeImportSpecifier(fromDir, toAbsolutePath) {
|
|
30
|
+
const rel = path.relative(fromDir, toAbsolutePath).split(path.sep).join('/');
|
|
31
|
+
return rel.startsWith('.') ? rel : `./${rel}`;
|
|
32
|
+
}
|
|
33
|
+
/** Root-relative filesystem path (posix-style) to a file inside the generated config dir —
|
|
34
|
+
* for Vite's ssrLoadModule, which wants a real file path, not an import specifier. */
|
|
35
|
+
function generatedFilePath(file) {
|
|
36
|
+
return path.relative(root, path.resolve(root, GENERATED_DIR, file)).split(path.sep).join('/');
|
|
37
|
+
}
|
|
38
|
+
export function generatedConfigServerPath() {
|
|
39
|
+
return generatedFilePath('rime.config.server.ts');
|
|
40
|
+
}
|
|
41
|
+
/** Where the panel/live route templates (common.server.ts) and the generated hooks.server.ts
|
|
42
|
+
* should import the client/server config from — a relative import specifier computed from
|
|
43
|
+
* `fromDir` (the absolute directory of the file doing the importing), so it resolves whether
|
|
44
|
+
* GENERATED_DIR lives under src/lib or elsewhere. One source of truth instead of hardcoding the
|
|
45
|
+
* path (or relying on the $lib alias, which only ever points at src/lib) at each call site. */
|
|
46
|
+
export function configImportPaths(fromDir) {
|
|
8
47
|
return {
|
|
9
|
-
client:
|
|
10
|
-
server:
|
|
48
|
+
client: relativeImportSpecifier(fromDir, path.resolve(root, GENERATED_DIR, 'rime.config.js')),
|
|
49
|
+
server: relativeImportSpecifier(fromDir, path.resolve(root, GENERATED_DIR, 'rime.config.server.js'))
|
|
11
50
|
};
|
|
12
51
|
}
|
|
13
52
|
/** Same idea as configImportPaths — one source of truth for where the generated schema
|
|
14
53
|
* lives instead of hardcoding the path at each call site. */
|
|
15
|
-
export function schemaPath(
|
|
16
|
-
return path.resolve(
|
|
54
|
+
export function schemaPath(projectRoot = process.cwd()) {
|
|
55
|
+
return path.resolve(projectRoot, GENERATED_DIR, 'schema.server.ts');
|
|
17
56
|
}
|
|
18
57
|
/**
|
|
19
58
|
* True when `metaUrl` (pass the caller's own `import.meta.url` — this can't be one shared
|
|
@@ -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');
|
|
5
|
+
const LIVE_PAGE_DIR = path.resolve(process.cwd(), 'src/routes/(rime)/panel/live-edit');
|
|
3
6
|
/**
|
|
4
7
|
* Main base layout
|
|
5
8
|
* /+layout.server.ts
|
|
@@ -146,7 +149,7 @@ export const load = (event: ServerLoadEvent) => event.locals.routes.panel.load.r
|
|
|
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
|
|
|
@@ -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>
|
|
@@ -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
|
|
@@ -70,12 +70,11 @@ async function handleApiKeyAuth(headers, user, auth) {
|
|
|
70
70
|
const result = await auth.api.verifyApiKey({
|
|
71
71
|
body: { key: apiKey }
|
|
72
72
|
});
|
|
73
|
-
if (!result.valid || !result.key ||
|
|
73
|
+
if (!result.valid || !result.key || !result.key.permissions) {
|
|
74
74
|
logger.error(RimeError.UNAUTHORIZED, 'Invalid api key');
|
|
75
75
|
throw error(401, RimeError.UNAUTHORIZED);
|
|
76
76
|
}
|
|
77
|
-
|
|
78
|
-
user.roles = permissions.roles;
|
|
77
|
+
user.roles = result.key.permissions.roles;
|
|
79
78
|
}
|
|
80
79
|
/**
|
|
81
80
|
* Builds complete user data by combining auth and CMS information
|