@fecommunity/reactpress-toolkit 3.1.0 → 4.0.0-beta.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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/dist/.source-fingerprint-toolkit +1 -0
  3. package/dist/app/createReactPressApp.d.ts +4 -84
  4. package/dist/app/createReactPressApp.js +3 -0
  5. package/dist/app/createThemeApp.d.ts +8 -6
  6. package/dist/app/createThemeApp.js +5 -1
  7. package/dist/plugin/admin/index.d.ts +2 -0
  8. package/dist/plugin/admin/index.js +2 -0
  9. package/dist/plugin/admin/plugin-admin.d.ts +43 -0
  10. package/dist/plugin/admin/plugin-admin.js +41 -0
  11. package/dist/plugin/admin/slots.d.ts +36 -0
  12. package/dist/plugin/admin/slots.js +16 -0
  13. package/dist/plugin/client/runtime.d.ts +6 -1
  14. package/dist/plugin/extension/index.d.ts +4 -0
  15. package/dist/plugin/extension/index.js +20 -0
  16. package/dist/plugin/extension/plugin-admin-locale.d.ts +21 -0
  17. package/dist/plugin/extension/plugin-admin-locale.io.d.ts +2 -0
  18. package/dist/plugin/extension/plugin-admin-locale.io.js +54 -0
  19. package/dist/plugin/extension/plugin-admin-locale.js +60 -0
  20. package/dist/plugin/extension/plugin.d.ts +82 -0
  21. package/dist/plugin/extension/plugin.js +146 -0
  22. package/dist/plugin/extension/security.d.ts +7 -0
  23. package/dist/plugin/extension/security.js +74 -0
  24. package/dist/plugin/extension/validate.d.ts +8 -0
  25. package/dist/plugin/extension/validate.js +55 -0
  26. package/dist/plugin/index.d.ts +4 -0
  27. package/dist/plugin/index.js +5 -1
  28. package/dist/plugin/node.d.ts +2 -0
  29. package/dist/plugin/node.js +6 -0
  30. package/dist/plugin/react/index.d.ts +1 -0
  31. package/dist/plugin/react/index.js +1 -0
  32. package/dist/plugin/react/plugin-admin-ui.d.ts +23 -0
  33. package/dist/plugin/react/plugin-admin-ui.js +38 -0
  34. package/dist/plugin/server/hook-reject.d.ts +12 -0
  35. package/dist/plugin/server/hook-reject.js +39 -0
  36. package/dist/plugin/server/index.d.ts +2 -0
  37. package/dist/plugin/server/index.js +18 -0
  38. package/dist/plugin/server/types.d.ts +34 -0
  39. package/dist/plugin/server/types.js +3 -0
  40. package/dist/theme/build/next-config.d.ts +4 -6
  41. package/dist/theme/build/next-config.js +0 -37
  42. package/dist/theme/build/node.d.ts +1 -1
  43. package/dist/theme/build/node.js +1 -1
  44. package/dist/theme/content/assets.js +33 -1
  45. package/dist/theme/extension/theme.d.ts +1 -1
  46. package/dist/theme/extension/theme.js +1 -1
  47. package/dist/theme/ssr/fetch.d.ts +3 -0
  48. package/dist/theme/ssr/pageProps.d.ts +5 -4
  49. package/dist/theme/ssr/pageProps.js +20 -3
  50. package/dist/theme/ssr/setting.d.ts +1 -0
  51. package/dist/theme/ssr/setting.js +3 -0
  52. package/dist/theme/ssr/templates.js +1 -1
  53. package/dist/types/index.d.ts +3 -0
  54. package/dist/ui/components/SiteAnalytics.d.ts +1 -1
  55. package/package.json +43 -15
@@ -10,9 +10,18 @@ const PUBLIC_PATH_ALIASES = {
10
10
  '/favicon.png': '/public/favicon.png',
11
11
  '/favicon.ico': '/public/favicon.ico',
12
12
  };
13
+ /** Theme Next rewrites serve alias keys (e.g. `/logo.png`), not `/public/*` API paths. */
14
+ const THEME_LOCAL_PUBLIC_PATHS = Object.fromEntries(Object.entries(PUBLIC_PATH_ALIASES).map(([themePath, apiPath]) => [apiPath, themePath]));
13
15
  function normalizePublicAssetPath(path) {
14
16
  return PUBLIC_PATH_ALIASES[path] ?? path;
15
17
  }
