rimecms 0.30.3 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -39
- package/dist/.rime-modules.d.ts +23 -0
- package/dist/.rime-modules.json +1 -0
- package/dist/adapter-sqlite/generate-schema/write.server.js +6 -6
- package/dist/core/areas/config/builder.server.d.ts +0 -1
- package/dist/core/collections/auth/hooks/before-upsert/augment-fields-password.server.d.ts +1 -1
- package/dist/core/collections/config/builder.server.d.ts +0 -1
- package/dist/core/collections/upload/hooks/convert-base64.server.d.ts +1 -1
- package/dist/core/collections/upload/hooks/extract-path.server.d.ts +1 -1
- package/dist/core/collections/upload/hooks/handle-path-creation.server.d.ts +1 -1
- package/dist/core/collections/upload/hooks/process-file-upload.server.d.ts +1 -1
- package/dist/core/config/auth/better-auth.server.d.ts +3 -3
- package/dist/core/config/client/augment-plugins.d.ts +1 -5
- package/dist/core/config/client/augment-plugins.js +3 -3
- package/dist/core/config/client/build-config.d.ts +1 -5
- package/dist/core/config/config-context.server.d.ts +1 -1
- package/dist/core/config/server/augment-plugins.server.d.ts +2 -42
- package/dist/core/config/server/augment-plugins.server.js +11 -6
- package/dist/core/config/server/build-config.server.d.ts +9 -4007
- package/dist/core/config/types.d.ts +12 -11
- package/dist/core/dev/cache/index.server.js +1 -1
- package/dist/core/dev/cli/clear/index.server.js +2 -0
- package/dist/core/dev/cli/generate-manifest/index.server.d.ts +17 -0
- package/dist/core/dev/cli/generate-manifest/index.server.js +221 -0
- package/dist/core/dev/cli/index.js +42 -0
- package/dist/core/dev/cli/init/index.server.js +11 -4
- package/dist/core/dev/cli/init/templates.d.ts +1 -1
- package/dist/core/dev/cli/init/templates.js +5 -3
- package/dist/core/dev/cli/util/package-manager.server.js +5 -3
- package/dist/core/dev/constants.d.ts +10 -0
- package/dist/core/dev/constants.js +15 -0
- package/dist/core/dev/generate/routes/common.server.js +4 -7
- package/dist/core/dev/generate/routes/index.server.js +25 -4
- package/dist/core/dev/generate/runtime/index.server.d.ts +31 -15
- package/dist/core/dev/generate/runtime/index.server.js +45 -53
- package/dist/core/dev/generate/runtime/parse-exports.server.d.ts +7 -0
- package/dist/core/dev/generate/runtime/parse-exports.server.js +40 -0
- package/dist/core/dev/generate/sanitize/index.server.d.ts +0 -7
- package/dist/core/dev/generate/sanitize/index.server.js +57 -5
- package/dist/core/dev/generate/types/index.server.js +16 -39
- package/dist/core/dev/vite/index.server.js +217 -39
- package/dist/core/ensure.server.d.ts +4 -3
- package/dist/core/ensure.server.js +8 -8
- package/dist/core/handlers/index.js +2 -2
- package/dist/core/operations/hooks/before-upsert/data-config-map.server.d.ts +1 -1
- package/dist/core/operations/hooks/before-upsert/handle-new-version.server.d.ts +1 -1
- package/dist/core/operations/hooks/before-upsert/original-config-map.server.d.ts +1 -1
- package/dist/core/operations/hooks/before-upsert/set-default-values.server.d.ts +1 -1
- package/dist/core/operations/hooks/before-upsert/validate-fields.server.d.ts +1 -1
- package/dist/core/operations/hooks/index.server.d.ts +0 -4
- package/dist/core/operations/hooks/index.server.js +0 -4
- package/dist/core/plugins/api-init/index.d.ts +2 -0
- package/dist/core/plugins/api-init/index.js +1 -0
- package/dist/core/plugins/api-init/{index.server.d.ts → module.server.d.ts} +0 -1
- package/dist/core/plugins/api-init/{index.server.js → module.server.js} +0 -1
- package/dist/core/plugins/cache/index.d.ts +2 -5
- package/dist/core/plugins/cache/index.js +1 -21
- package/dist/core/plugins/cache/module.d.ts +4 -0
- package/dist/core/plugins/cache/module.js +22 -0
- package/dist/core/plugins/cache/{index.server.d.ts → module.server.d.ts} +1 -2
- package/dist/core/plugins/cache/{index.server.js → module.server.js} +0 -1
- package/dist/core/plugins/index.d.ts +1 -8
- package/dist/core/plugins/index.js +0 -3
- package/dist/core/plugins/mailer/index.d.ts +2 -0
- package/dist/core/plugins/mailer/index.js +1 -0
- package/dist/core/plugins/mailer/{index.server.d.ts → module.server.d.ts} +0 -1
- package/dist/core/plugins/mailer/{index.server.js → module.server.js} +0 -1
- package/dist/core/plugins/sse/index.d.ts +2 -0
- package/dist/core/plugins/sse/index.js +1 -0
- package/dist/core/plugins/sse/{index.server.d.ts → module.server.d.ts} +0 -1
- package/dist/core/plugins/sse/{index.server.js → module.server.js} +0 -1
- package/dist/core/rime.server.d.ts +16 -16
- package/dist/fields/link/index.js +59 -56
- package/dist/fields/relation/index.js +63 -70
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/panel/context/config.svelte.d.ts +2 -2
- package/dist/panel/context/documentForm.svelte.d.ts +2 -2
- package/dist/panel/context/live.svelte.js +1 -1
- package/dist/panel/pages/auth/sign-in/SignIn.svelte +6 -1
- package/dist/server.d.ts +4 -4
- package/dist/server.js +4 -4
- package/dist/types.d.ts +1 -1
- package/package.json +2 -2
|
@@ -4,21 +4,37 @@ export type RuntimeRegistryEntry = {
|
|
|
4
4
|
};
|
|
5
5
|
export type RuntimeRegistry = Map<string, RuntimeRegistryEntry>;
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Finds an installed package's root by walking up from `fromDir`, checking each ancestor's
|
|
8
|
+
* `node_modules/<pkgName>` directly for a `package.json` — the pre-`exports` Node resolution
|
|
9
|
+
* algorithm, pure directory existence, no `exports`-conditions matching involved at all.
|
|
8
10
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
|
|
11
|
+
* Needed in place of `require.resolve`/`import.meta.resolve`: both gate on a package's own
|
|
12
|
+
* `exports` map matching some condition set (`"require"`/`"default"` for the former, whatever
|
|
13
|
+
* conditions the resolving runtime declares for the latter), and a package that only exposes
|
|
14
|
+
* conditions neither uses — confirmed in practice with rime's own `"."` export, `types`/
|
|
15
|
+
* `svelte`/`import` only, no `"require"`/`"default"` fallback — fails to resolve even its own
|
|
16
|
+
* main entry through either API. This sidesteps that entirely: `node_modules/<pkgName>` is a
|
|
17
|
+
* real directory (or, under pnpm, a real symlink `fs.existsSync` follows transparently)
|
|
18
|
+
* regardless of what that package's `exports` map declares.
|
|
19
|
+
*/
|
|
20
|
+
export declare function findInstalledPackageRoot(pkgName: string, fromDir: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Direct, single-lookup check for one `<root>/<name>/module(.server)?.ts|js` pair — no
|
|
23
|
+
* directory walk, just the two `fs.existsSync`-style checks `findModuleFile` already does.
|
|
24
|
+
* Used by the Vite plugin's `resolveId`/`load` for on-demand resolution of a `$rime/modules`
|
|
25
|
+
* self-reference; `scanModulePairs` below (a real walk) stays reserved for the barrel (which
|
|
26
|
+
* needs every pair at once) and type generation.
|
|
27
|
+
*/
|
|
28
|
+
export declare function findModulePair(root: string, name: string): RuntimeRegistryEntry | null;
|
|
29
|
+
/**
|
|
30
|
+
* Recursively finds every `module`/`module.server` folder under `root`, registered under the
|
|
31
|
+
* containing folder's path relative to `root` — e.g. `fields/relation/module.ts` under a
|
|
32
|
+
* `src/lib`-rooted scan registers as `fields/relation`. Used by the `$rime/modules` barrel
|
|
33
|
+
* (live, dev-mode only) and by `generate-manifest` (once, at prepack, scanning `dist/`).
|
|
18
34
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
35
|
+
* Either file alone is enough to register (single-sided is legitimate — a server-only piece,
|
|
36
|
+
* e.g. a collection's hooks, never needs a hand-written client stub; the missing side is just
|
|
37
|
+
* an empty string here, same convention `findModulePair` above uses). `rime.generated/` is
|
|
38
|
+
* skipped since it's sanitize's own output, unrelated to this.
|
|
23
39
|
*/
|
|
24
|
-
export declare function
|
|
40
|
+
export declare function scanModulePairs(root: string): RuntimeRegistry;
|
|
@@ -1,23 +1,33 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
4
|
-
import { isInstalledDependency, OUTPUT_DIR } from '../../constants.js';
|
|
3
|
+
import { OUTPUT_DIR } from '../../constants.js';
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* Finds an installed package's root by walking up from `fromDir`, checking each ancestor's
|
|
6
|
+
* `node_modules/<pkgName>` directly for a `package.json` — the pre-`exports` Node resolution
|
|
7
|
+
* algorithm, pure directory existence, no `exports`-conditions matching involved at all.
|
|
8
|
+
*
|
|
9
|
+
* Needed in place of `require.resolve`/`import.meta.resolve`: both gate on a package's own
|
|
10
|
+
* `exports` map matching some condition set (`"require"`/`"default"` for the former, whatever
|
|
11
|
+
* conditions the resolving runtime declares for the latter), and a package that only exposes
|
|
12
|
+
* conditions neither uses — confirmed in practice with rime's own `"."` export, `types`/
|
|
13
|
+
* `svelte`/`import` only, no `"require"`/`"default"` fallback — fails to resolve even its own
|
|
14
|
+
* main entry through either API. This sidesteps that entirely: `node_modules/<pkgName>` is a
|
|
15
|
+
* real directory (or, under pnpm, a real symlink `fs.existsSync` follows transparently)
|
|
16
|
+
* regardless of what that package's `exports` map declares.
|
|
10
17
|
*/
|
|
11
|
-
function
|
|
12
|
-
let dir =
|
|
13
|
-
while (
|
|
18
|
+
export function findInstalledPackageRoot(pkgName, fromDir) {
|
|
19
|
+
let dir = fromDir;
|
|
20
|
+
while (true) {
|
|
21
|
+
const candidate = path.join(dir, 'node_modules', pkgName);
|
|
22
|
+
if (fs.existsSync(path.join(candidate, 'package.json'))) {
|
|
23
|
+
return candidate;
|
|
24
|
+
}
|
|
14
25
|
const parent = path.dirname(dir);
|
|
15
26
|
if (parent === dir) {
|
|
16
|
-
throw new Error(`$rime: could not
|
|
27
|
+
throw new Error(`$rime/modules: could not find installed package '${pkgName}' above ${fromDir}`);
|
|
17
28
|
}
|
|
18
29
|
dir = parent;
|
|
19
30
|
}
|
|
20
|
-
return path.join(dir, 'dist');
|
|
21
31
|
}
|
|
22
32
|
/** `module.ts` when scanning TS source, `module.js` when scanning a built `dist/`. */
|
|
23
33
|
function findModuleFile(dir, baseName) {
|
|
@@ -29,16 +39,30 @@ function findModuleFile(dir, baseName) {
|
|
|
29
39
|
return null;
|
|
30
40
|
}
|
|
31
41
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* `
|
|
42
|
+
* Direct, single-lookup check for one `<root>/<name>/module(.server)?.ts|js` pair — no
|
|
43
|
+
* directory walk, just the two `fs.existsSync`-style checks `findModuleFile` already does.
|
|
44
|
+
* Used by the Vite plugin's `resolveId`/`load` for on-demand resolution of a `$rime/modules`
|
|
45
|
+
* self-reference; `scanModulePairs` below (a real walk) stays reserved for the barrel (which
|
|
46
|
+
* needs every pair at once) and type generation.
|
|
47
|
+
*/
|
|
48
|
+
export function findModulePair(root, name) {
|
|
49
|
+
const dir = path.join(root, name);
|
|
50
|
+
const client = findModuleFile(dir, 'module');
|
|
51
|
+
const server = findModuleFile(dir, 'module.server');
|
|
52
|
+
return client || server ? { client: client ?? '', server: server ?? '' } : null;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Recursively finds every `module`/`module.server` folder under `root`, registered under the
|
|
56
|
+
* containing folder's path relative to `root` — e.g. `fields/relation/module.ts` under a
|
|
57
|
+
* `src/lib`-rooted scan registers as `fields/relation`. Used by the `$rime/modules` barrel
|
|
58
|
+
* (live, dev-mode only) and by `generate-manifest` (once, at prepack, scanning `dist/`).
|
|
35
59
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
60
|
+
* Either file alone is enough to register (single-sided is legitimate — a server-only piece,
|
|
61
|
+
* e.g. a collection's hooks, never needs a hand-written client stub; the missing side is just
|
|
62
|
+
* an empty string here, same convention `findModulePair` above uses). `rime.generated/` is
|
|
63
|
+
* skipped since it's sanitize's own output, unrelated to this.
|
|
40
64
|
*/
|
|
41
|
-
function scanModulePairs(root) {
|
|
65
|
+
export function scanModulePairs(root) {
|
|
42
66
|
const registry = new Map();
|
|
43
67
|
if (!fs.existsSync(root))
|
|
44
68
|
return registry;
|
|
@@ -49,9 +73,9 @@ function scanModulePairs(root) {
|
|
|
49
73
|
const fullPath = path.join(dir, entry.name);
|
|
50
74
|
const client = findModuleFile(fullPath, 'module');
|
|
51
75
|
const server = findModuleFile(fullPath, 'module.server');
|
|
52
|
-
if (client
|
|
76
|
+
if (client || server) {
|
|
53
77
|
const key = path.relative(root, fullPath).split(path.sep).join('/');
|
|
54
|
-
registry.set(key, { client, server });
|
|
78
|
+
registry.set(key, { client: client ?? '', server: server ?? '' });
|
|
55
79
|
}
|
|
56
80
|
walk(fullPath);
|
|
57
81
|
}
|
|
@@ -59,35 +83,3 @@ function scanModulePairs(root) {
|
|
|
59
83
|
walk(root);
|
|
60
84
|
return registry;
|
|
61
85
|
}
|
|
62
|
-
/**
|
|
63
|
-
* Builds the `$rime/<name>` → { browser file, server file } lookup table.
|
|
64
|
-
*
|
|
65
|
-
* @example rime's own field, installed as a dependency in some app
|
|
66
|
-
* // /my-app/node_modules/rimecms/dist/fields/relation/module.ts + module.server.ts
|
|
67
|
-
* // → registry.get('fields/relation') → { client: '.../module.ts', server: '.../module.server.ts' }
|
|
68
|
-
* // → import { x } from '$rime/fields/relation' // resolves
|
|
69
|
-
*
|
|
70
|
-
* @example that same app's own custom field
|
|
71
|
-
* // /my-app/src/lib/fields/geocode/module.ts + module.server.ts
|
|
72
|
-
* // → registry.get('fields/geocode') → { client: '.../module.ts', server: '.../module.server.ts' }
|
|
73
|
-
* // → import { x } from '$rime/fields/geocode' // resolves, same mechanism, zero extra setup
|
|
74
|
-
*
|
|
75
|
-
* @example nothing on disk for that name
|
|
76
|
-
* // no folder anywhere has both typo/module.ts and typo/module.server.ts
|
|
77
|
-
* // → registry.get('typo') → undefined
|
|
78
|
-
* // → import { x } from '$rime/typo' // fails: "cannot resolve module"
|
|
79
|
-
*/
|
|
80
|
-
export function buildRuntimeRegistry() {
|
|
81
|
-
const registry = new Map();
|
|
82
|
-
if (isInstalledDependency(import.meta.url)) {
|
|
83
|
-
const nativeLibDir = findDistRoot(path.dirname(fileURLToPath(import.meta.url)));
|
|
84
|
-
for (const [key, entry] of scanModulePairs(nativeLibDir)) {
|
|
85
|
-
registry.set(key, entry);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
const consumerLibDir = path.resolve(process.cwd(), 'src/lib');
|
|
89
|
-
for (const [key, entry] of scanModulePairs(consumerLibDir)) {
|
|
90
|
-
registry.set(key, entry);
|
|
91
|
-
}
|
|
92
|
-
return registry;
|
|
93
|
-
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Top-level named + default export identifiers of a module — used by the Vite plugin's
|
|
3
|
+
* `exportFrom()` to stub out a side of a `$rime/<name>` pair that wasn't authored (e.g. a
|
|
4
|
+
* collection's server-only hook, requested by a client build), matching the real side's
|
|
5
|
+
* export names so ESM's static named-export binding doesn't throw at link time.
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseExportNames(filePath: string): string[];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { babelParse } from 'ast-kit';
|
|
2
|
+
import * as t from '@babel/types';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
/**
|
|
5
|
+
* Top-level named + default export identifiers of a module — used by the Vite plugin's
|
|
6
|
+
* `exportFrom()` to stub out a side of a `$rime/<name>` pair that wasn't authored (e.g. a
|
|
7
|
+
* collection's server-only hook, requested by a client build), matching the real side's
|
|
8
|
+
* export names so ESM's static named-export binding doesn't throw at link time.
|
|
9
|
+
*/
|
|
10
|
+
export function parseExportNames(filePath) {
|
|
11
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
12
|
+
const ast = babelParse(content, 'ts', { sourceType: 'module', attachComment: false });
|
|
13
|
+
const names = [];
|
|
14
|
+
for (const node of ast.body) {
|
|
15
|
+
if (t.isExportNamedDeclaration(node)) {
|
|
16
|
+
if (node.declaration) {
|
|
17
|
+
if (t.isVariableDeclaration(node.declaration)) {
|
|
18
|
+
for (const decl of node.declaration.declarations) {
|
|
19
|
+
if (t.isIdentifier(decl.id))
|
|
20
|
+
names.push(decl.id.name);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else if ('id' in node.declaration &&
|
|
24
|
+
node.declaration.id &&
|
|
25
|
+
t.isIdentifier(node.declaration.id)) {
|
|
26
|
+
names.push(node.declaration.id.name);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
for (const spec of node.specifiers) {
|
|
30
|
+
if (t.isExportSpecifier(spec) && t.isIdentifier(spec.exported)) {
|
|
31
|
+
names.push(spec.exported.name);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (t.isExportDefaultDeclaration(node)) {
|
|
36
|
+
names.push('default');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return names;
|
|
40
|
+
}
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* $ prefix-based sanitizer that rules:
|
|
3
|
-
* - All server-only config properties begin with $ (e.g., $url, $hooks)
|
|
4
|
-
* - All server-only field methods begin with $ (e.g., $beforeSave, $beforeRead)
|
|
5
|
-
* - Content must be pure functions or imports from .server.ts files
|
|
6
|
-
* - Outputs to .generated folder, preserving original folder structure
|
|
7
|
-
*/
|
|
8
1
|
export function sanitize(): Promise<void>;
|
|
9
2
|
/**
|
|
10
3
|
* Updates imports in server files to use server versions of split modules
|
|
@@ -15,6 +15,11 @@ import { INPUT_DIR, OUTPUT_DIR } from '../../constants.js';
|
|
|
15
15
|
* - Outputs to .generated folder, preserving original folder structure
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
// The top-level config — real, hand-authored. Unlike every other .server.ts file under
|
|
19
|
+
// +rime/ (copied verbatim, server-only, no client counterpart needed), this one always needs
|
|
20
|
+
// a sanitized client copy too — the panel still needs +rime.generated/rime.config.ts.
|
|
21
|
+
const TOP_LEVEL_CONFIG = 'rime.config.server.ts';
|
|
22
|
+
|
|
18
23
|
export async function sanitize() {
|
|
19
24
|
const root = process.cwd();
|
|
20
25
|
const configDir = path.resolve(root, 'src/lib/', INPUT_DIR);
|
|
@@ -66,12 +71,22 @@ export async function sanitize() {
|
|
|
66
71
|
}
|
|
67
72
|
}
|
|
68
73
|
|
|
69
|
-
// Also scan and copy all existing .server.ts files
|
|
70
|
-
|
|
74
|
+
// Also scan and copy all existing .server.ts files — except the top-level config, which
|
|
75
|
+
// gets its own client+server split below instead of a plain verbatim copy.
|
|
76
|
+
const serverFiles = (await scanServerFiles(configDir)).filter(
|
|
77
|
+
(filePath) => path.relative(configDir, filePath) !== TOP_LEVEL_CONFIG
|
|
78
|
+
);
|
|
71
79
|
|
|
72
80
|
// Scan and copy all other files (non-.ts files like .svelte, .json, etc.)
|
|
73
81
|
const otherFiles = await scanOtherFiles(configDir);
|
|
74
82
|
|
|
83
|
+
// Top-level config split: same client/server treatment as every other split file below,
|
|
84
|
+
// just addressed by its fixed name instead of found via the scan (it's .server.ts-suffixed,
|
|
85
|
+
// so scanConfigFiles/allFiles never sees it). Runs after the pre-scan above so splitFiles is
|
|
86
|
+
// fully populated — this file's own `import { Pages } from './pages'`-style imports need to
|
|
87
|
+
// know which nested files themselves got split.
|
|
88
|
+
await processTopLevelConfig(configDir, outputDir, outputFiles, splitFiles);
|
|
89
|
+
|
|
75
90
|
for (const filePath of allFiles) {
|
|
76
91
|
const relativePath = path.relative(configDir, filePath);
|
|
77
92
|
logger.debug(` Processing: ${relativePath}`);
|
|
@@ -130,10 +145,13 @@ export async function sanitize() {
|
|
|
130
145
|
}
|
|
131
146
|
}
|
|
132
147
|
|
|
133
|
-
// Delete files that exist in current list but not in output list
|
|
148
|
+
// Delete files that exist in current list but not in output list. schema.server.ts is
|
|
149
|
+
// excluded — write.server.ts owns it (writes it straight into OUTPUT_DIR, see schemaPath()
|
|
150
|
+
// in constants.ts), sanitize() never adds it to outputFiles, so without this exclusion
|
|
151
|
+
// every sanitize run deletes it out from under write()'s own cache guard.
|
|
152
|
+
const SCHEMA_FILE = 'schema.server.ts';
|
|
134
153
|
for (const existingFile of existingFiles) {
|
|
135
|
-
|
|
136
|
-
if (!outputFiles.has(existingFile) && existingFile !== 'schema.server.ts') {
|
|
154
|
+
if (existingFile !== SCHEMA_FILE && !outputFiles.has(existingFile)) {
|
|
137
155
|
const fileToDelete = path.join(outputDir, existingFile);
|
|
138
156
|
fs.unlinkSync(fileToDelete);
|
|
139
157
|
logger.debug(` Deleted: ${existingFile}`);
|
|
@@ -143,6 +161,40 @@ export async function sanitize() {
|
|
|
143
161
|
logger.info('Sanitization complete');
|
|
144
162
|
}
|
|
145
163
|
|
|
164
|
+
/**
|
|
165
|
+
* The top-level config (src/lib/+rime/rime.config.server.ts) — real, hand-authored. Client
|
|
166
|
+
* copy via analyzeFile + sanitizeClientAst + removeUnusedImports, written into
|
|
167
|
+
* +rime.generated/, plus a server copy via updateServerImports so its own imports of nested
|
|
168
|
+
* split files resolve like every other split file's do.
|
|
169
|
+
*/
|
|
170
|
+
async function processTopLevelConfig(configDir, outputDir, outputFiles, splitFiles) {
|
|
171
|
+
const sourcePath = path.join(configDir, TOP_LEVEL_CONFIG);
|
|
172
|
+
if (!fs.existsSync(sourcePath)) return; // ensureUserConfigExist() already guards this
|
|
173
|
+
|
|
174
|
+
const content = fs.readFileSync(sourcePath, 'utf-8');
|
|
175
|
+
const ast = babelParse(content, 'ts', { sourceType: 'module', attachComment: false });
|
|
176
|
+
const analysis = analyzeFile(ast);
|
|
177
|
+
|
|
178
|
+
const clientPath = path.join(outputDir, 'rime.config.ts');
|
|
179
|
+
const serverPath = path.join(outputDir, TOP_LEVEL_CONFIG);
|
|
180
|
+
outputFiles.add(path.relative(outputDir, clientPath));
|
|
181
|
+
outputFiles.add(path.relative(outputDir, serverPath));
|
|
182
|
+
|
|
183
|
+
const clientAst = sanitizeClientAst(ast, analysis);
|
|
184
|
+
const cleanedAst = removeUnusedImports(clientAst);
|
|
185
|
+
const clientCode = generate(cleanedAst, { compact: false, comments: true }).code;
|
|
186
|
+
if (shouldWriteFile(clientPath, clientCode)) {
|
|
187
|
+
fs.writeFileSync(clientPath, clientCode);
|
|
188
|
+
logger.debug(` Sanitized: rime.config.ts`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const serverContent = updateServerImports(content, splitFiles, '.');
|
|
192
|
+
if (shouldWriteFile(serverPath, serverContent)) {
|
|
193
|
+
fs.writeFileSync(serverPath, serverContent);
|
|
194
|
+
logger.debug(` Created: ${TOP_LEVEL_CONFIG}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
146
198
|
async function scanConfigFiles(configDir) {
|
|
147
199
|
const files = [];
|
|
148
200
|
|
|
@@ -13,7 +13,6 @@ import { capitalize, toPascalCase } from '../../../../util/string.js';
|
|
|
13
13
|
import fs from 'node:fs';
|
|
14
14
|
import path from 'node:path';
|
|
15
15
|
import { isInstalledDependency, OUTPUT_DIR } from '../../constants.js';
|
|
16
|
-
import { buildRuntimeRegistry } from '../runtime/index.server.js';
|
|
17
16
|
const IS_RIME_REPO = !isInstalledDependency(import.meta.url);
|
|
18
17
|
// Relation type
|
|
19
18
|
const relationValueType = `
|
|
@@ -114,43 +113,20 @@ const templateDeclareVirtualModule = () => [
|
|
|
114
113
|
`\texport * from '${PACKAGE_NAME}/config/server';`,
|
|
115
114
|
`}`,
|
|
116
115
|
`declare module '$rime/schema' {`,
|
|
117
|
-
`\texport * from '$lib
|
|
118
|
-
`}
|
|
119
|
-
|
|
116
|
+
`\texport * from '$lib/rime.schema.server.js';`,
|
|
117
|
+
`}`
|
|
118
|
+
// $rime/modules (the bare barrel) is typed by src/rime.modules.generated.d.ts instead —
|
|
119
|
+
// written directly by the Vite plugin's own dev-server watcher (regenerateModulesDeclaration
|
|
120
|
+
// in core/dev/vite/index.server.ts), not here, since it needs to react to module.(server.)ts
|
|
121
|
+
// files appearing/changing on their own, independent of a config regen.
|
|
122
|
+
//
|
|
123
|
+
// A package's own qualified $rime/modules/<pkg>/<path> references are self-contained —
|
|
124
|
+
// generate-manifest inserts a /// <reference> directly into each rewritten .d.ts file at
|
|
125
|
+
// prepack (see generate-manifest/index.server.ts), so this app never needs to know which
|
|
126
|
+
// installed packages exist or eagerly reference all of them; verified directly (a real tsc
|
|
127
|
+
// run resolves it correctly from a file two levels deep inside node_modules, zero consumer
|
|
128
|
+
// awareness needed).
|
|
120
129
|
].join('\n');
|
|
121
|
-
/**
|
|
122
|
-
* One `declare module '$rime/<name>'` per registered field module.ts + module.server.ts pair
|
|
123
|
-
* (rime-native and consumer-local alike — see buildRuntimeRegistry), sourced from the
|
|
124
|
-
* `.server.ts` side (the real, server-only implementation of the shared hook; the client
|
|
125
|
-
* module.ts only has the no-op). Unrelated to type generation itself — that goes through
|
|
126
|
-
* `field.use.generateType()` on the builder instance directly, not through this registry.
|
|
127
|
-
* Runtime resolution (the Vite plugin's `load()`) is unaffected either way — it still picks
|
|
128
|
-
* the real client-vs-server module dynamically based on build context.
|
|
129
|
-
*/
|
|
130
|
-
const templateDeclareFieldModules = () => {
|
|
131
|
-
const registry = buildRuntimeRegistry();
|
|
132
|
-
return Array.from(registry.entries()).map(([name, entry]) => {
|
|
133
|
-
const modulePath = toModuleSpecifier(entry.server);
|
|
134
|
-
return `declare module '$rime/${name}' {\n\texport * from '${modulePath}';\n}`;
|
|
135
|
-
});
|
|
136
|
-
};
|
|
137
|
-
/**
|
|
138
|
-
* `$lib/...` when the file is inside this app's own src/lib (true for a consumer's own custom
|
|
139
|
-
* field, and for rime's own fields when developing rime itself, since they live inside src/lib
|
|
140
|
-
* in that case too) — matches the `$rime/schema` declaration above, and stays readable/portable
|
|
141
|
-
* instead of an absolute path. Falls back to an absolute path only when there's genuinely no
|
|
142
|
-
* alias for it: rime's own fields when installed as a real dependency, living in
|
|
143
|
-
* node_modules/rimecms/dist/, outside this app's src/lib entirely.
|
|
144
|
-
*/
|
|
145
|
-
function toModuleSpecifier(serverPath) {
|
|
146
|
-
const libRoot = path.resolve(process.cwd(), 'src/lib');
|
|
147
|
-
const jsPath = serverPath.replace(/\.ts$/, '.js');
|
|
148
|
-
const relative = path.relative(libRoot, jsPath);
|
|
149
|
-
if (!relative.startsWith('..')) {
|
|
150
|
-
return `$lib/${relative.split(path.sep).join('/')}`;
|
|
151
|
-
}
|
|
152
|
-
return jsPath;
|
|
153
|
-
}
|
|
154
130
|
/**
|
|
155
131
|
* Generates type definitions for image sizes
|
|
156
132
|
* @returns A string containing the type definition for image sizes
|
|
@@ -283,6 +259,7 @@ export async function generateTypesString(config) {
|
|
|
283
259
|
const blocksTypeNames = `export type BlockTypes = ${registeredBlocks.map((name) => `'${name}'`).join('|')}\n`;
|
|
284
260
|
const anyBlock = `export type AnyBlock = ${registeredBlocks.map((name) => `Block${toPascalCase(name)}`).join('|')}\n`;
|
|
285
261
|
const typeImports = `import type { ${Array.from(imports).join(', ')} } from '${PACKAGE_NAME}/types'`;
|
|
262
|
+
const rimeConfigServerPath = `./lib/${OUTPUT_DIR}/rime.config.server.ts`;
|
|
286
263
|
const locals = `declare global {
|
|
287
264
|
namespace App {
|
|
288
265
|
interface Locals {
|
|
@@ -316,7 +293,7 @@ export async function generateTypesString(config) {
|
|
|
316
293
|
/** Singleton providing access to auth, config and local-api */
|
|
317
294
|
rime: ReturnType<
|
|
318
295
|
Awaited<
|
|
319
|
-
typeof import('
|
|
296
|
+
typeof import('${rimeConfigServerPath}').default
|
|
320
297
|
>['createRimeContext']
|
|
321
298
|
>;
|
|
322
299
|
/** Flag enabled by the core plugin rime.cache when the API cache is ON */
|
|
@@ -381,7 +358,7 @@ function write(key, content, filePath) {
|
|
|
381
358
|
*/
|
|
382
359
|
async function generateTypes(config) {
|
|
383
360
|
const mainTypes = await generateTypesString(config);
|
|
384
|
-
const declarations =
|
|
361
|
+
const declarations = templateDeclareVirtualModule();
|
|
385
362
|
const appGeneratedPath = path.resolve(process.cwd(), 'src', 'app.generated.d.ts');
|
|
386
363
|
const virtualModuleGeneratedPath = path.resolve(process.cwd(), 'src', 'rime.generated.d.ts');
|
|
387
364
|
write('app.generated', mainTypes, appGeneratedPath);
|