@geekron/hono 0.0.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 +176 -0
- package/dist/contract.d.ts +5 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +4 -0
- package/dist/route/index.d.ts +5 -0
- package/dist/route/index.d.ts.map +1 -0
- package/dist/route/index.js +4 -0
- package/dist/route/interfaces.d.ts +35 -0
- package/dist/route/interfaces.d.ts.map +1 -0
- package/dist/route/interfaces.js +1 -0
- package/dist/route/methods.d.ts +13 -0
- package/dist/route/methods.d.ts.map +1 -0
- package/dist/route/methods.js +79 -0
- package/dist/route/setup.d.ts +18 -0
- package/dist/route/setup.d.ts.map +1 -0
- package/dist/route/setup.js +11 -0
- package/dist/route/slot.d.ts +15 -0
- package/dist/route/slot.d.ts.map +1 -0
- package/dist/route/slot.js +28 -0
- package/dist/strapi/cms/cms.d.ts +17 -0
- package/dist/strapi/cms/cms.d.ts.map +1 -0
- package/dist/strapi/cms/cms.js +57 -0
- package/dist/strapi/cms/common.d.ts +9 -0
- package/dist/strapi/cms/common.d.ts.map +1 -0
- package/dist/strapi/cms/common.js +30 -0
- package/dist/strapi/cms/components.d.ts +20 -0
- package/dist/strapi/cms/components.d.ts.map +1 -0
- package/dist/strapi/cms/components.js +33 -0
- package/dist/strapi/cms/content-types.d.ts +48 -0
- package/dist/strapi/cms/content-types.d.ts.map +1 -0
- package/dist/strapi/cms/content-types.js +49 -0
- package/dist/strapi/cms/index.d.ts +10 -0
- package/dist/strapi/cms/index.d.ts.map +1 -0
- package/dist/strapi/cms/index.js +9 -0
- package/dist/strapi/cms/locales.d.ts +16 -0
- package/dist/strapi/cms/locales.d.ts.map +1 -0
- package/dist/strapi/cms/locales.js +33 -0
- package/dist/strapi/cms/menu.d.ts +19 -0
- package/dist/strapi/cms/menu.d.ts.map +1 -0
- package/dist/strapi/cms/menu.js +80 -0
- package/dist/strapi/cms/setup.d.ts +11 -0
- package/dist/strapi/cms/setup.d.ts.map +1 -0
- package/dist/strapi/cms/setup.js +25 -0
- package/dist/strapi/cms/site.d.ts +9 -0
- package/dist/strapi/cms/site.d.ts.map +1 -0
- package/dist/strapi/cms/site.js +30 -0
- package/dist/strapi/cms/translations.d.ts +25 -0
- package/dist/strapi/cms/translations.d.ts.map +1 -0
- package/dist/strapi/cms/translations.js +38 -0
- package/dist/strapi/index.d.ts +5 -0
- package/dist/strapi/index.d.ts.map +1 -0
- package/dist/strapi/index.js +4 -0
- package/dist/strapi/interfaces/index.d.ts +2 -0
- package/dist/strapi/interfaces/index.d.ts.map +1 -0
- package/dist/strapi/interfaces/index.js +1 -0
- package/dist/strapi/interfaces/media.d.ts +42 -0
- package/dist/strapi/interfaces/media.d.ts.map +1 -0
- package/dist/strapi/interfaces/media.js +1 -0
- package/dist/strapi/route.d.ts +3 -0
- package/dist/strapi/route.d.ts.map +1 -0
- package/dist/strapi/route.js +61 -0
- package/dist/strapi/utils/fileTitle.d.ts +3 -0
- package/dist/strapi/utils/fileTitle.d.ts.map +1 -0
- package/dist/strapi/utils/fileTitle.js +3 -0
- package/dist/strapi/utils/fileUrl.d.ts +3 -0
- package/dist/strapi/utils/fileUrl.d.ts.map +1 -0
- package/dist/strapi/utils/fileUrl.js +4 -0
- package/dist/strapi/utils/imgAlt.d.ts +3 -0
- package/dist/strapi/utils/imgAlt.d.ts.map +1 -0
- package/dist/strapi/utils/imgAlt.js +3 -0
- package/dist/strapi/utils/imgInfo.d.ts +9 -0
- package/dist/strapi/utils/imgInfo.d.ts.map +1 -0
- package/dist/strapi/utils/imgInfo.js +13 -0
- package/dist/strapi/utils/imgSrc.d.ts +8 -0
- package/dist/strapi/utils/imgSrc.d.ts.map +1 -0
- package/dist/strapi/utils/imgSrc.js +17 -0
- package/dist/strapi/utils/index.d.ts +7 -0
- package/dist/strapi/utils/index.d.ts.map +1 -0
- package/dist/strapi/utils/index.js +6 -0
- package/dist/strapi/utils/resource.d.ts +7 -0
- package/dist/strapi/utils/resource.d.ts.map +1 -0
- package/dist/strapi/utils/resource.js +17 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# @geekron/hono
|
|
2
|
+
|
|
3
|
+
一个基于 Hono 和 Strapi 的 CMS SDK,提供路由管理和 Strapi 集成功能。
|
|
4
|
+
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- 🚀 基于 [Hono](https://hono.dev/) 的高性能路由系统
|
|
8
|
+
- 📦 与 [Strapi](https://strapi.io/) 深度集成
|
|
9
|
+
- 🛠️ TypeScript 支持
|
|
10
|
+
- 🔧 灵活的路由配置
|
|
11
|
+
- 🌐 多语言支持
|
|
12
|
+
- 📝 内容类型管理
|
|
13
|
+
- 🎨 组件化开发
|
|
14
|
+
|
|
15
|
+
## 安装
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bun install @geekron/hono
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 环境配置
|
|
22
|
+
|
|
23
|
+
在项目根目录创建 `.env` 文件:
|
|
24
|
+
|
|
25
|
+
```env
|
|
26
|
+
CMS_URL=http://localhost:1337
|
|
27
|
+
CMS_TOKEN=your_strapi_api_token
|
|
28
|
+
MEDIA_URL=http://localhost:1337 # 可选,默认使用 CMS_URL
|
|
29
|
+
URL_SUFFIX=.html # 可选,默认为 .html
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 使用方式
|
|
33
|
+
|
|
34
|
+
### 导入模块
|
|
35
|
+
|
|
36
|
+
项目提供两个主要模块:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// 导入 Strapi 相关功能
|
|
40
|
+
import { ... } from '@geekron/hono/strapi'
|
|
41
|
+
|
|
42
|
+
// 导入路由相关功能
|
|
43
|
+
import { ... } from '@geekron/hono/route'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Strapi 模块
|
|
47
|
+
|
|
48
|
+
Strapi 模块提供了以下功能:
|
|
49
|
+
|
|
50
|
+
- **CMS 管理**: 站点配置、内容类型、组件管理
|
|
51
|
+
- **国际化**: 多语言和翻译支持
|
|
52
|
+
- **菜单管理**: 动态菜单系统
|
|
53
|
+
- **媒体处理**: 图片和文件资源管理
|
|
54
|
+
- **工具函数**: 文件 URL、图片信息等实用工具
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import {
|
|
58
|
+
// CMS 核心
|
|
59
|
+
getCMS,
|
|
60
|
+
getSite,
|
|
61
|
+
getContentTypes,
|
|
62
|
+
|
|
63
|
+
// 国际化
|
|
64
|
+
getLocales,
|
|
65
|
+
getTranslations,
|
|
66
|
+
|
|
67
|
+
// 菜单
|
|
68
|
+
getMenu,
|
|
69
|
+
|
|
70
|
+
// 工具函数
|
|
71
|
+
fileUrl,
|
|
72
|
+
imgSrc,
|
|
73
|
+
imgAlt,
|
|
74
|
+
imgInfo,
|
|
75
|
+
} from '@geekron/hono/strapi'
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 路由模块
|
|
79
|
+
|
|
80
|
+
路由模块提供灵活的路由配置和管理:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import {
|
|
84
|
+
type RouteItem,
|
|
85
|
+
type RouteItemHandler,
|
|
86
|
+
setupRoutes,
|
|
87
|
+
} from '@geekron/hono/route'
|
|
88
|
+
|
|
89
|
+
// 配置路由
|
|
90
|
+
const routes: RouteItem[] = [
|
|
91
|
+
{
|
|
92
|
+
method: 'GET',
|
|
93
|
+
path: '/',
|
|
94
|
+
name: 'home',
|
|
95
|
+
// ...
|
|
96
|
+
},
|
|
97
|
+
// 更多路由配置
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
setupRoutes(app, routes)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 路由配置选项
|
|
104
|
+
|
|
105
|
+
路由支持以下配置:
|
|
106
|
+
|
|
107
|
+
- `method`: HTTP 方法(GET, POST 等)
|
|
108
|
+
- `path`: 路由路径
|
|
109
|
+
- `name`: 路由名称(可选,默认为路径的 kebab-case 形式)
|
|
110
|
+
- `suffix`: URL 后缀(可选,默认使用环境变量 `URL_SUFFIX`)
|
|
111
|
+
- `dataType`: 数据类型
|
|
112
|
+
- `sitemap`: 是否包含在站点地图中
|
|
113
|
+
|
|
114
|
+
## 开发
|
|
115
|
+
|
|
116
|
+
### 安装依赖
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
bun install
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 代码格式化
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
bun run format
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 代码检查
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
bun run lint
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 完整检查
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
bun run check
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## 项目结构
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
.
|
|
144
|
+
├── src/
|
|
145
|
+
│ ├── route/ # 路由模块
|
|
146
|
+
│ │ ├── index.ts # 路由导出
|
|
147
|
+
│ │ ├── interfaces.ts # 路由接口定义
|
|
148
|
+
│ │ ├── methods.ts # HTTP 方法定义
|
|
149
|
+
│ │ ├── setup.ts # 路由设置
|
|
150
|
+
│ │ └── slot.ts # 路由插槽
|
|
151
|
+
│ ├── strapi/ # Strapi 集成模块
|
|
152
|
+
│ │ ├── cms/ # CMS 核心功能
|
|
153
|
+
│ │ ├── interfaces/ # 接口定义
|
|
154
|
+
│ │ ├── utils/ # 工具函数
|
|
155
|
+
│ │ ├── index.ts
|
|
156
|
+
│ │ └── route.ts # Strapi 路由处理
|
|
157
|
+
│ └── contract.ts # 环境变量和配置
|
|
158
|
+
├── package.json
|
|
159
|
+
└── tsconfig.json
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## 技术栈
|
|
163
|
+
|
|
164
|
+
- [Hono](https://hono.dev/) - 快速、轻量的 Web 框架
|
|
165
|
+
- [Strapi Client](https://www.npmjs.com/package/@strapi/client) - Strapi API 客户端
|
|
166
|
+
- [Voca](https://vocajs.com/) - 字符串处理库
|
|
167
|
+
- [TypeScript](https://www.typescriptlang.org/) - 类型安全
|
|
168
|
+
- [Biome](https://biomejs.dev/) - 代码格式化和检查
|
|
169
|
+
|
|
170
|
+
## 许可证
|
|
171
|
+
|
|
172
|
+
MIT
|
|
173
|
+
|
|
174
|
+
## 贡献
|
|
175
|
+
|
|
176
|
+
欢迎提交 Issue 和 Pull Request!
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,QAAiD,CAAA;AACrE,eAAO,MAAM,SAAS,QAAmC,CAAA;AACzD,eAAO,MAAM,SAAS,oBAAwB,CAAA;AAC9C,eAAO,MAAM,UAAU,QAAoC,CAAA"}
|
package/dist/contract.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/route/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,SAAS,CAAA;AACvB,cAAc,QAAQ,CAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Context } from 'hono';
|
|
2
|
+
import type { Variables } from '../route/setup';
|
|
3
|
+
export type RouteHandler = (c: Context<{
|
|
4
|
+
Variables: Variables;
|
|
5
|
+
}>) => Promise<Response> | Response;
|
|
6
|
+
export type RouteMethod = 'get' | 'post' | 'put' | 'all' | 'notFound' | 'onError';
|
|
7
|
+
export interface RouteSitemap {
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
priority?: number;
|
|
10
|
+
paginate?: number;
|
|
11
|
+
changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
|
12
|
+
}
|
|
13
|
+
export interface RouteOption {
|
|
14
|
+
sitemap?: RouteSitemap;
|
|
15
|
+
handler: RouteHandler;
|
|
16
|
+
dataType?: string;
|
|
17
|
+
suffix?: string;
|
|
18
|
+
name?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface RouteItem {
|
|
21
|
+
dataType?: string;
|
|
22
|
+
sitemap?: RouteSitemap;
|
|
23
|
+
method: RouteMethod;
|
|
24
|
+
name: string;
|
|
25
|
+
path: string;
|
|
26
|
+
fullPath: string;
|
|
27
|
+
suffix: string;
|
|
28
|
+
params: string[];
|
|
29
|
+
}
|
|
30
|
+
export interface RouteType {
|
|
31
|
+
dataType: string;
|
|
32
|
+
items: Array<RouteItem>;
|
|
33
|
+
}
|
|
34
|
+
export type RouteItemHandler = (method: 'get' | 'post' | 'put' | 'all') => (path: string, option: RouteOption) => Promise<RouteItem> | RouteItem;
|
|
35
|
+
//# sourceMappingURL=interfaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../src/route/interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAE9C,MAAM,MAAM,YAAY,GAAG,CAC1B,CAAC,EAAE,OAAO,CAAC;IAAE,SAAS,EAAE,SAAS,CAAA;CAAE,CAAC,KAChC,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAA;AAEjC,MAAM,MAAM,WAAW,GACpB,KAAK,GACL,MAAM,GACN,KAAK,GACL,KAAK,GACL,UAAU,GACV,SAAS,CAAA;AAEZ,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EACR,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,CAAA;CACV;AAED,MAAM,WAAW,WAAW;IAC3B,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,OAAO,EAAE,YAAY,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,MAAM,EAAE,WAAW,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,EAAE,CAAA;CAChB;AACD,MAAM,WAAW,SAAS;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,CAAA;CACvB;AAED,MAAM,MAAM,gBAAgB,GAAG,CAC9B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,KAClC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RouteHandler, RouteItem, RouteOption, RouteType } from './interfaces';
|
|
2
|
+
export declare const route: {
|
|
3
|
+
all: (path: string, option: RouteOption) => void;
|
|
4
|
+
get: (path: string, option: RouteOption) => void;
|
|
5
|
+
post: (path: string, option: RouteOption) => void;
|
|
6
|
+
put: (path: string, option: RouteOption) => void;
|
|
7
|
+
notFound: (handler: RouteHandler) => void;
|
|
8
|
+
onError: (handler: RouteHandler) => void;
|
|
9
|
+
};
|
|
10
|
+
export declare const getRouteItems: () => RouteItem[];
|
|
11
|
+
export declare const getRouteItemByName: (name: string) => RouteItem | undefined;
|
|
12
|
+
export declare const getRouteItemByType: (dataType: string) => RouteType | undefined;
|
|
13
|
+
//# sourceMappingURL=methods.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"methods.d.ts","sourceRoot":"","sources":["../../src/route/methods.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACX,YAAY,EACZ,SAAS,EACT,WAAW,EACX,SAAS,EACT,MAAM,cAAc,CAAA;AAErB,eAAO,MAAM,KAAK;gBA0CH,MAAM,UAAU,WAAW;gBAA3B,MAAM,UAAU,WAAW;iBAA3B,MAAM,UAAU,WAAW;gBAA3B,MAAM,UAAU,WAAW;wBArCrB,YAAY;uBAMb,YAAY;CAa/B,CAAA;AAKD,eAAO,MAAM,aAAa,mBAEzB,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,0BAE9C,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,UAAU,MAAM,0BAElD,CAAA"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { HTTPException } from 'hono/http-exception';
|
|
2
|
+
import { setup } from '../route/setup';
|
|
3
|
+
import { getContentTypes } from '../strapi';
|
|
4
|
+
export const route = {
|
|
5
|
+
all: method('all'),
|
|
6
|
+
get: method('get'),
|
|
7
|
+
post: method('post'),
|
|
8
|
+
put: method('put'),
|
|
9
|
+
notFound: (handler) => {
|
|
10
|
+
setup.app.notFound(async (c) => {
|
|
11
|
+
c.status(404);
|
|
12
|
+
return handler(c);
|
|
13
|
+
});
|
|
14
|
+
},
|
|
15
|
+
onError: (handler) => {
|
|
16
|
+
setup.app.onError(async (error, c) => {
|
|
17
|
+
console.error(error);
|
|
18
|
+
if (error instanceof HTTPException) {
|
|
19
|
+
if (error.status < 500) {
|
|
20
|
+
c.status(error.status);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
c.status(400);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return handler(c);
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
const routeItems = [];
|
|
31
|
+
const routeItemByName = new Map();
|
|
32
|
+
const routeItemByType = new Map();
|
|
33
|
+
export const getRouteItems = () => {
|
|
34
|
+
return routeItems;
|
|
35
|
+
};
|
|
36
|
+
export const getRouteItemByName = (name) => {
|
|
37
|
+
return routeItemByName.get(name);
|
|
38
|
+
};
|
|
39
|
+
export const getRouteItemByType = (dataType) => {
|
|
40
|
+
return routeItemByType.get(dataType);
|
|
41
|
+
};
|
|
42
|
+
function method(method) {
|
|
43
|
+
return (path, option) => {
|
|
44
|
+
const types = getContentTypes();
|
|
45
|
+
const app = setup.app;
|
|
46
|
+
const methods = {
|
|
47
|
+
get: app.get.bind(app),
|
|
48
|
+
post: app.post.bind(app),
|
|
49
|
+
put: app.put.bind(app),
|
|
50
|
+
all: app.all.bind(app),
|
|
51
|
+
notFound: app.notFound.bind(app),
|
|
52
|
+
onError: app.onError.bind(app),
|
|
53
|
+
};
|
|
54
|
+
const route = methods[method];
|
|
55
|
+
const handler = setup.routeItemHandler(method);
|
|
56
|
+
Promise.resolve(handler(path, option)).then((routeItem) => {
|
|
57
|
+
const name = routeItem.name;
|
|
58
|
+
if (routeItemByName.has(name)) {
|
|
59
|
+
throw new Error(`Route item name "${name}" already exists`);
|
|
60
|
+
}
|
|
61
|
+
routeItemByName.set(name, routeItem);
|
|
62
|
+
const dataType = routeItem.dataType;
|
|
63
|
+
if (dataType) {
|
|
64
|
+
if (!types.has(dataType)) {
|
|
65
|
+
throw new Error(`Content type "${dataType}" not found`);
|
|
66
|
+
}
|
|
67
|
+
const items = routeItemByType.get(dataType)?.items || [];
|
|
68
|
+
routeItemByType.set(dataType, {
|
|
69
|
+
dataType,
|
|
70
|
+
items: [...items, routeItem],
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
routeItems.push(routeItem);
|
|
74
|
+
route(routeItem.fullPath, async (c) => {
|
|
75
|
+
return option.handler(c);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Hono } from 'hono';
|
|
2
|
+
import type { Child } from 'hono/jsx';
|
|
3
|
+
import type { RouteItem, RouteItemHandler } from '../route/interfaces';
|
|
4
|
+
export type AppInstance = Hono<{
|
|
5
|
+
Variables: Variables;
|
|
6
|
+
}>;
|
|
7
|
+
export interface Variables {
|
|
8
|
+
app: AppInstance;
|
|
9
|
+
slots: Map<string, Child[]>;
|
|
10
|
+
route: RouteItem;
|
|
11
|
+
}
|
|
12
|
+
export interface SetupRoutesOption {
|
|
13
|
+
app: AppInstance;
|
|
14
|
+
routeItemHandler: RouteItemHandler;
|
|
15
|
+
}
|
|
16
|
+
export declare const setup: SetupRoutesOption;
|
|
17
|
+
export declare const setupRoutes: (paths: string | string[], option: SetupRoutesOption) => Promise<void>;
|
|
18
|
+
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/route/setup.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAChC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAErE,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC;IAAE,SAAS,EAAE,SAAS,CAAA;CAAE,CAAC,CAAA;AAExD,MAAM,WAAW,SAAS;IACzB,GAAG,EAAE,WAAW,CAAA;IAChB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;IAC3B,KAAK,EAAE,SAAS,CAAA;CAChB;AAED,MAAM,WAAW,iBAAiB;IACjC,GAAG,EAAE,WAAW,CAAA;IAChB,gBAAgB,EAAE,gBAAgB,CAAA;CAClC;AAED,eAAO,MAAM,KAAK,EAAS,iBAAiB,CAAA;AAE5C,eAAO,MAAM,WAAW,GACvB,OAAO,MAAM,GAAG,MAAM,EAAE,EACxB,QAAQ,iBAAiB,kBASzB,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
export const setup = {};
|
|
3
|
+
export const setupRoutes = async (paths, option) => {
|
|
4
|
+
const { app } = option;
|
|
5
|
+
setup.app = app;
|
|
6
|
+
setup.routeItemHandler = option.routeItemHandler;
|
|
7
|
+
const files = fs.globSync(paths);
|
|
8
|
+
files.forEach((file) => {
|
|
9
|
+
require(file);
|
|
10
|
+
});
|
|
11
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Context } from 'hono';
|
|
2
|
+
import type { Child } from 'hono/jsx';
|
|
3
|
+
import type { Variables } from '../route/setup';
|
|
4
|
+
export declare const slot: <SlotName extends string>(ctx: Context<{
|
|
5
|
+
Variables: Variables;
|
|
6
|
+
}>) => {
|
|
7
|
+
append: (name: SlotName, content: Child) => Child[];
|
|
8
|
+
parse: (render: (ctx: Context<{
|
|
9
|
+
Variables: Variables;
|
|
10
|
+
}>) => Promise<Child> | Child) => Promise<{
|
|
11
|
+
content: string | undefined;
|
|
12
|
+
slots: Map<SlotName, Child[]>;
|
|
13
|
+
}>;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=slot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot.d.ts","sourceRoot":"","sources":["../../src/route/slot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAE9C,eAAO,MAAM,IAAI,GAAI,QAAQ,SAAS,MAAM,EAC3C,KAAK,OAAO,CAAC;IAAE,SAAS,EAAE,SAAS,CAAA;CAAE,CAAC;mBAGtB,QAAQ,WAAW,KAAK;oBAe9B,CACP,GAAG,EAAE,OAAO,CAAC;QAAE,SAAS,EAAE,SAAS,CAAA;KAAE,CAAC,KAClC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK;;;;CAe7B,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const slot = (ctx) => {
|
|
2
|
+
return {
|
|
3
|
+
append: (name, content) => {
|
|
4
|
+
const slots = ctx.get('slots') || new Map();
|
|
5
|
+
let slot = slots.get(name) || [];
|
|
6
|
+
if (!content)
|
|
7
|
+
return slot;
|
|
8
|
+
if (!Array.isArray(content)) {
|
|
9
|
+
content = [content];
|
|
10
|
+
}
|
|
11
|
+
slot = [...slot, ...content];
|
|
12
|
+
slot = slot.filter(Boolean);
|
|
13
|
+
slots.set(name, slot);
|
|
14
|
+
ctx.set('slots', slots);
|
|
15
|
+
return slot;
|
|
16
|
+
},
|
|
17
|
+
parse: async (render) => {
|
|
18
|
+
// 【第一阶段】渲染内容并强制执行,触发所有组件的 slot.append
|
|
19
|
+
const preContent = await render(ctx);
|
|
20
|
+
// 使用 toString() 方法强制渲染(支持异步组件)
|
|
21
|
+
// 这会触发所有子组件执行,slot.append 生效
|
|
22
|
+
const content = await preContent?.toString();
|
|
23
|
+
// 【第二阶段】获取已收集的 slots
|
|
24
|
+
const slots = (ctx.get('slots') || new Map());
|
|
25
|
+
return { content, slots };
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 创建CMS客户端
|
|
3
|
+
*/
|
|
4
|
+
export declare const cms: import("@strapi/client").StrapiClient;
|
|
5
|
+
/**
|
|
6
|
+
* 获取CMS客户端
|
|
7
|
+
*/
|
|
8
|
+
export declare const getCMS: () => import("@strapi/client").StrapiClient;
|
|
9
|
+
/**
|
|
10
|
+
* 检查CMS状态
|
|
11
|
+
*/
|
|
12
|
+
export declare const cmsStatus: () => Promise<boolean>;
|
|
13
|
+
/**
|
|
14
|
+
* 检查CMS状态
|
|
15
|
+
*/
|
|
16
|
+
export declare const checkCmsStatus: () => Promise<void>;
|
|
17
|
+
//# sourceMappingURL=cms.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cms.d.ts","sourceRoot":"","sources":["../../../src/strapi/cms/cms.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,GAAG,uCAGd,CAAA;AAEF;;GAEG;AACH,eAAO,MAAM,MAAM,6CAElB,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,SAAS,wBAUrB,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,qBAqB1B,CAAA"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { strapi } from '@strapi/client';
|
|
2
|
+
import { CMS_TOKEN, CMS_URL } from '../../contract';
|
|
3
|
+
/**
|
|
4
|
+
* 创建CMS客户端
|
|
5
|
+
*/
|
|
6
|
+
export const cms = strapi({
|
|
7
|
+
baseURL: `${CMS_URL}/api`,
|
|
8
|
+
auth: CMS_TOKEN,
|
|
9
|
+
});
|
|
10
|
+
/**
|
|
11
|
+
* 获取CMS客户端
|
|
12
|
+
*/
|
|
13
|
+
export const getCMS = () => {
|
|
14
|
+
return cms;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* 检查CMS状态
|
|
18
|
+
*/
|
|
19
|
+
export const cmsStatus = async () => {
|
|
20
|
+
try {
|
|
21
|
+
const checkUrl = `${CMS_URL}/dashboard/website/hello`;
|
|
22
|
+
const response = await fetch(checkUrl);
|
|
23
|
+
console.log('✅ API health check response:', response.statusText);
|
|
24
|
+
return response.ok;
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
console.error('❌ Error checking API health:', error);
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* 检查CMS状态
|
|
33
|
+
*/
|
|
34
|
+
export const checkCmsStatus = async () => {
|
|
35
|
+
let attempts = 0;
|
|
36
|
+
const maxAttempts = 30; // 最多尝试30秒
|
|
37
|
+
while (attempts < maxAttempts) {
|
|
38
|
+
try {
|
|
39
|
+
console.log(`第 ${attempts + 1} 次尝试检查CMS状态...`);
|
|
40
|
+
const status = await cmsStatus();
|
|
41
|
+
if (status) {
|
|
42
|
+
console.log('✅ CMS状态:', 'OK');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
console.log('❌ CMS状态:', '异常,继续检查...');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
console.error('❌ 获取CMS状态时发生错误:', error);
|
|
51
|
+
}
|
|
52
|
+
attempts++;
|
|
53
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
54
|
+
}
|
|
55
|
+
console.log('达到最大尝试次数');
|
|
56
|
+
throw new Error('CMS状态: 异常,请检查CMS是否正常启动');
|
|
57
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface Common {
|
|
2
|
+
[key: string]: any;
|
|
3
|
+
}
|
|
4
|
+
export type CommonPopulate = string | string[] | Record<string, unknown>;
|
|
5
|
+
export declare const setCommon: (common: Common) => void;
|
|
6
|
+
export declare const getCommon: <T = Common>() => T;
|
|
7
|
+
export declare const fetchCommon: (populate?: CommonPopulate, refresh?: boolean) => Promise<Common>;
|
|
8
|
+
export declare const initCommon: (populate?: CommonPopulate, refresh?: boolean) => Promise<Common>;
|
|
9
|
+
//# sourceMappingURL=common.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../src/strapi/cms/common.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,MAAM;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAClB;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAGxE,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,SAEvC,CAAA;AAED,eAAO,MAAM,SAAS,GAAI,CAAC,GAAG,MAAM,OAKlB,CACjB,CAAA;AAED,eAAO,MAAM,WAAW,GACvB,WAAU,cAAoB,EAC9B,iBAAe,oBAGf,CAAA;AAED,eAAO,MAAM,UAAU,GACtB,WAAU,cAAoB,EAC9B,iBAAc,oBAcd,CAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { cms } from './cms';
|
|
2
|
+
const cache = new Map();
|
|
3
|
+
export const setCommon = (common) => {
|
|
4
|
+
cache.set('common', common);
|
|
5
|
+
};
|
|
6
|
+
export const getCommon = () => {
|
|
7
|
+
const common = cache.get('common');
|
|
8
|
+
if (!common) {
|
|
9
|
+
throw new Error('common not found');
|
|
10
|
+
}
|
|
11
|
+
return common;
|
|
12
|
+
};
|
|
13
|
+
export const fetchCommon = async (populate = '*', refresh = false) => {
|
|
14
|
+
return await initCommon(populate, refresh);
|
|
15
|
+
};
|
|
16
|
+
export const initCommon = async (populate = '*', refresh = true) => {
|
|
17
|
+
if (refresh)
|
|
18
|
+
cache.clear();
|
|
19
|
+
if (cache.has('common')) {
|
|
20
|
+
return Promise.resolve(cache.get('common'));
|
|
21
|
+
}
|
|
22
|
+
const common = await cms
|
|
23
|
+
.single('common')
|
|
24
|
+
.find({
|
|
25
|
+
populate,
|
|
26
|
+
})
|
|
27
|
+
.then((res) => res.data);
|
|
28
|
+
setCommon(common);
|
|
29
|
+
return getCommon();
|
|
30
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ComponentSchema {
|
|
2
|
+
displayName: string;
|
|
3
|
+
description: string;
|
|
4
|
+
icon?: string;
|
|
5
|
+
collectionName: string;
|
|
6
|
+
attributes: {
|
|
7
|
+
[key: string]: Record<string, any>;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export interface Component {
|
|
11
|
+
uid: string;
|
|
12
|
+
category: string;
|
|
13
|
+
apiId: string;
|
|
14
|
+
schema: ComponentSchema;
|
|
15
|
+
}
|
|
16
|
+
export declare const getComponents: () => Map<string, Component>;
|
|
17
|
+
export declare const getComponent: (uid: string) => Component | undefined;
|
|
18
|
+
export declare const fetchComponents: (refresh?: boolean) => Promise<Map<string, Component>>;
|
|
19
|
+
export declare const initComponents: (refresh?: boolean) => Promise<Map<string, Component>>;
|
|
20
|
+
//# sourceMappingURL=components.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../../src/strapi/cms/components.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC/B,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE;QACX,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAClC,CAAA;CACD;AAED,MAAM,WAAW,SAAS;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,eAAe,CAAA;CACvB;AAID,eAAO,MAAM,aAAa,8BAKzB,CAAA;AAED,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,0BAEvC,CAAA;AAED,eAAO,MAAM,eAAe,GAAU,iBAAe,oCAEpD,CAAA;AAED,eAAO,MAAM,cAAc,GAAU,iBAAc,oCAgBlD,CAAA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { cms } from './cms';
|
|
2
|
+
const components = new Map();
|
|
3
|
+
export const getComponents = () => {
|
|
4
|
+
if (components.size === 0) {
|
|
5
|
+
throw new Error('No components found');
|
|
6
|
+
}
|
|
7
|
+
return components;
|
|
8
|
+
};
|
|
9
|
+
export const getComponent = (uid) => {
|
|
10
|
+
return components.get(uid);
|
|
11
|
+
};
|
|
12
|
+
export const fetchComponents = async (refresh = false) => {
|
|
13
|
+
return await initComponents(refresh);
|
|
14
|
+
};
|
|
15
|
+
export const initComponents = async (refresh = true) => {
|
|
16
|
+
try {
|
|
17
|
+
if (refresh)
|
|
18
|
+
components.clear();
|
|
19
|
+
if (components.size > 0) {
|
|
20
|
+
return Promise.resolve(components);
|
|
21
|
+
}
|
|
22
|
+
const res = await cms.fetch('/content-type-builder/components');
|
|
23
|
+
const { data } = await res.json();
|
|
24
|
+
data?.forEach((item) => {
|
|
25
|
+
components.set(item.uid, item);
|
|
26
|
+
});
|
|
27
|
+
return components;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error('components error', error);
|
|
31
|
+
return new Map();
|
|
32
|
+
}
|
|
33
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 内容类型定义
|
|
3
|
+
*/
|
|
4
|
+
export interface ContentTypeSchema {
|
|
5
|
+
draftAndPublish: boolean;
|
|
6
|
+
displayName: string;
|
|
7
|
+
singularName: string;
|
|
8
|
+
pluralName: string;
|
|
9
|
+
description: string;
|
|
10
|
+
pluginOptions: {
|
|
11
|
+
'content-manager': Record<string, any>;
|
|
12
|
+
'content-type-builder': Record<string, any>;
|
|
13
|
+
};
|
|
14
|
+
kind: 'collectionType' | 'singleType';
|
|
15
|
+
collectionName: string;
|
|
16
|
+
attributes: {
|
|
17
|
+
[key: string]: Record<string, any>;
|
|
18
|
+
};
|
|
19
|
+
visible: boolean;
|
|
20
|
+
restrictRelationsTo: string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 内容类型
|
|
24
|
+
*/
|
|
25
|
+
export interface ContentType {
|
|
26
|
+
uid: string;
|
|
27
|
+
plugin: string;
|
|
28
|
+
apiID: string;
|
|
29
|
+
schema: ContentTypeSchema;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 获取内容类型集合
|
|
33
|
+
*/
|
|
34
|
+
export declare const getContentTypes: () => Map<string, ContentType>;
|
|
35
|
+
/**
|
|
36
|
+
* 获取内容类型
|
|
37
|
+
* @param uid
|
|
38
|
+
*/
|
|
39
|
+
export declare const getContentType: (uid: string) => ContentType | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* 获取内容类型
|
|
42
|
+
*/
|
|
43
|
+
export declare const fetchContentTypes: (refresh?: boolean) => Promise<Map<string, ContentType>>;
|
|
44
|
+
/**
|
|
45
|
+
* 初始化内容类型
|
|
46
|
+
*/
|
|
47
|
+
export declare const initContentTypes: (refresh?: boolean) => Promise<Map<string, ContentType>>;
|
|
48
|
+
//# sourceMappingURL=content-types.d.ts.map
|