18
+ function toThemeServablePath(apiPath) {
19
+ return THEME_LOCAL_PUBLIC_PATHS[apiPath] ?? apiPath;
20
+ }
21
+ /** Paths proxied by theme `next.config` rewrites — keep relative, never bake absolute API URLs. */
22
+ function isThemeRewritePath(path) {
23
+ return path in THEME_LOCAL_PUBLIC_PATHS || path.startsWith('/public/') || path.startsWith('/uploads/');
24
+ }
16
25
  /** Whether a configured asset path is likely to resolve (skip broken defaults like `/logo.png`). */
17
26
  function isLikelyValidAssetPath(url) {
18
27
  const trimmed = (url ?? '').trim();
@@ -44,6 +53,26 @@ function resolvePublicSiteOrigin() {
44
53
  'http://localhost:3002/api';
45
54
  return serverApi.replace(/\/api\/?$/, '').replace(/\/$/, '');
46
55
  }
56
+ /** Visitor site origin — differs from API origin during SSR (theme :3001 vs API :3002). */
57
+ function resolveThemeSiteOrigin() {
58
+ if (typeof window !== 'undefined') {
59
+ return window.location.origin;
60
+ }
61
+ const clientSite = process.env.CLIENT_SITE_URL?.trim();
62
+ if (clientSite) {
63
+ try {
64
+ return new URL(clientSite).origin;
65
+ }
66
+ catch {
67
+ return clientSite.replace(/\/$/, '');
68
+ }
69
+ }
70
+ const clientPort = process.env.CLIENT_PORT?.trim() || process.env.PORT?.trim();
71
+ if (clientPort) {
72
+ return `http://127.0.0.1:${clientPort}`;
73
+ }
74
+ return resolvePublicSiteOrigin();
75
+ }
47
76
  /** Resolve media / logo URLs for theme pages. */
48
77
  function resolvePublicAssetUrl(url) {
49
78
  const trimmed = (url ?? '').trim();
@@ -57,8 +86,11 @@ function resolvePublicAssetUrl(url) {
57
86
  }
58
87
  if (trimmed.startsWith('/')) {
59
88
  const normalized = normalizePublicAssetPath(trimmed);
89
+ if (isThemeRewritePath(normalized)) {
90
+ return toThemeServablePath(normalized);
91
+ }
60
92
  const origin = resolvePublicSiteOrigin();
61
- const themeOrigin = typeof window !== 'undefined' ? window.location.origin : origin;
93
+ const themeOrigin = resolveThemeSiteOrigin();
62
94
  if (origin === themeOrigin) {
63
95
  return normalized;
64
96
  }
@@ -71,7 +71,7 @@ export interface SiteThemeState {
71
71
  mods: Record<string, ThemeMods>;
72
72
  previewThemeId?: string;
73
73
  }
74
- export declare const DEFAULT_ACTIVE_THEME = "twentytwentyfive";
74
+ export declare const DEFAULT_ACTIVE_THEME = "hello-world";
75
75
  export declare const defaultSiteThemeState: SiteThemeState;
76
76
  export interface GlobalSettingWithTheme {
77
77
  zh?: unknown;
@@ -19,7 +19,7 @@ Object.defineProperty(exports, "appearancePrimaryColorForMode", { enumerable: tr
19
19
  function appearancePrimaryColor(mods, fallback = '#f44336') {
20
20
  return (0, twentytwentyfive_vars_1.appearancePrimaryColorForMode)(mods, false, fallback);
21
21
  }
22
- exports.DEFAULT_ACTIVE_THEME = 'twentytwentyfive';
22
+ exports.DEFAULT_ACTIVE_THEME = 'hello-world';
23
23
  exports.defaultSiteThemeState = {
24
24
  activeTheme: exports.DEFAULT_ACTIVE_THEME,
25
25
  installedThemes: [exports.DEFAULT_ACTIVE_THEME],
@@ -73,7 +73,10 @@ export declare function fetchTagArchive(api: ThemeApi, tag: string): Promise<{
73
73
  export type ThemeArticlePage = {
74
74
  id: string;
75
75
  title: string;
76
+ slug?: string;
76
77
  summary?: string;
78
+ seoDescription?: string;
79
+ seoKeywords?: string;
77
80
  html?: string;
78
81
  cover?: string;
79
82
  publishAt?: string;
@@ -1,7 +1,7 @@
1
1
  import type { ThemeApi } from '../api/api';
2
2
  import { type CarouselArticle, type ListArticle } from '../content/articleSlim';
3
3
  import { type ArchiveTree } from '../content/archiveSlim';
4
- import type { IArticle, ICategory, IKnowledge, ITag } from '../../types';
4
+ import type { IArticle, ICategory, IKnowledge, IPage, ITag } from '../../types';
5
5
  export type HomePageProps = {
6
6
  articles: ListArticle[];
7
7
  total: number;
@@ -52,9 +52,10 @@ export declare function fetchKnowledgeChapterPageProps(api: ThemeApi, pId: strin
52
52
  }>;
53
53
  /** Site search results for `/search?keyword=`. */
54
54
  export declare function fetchSearchPageProps(api: ThemeApi, keyword: string): Promise<SearchPageProps>;
55
- /** CMS static page by id. */
56
- export declare function fetchCmsPageProps(api: ThemeApi, id: string): Promise<{
57
- page: unknown;
55
+ export type CmsPageProps = Pick<IPage, 'id' | 'name' | 'path' | 'html' | 'toc' | 'status' | 'publishAt' | 'views'>;
56
+ /** CMS static page by id or path slug (admin → 页面). */
57
+ export declare function fetchCmsPageProps(api: ThemeApi, idOrPath: string | undefined): Promise<{
58
+ page: CmsPageProps | null;
58
59
  }>;
59
60
  /** Single article by id (full entity from API). */
60
61
  export declare function fetchArticleDetailProps(api: ThemeApi, id: string): Promise<{
@@ -15,6 +15,7 @@ const api_data_1 = require("../api/api-data");
15
15
  const articleSlim_1 = require("../content/articleSlim");
16
16
  const archiveSlim_1 = require("../content/archiveSlim");
17
17
  const carouselArticles_1 = require("../content/carouselArticles");
18
+ const assets_1 = require("../content/assets");
18
19
  const fetch_1 = require("./fetch");
19
20
  const DEFAULT_PAGE_SIZE = 12;
20
21
  function fallbackCategory(value) {
@@ -128,9 +129,25 @@ async function fetchSearchPageProps(api, keyword) {
128
129
  const articles = (0, api_data_1.unpackList)(response).filter((article) => article.status === 'publish');
129
130
  return { keyword: trimmed, articles };
130
131
  }
131
- /** CMS static page by id. */
132
- async function fetchCmsPageProps(api, id) {
133
- return { page: (0, api_data_1.unpackOne)(await api.page.findById(id)) };
132
+ /** CMS static page by id or path slug (admin → 页面). */
133
+ async function fetchCmsPageProps(api, idOrPath) {
134
+ if (!idOrPath?.trim())
135
+ return { page: null };
136
+ const raw = (0, api_data_1.unpackOne)(await api.page.findById(idOrPath.trim()));
137
+ if (!raw || raw.status !== 'publish')
138
+ return { page: null };
139
+ return {
140
+ page: {
141
+ id: raw.id,
142
+ name: raw.name,
143
+ path: raw.path,
144
+ html: raw.html ? (0, assets_1.rewriteArticleHtmlAssets)(raw.html) : raw.html,
145
+ toc: raw.toc,
146
+ status: raw.status,
147
+ publishAt: raw.publishAt,
148
+ views: raw.views,
149
+ },
150
+ };
134
151
  }
135
152
  /** Single article by id (full entity from API). */
136
153
  async function fetchArticleDetailProps(api, id) {
@@ -3,6 +3,7 @@ export declare function unwrapSetting(response: unknown): Record<string, unknown
3
3
  export interface SiteMeta {
4
4
  siteName: string;
5
5
  siteDescription: string;
6
+ siteKeywords?: string;
6
7
  siteUrl?: string;
7
8
  siteLogo?: string;
8
9
  siteFavicon?: string;
@@ -31,6 +31,9 @@ function parseSiteMeta(row) {
31
31
  siteName: String(row.systemTitle ?? 'ReactPress Site').trim() || exports.DEFAULT_SITE_META.siteName,
32
32
  siteDescription: String(row.systemSubTitle ?? exports.DEFAULT_SITE_META.siteDescription).trim() ||
33
33
  exports.DEFAULT_SITE_META.siteDescription,
34
+ siteKeywords: row.seoKeyword != null && String(row.seoKeyword).trim()
35
+ ? String(row.seoKeyword).trim()
36
+ : undefined,
34
37
  siteUrl: row.systemUrl != null ? String(row.systemUrl).trim() || undefined : undefined,
35
38
  siteLogo: row.systemLogo != null && String(row.systemLogo).trim()
36
39
  ? String(row.systemLogo).trim()
@@ -34,7 +34,7 @@ exports.ThemeTemplate = {
34
34
  exports.DEFAULT_TEMPLATE_FILES = {
35
35
  [exports.ThemeTemplate.HOME]: 'pages/index.tsx',
36
36
  [exports.ThemeTemplate.SINGLE]: 'pages/article/[id].tsx',
37
- [exports.ThemeTemplate.PAGE]: 'pages/about.tsx',
37
+ [exports.ThemeTemplate.PAGE]: 'pages/[path].tsx',
38
38
  [exports.ThemeTemplate.ARCHIVE_CATEGORY]: 'pages/category/[category].tsx',
39
39
  [exports.ThemeTemplate.ARCHIVE_TAG]: 'pages/tag/[tag].tsx',
40
40
  [exports.ThemeTemplate.SEARCH]: 'pages/search.tsx',
@@ -94,6 +94,9 @@ export interface IArticle {
94
94
  title: string;
95
95
  cover: string;
96
96
  summary: string;
97
+ slug?: string | null;
98
+ seoKeywords?: string | null;
99
+ seoDescription?: string | null;
97
100
  content: string;
98
101
  html: string;
99
102
  toc: string;
@@ -2,4 +2,4 @@ export interface SiteAnalyticsProps {
2
2
  children?: React.ReactNode;
3
3
  }
4
4
  /** Inject Google Analytics / Baidu Tongji scripts from site settings. */
5
- export declare function SiteAnalytics({ children }: SiteAnalyticsProps): string | number | boolean | import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | Iterable<import("react").ReactNode> | import("react").ReactPortal | null;
5
+ export declare function SiteAnalytics({ children }: SiteAnalyticsProps): string | number | bigint | boolean | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<import("react").ReactNode> | import("react").ReactPortal | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<import("react").ReactNode> | null | undefined> | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fecommunity/reactpress-toolkit",
3
- "version": "3.1.0",
3
+ "version": "4.0.0-beta.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "exports": {
@@ -79,6 +79,18 @@
79
79
  "./plugin/dev": {
80
80
  "types": "./dist/plugin/dev/index.d.ts",
81
81
  "default": "./dist/plugin/dev/index.js"
82
+ },
83
+ "./plugin/extension": {
84
+ "types": "./dist/plugin/extension/index.d.ts",
85
+ "default": "./dist/plugin/extension/index.js"
86
+ },
87
+ "./plugin/server": {
88
+ "types": "./dist/plugin/server/index.d.ts",
89
+ "default": "./dist/plugin/server/index.js"
90
+ },
91
+ "./plugin/node": {
92
+ "types": "./dist/plugin/node.d.ts",
93
+ "default": "./dist/plugin/node.js"
82
94
  }
83
95
  },
84
96
  "peerDependencies": {
@@ -92,19 +104,30 @@
92
104
  "viewerjs": ">=1"
93
105
  },
94
106
  "peerDependenciesMeta": {
95
- "@tanstack/react-query": { "optional": true },
96
- "@ant-design/cssinjs": { "optional": true },
97
- "highlight.js": { "optional": true },
98
- "next": { "optional": true },
99
- "nprogress": { "optional": true },
100
- "react": { "optional": true },
101
- "react-dom": { "optional": true },
102
- "viewerjs": { "optional": true }
103
- },
104
- "scripts": {
105
- "generate": "node scripts/generate-swagger.js",
106
- "build": "tsc && rm -rf dist/config/locales && cp -r src/config/locales dist/config/locales",
107
- "typecheck": "tsc --noEmit"
107
+ "@tanstack/react-query": {
108
+ "optional": true
109
+ },
110
+ "@ant-design/cssinjs": {
111
+ "optional": true
112
+ },
113
+ "highlight.js": {
114
+ "optional": true
115
+ },
116
+ "next": {
117
+ "optional": true
118
+ },
119
+ "nprogress": {
120
+ "optional": true
121
+ },
122
+ "react": {
123
+ "optional": true
124
+ },
125
+ "react-dom": {
126
+ "optional": true
127
+ },
128
+ "viewerjs": {
129
+ "optional": true
130
+ }
108
131
  },
109
132
  "files": [
110
133
  "dist"
@@ -145,5 +168,10 @@
145
168
  "react": "^18.3.1",
146
169
  "react-dom": "^18.3.1",
147
170
  "typescript": "^5.7.3"
171
+ },
172
+ "scripts": {
173
+ "generate": "node scripts/generate-swagger.js",
174
+ "build": "tsc && rm -rf dist/config/locales && cp -r src/config/locales dist/config/locales",
175
+ "typecheck": "tsc --noEmit"
148
176
  }
149
- }
177
+ }