@ubean/app 0.6.0-beta.5 → 0.6.1-beta.2
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/dist/index.d.ts +191 -191
- package/dist/index.js +158 -124
- package/package.json +14 -14
package/dist/index.d.ts
CHANGED
|
@@ -2,10 +2,199 @@ import { RegisterOptions, RouteRegistrar } from "@ubean/routes";
|
|
|
2
2
|
import { CacheStore } from "@ubean/server/cache";
|
|
3
3
|
import { DataCacheMiddlewareOptions } from "@ubean/server/middleware";
|
|
4
4
|
import { CsrfOptions, SecurityHeadersOptions } from "@ubean/server/security";
|
|
5
|
-
import { ComposedHandler, ComposedHandler as ComposedHandler$1, RouteMeta, RouteMeta as RouteMeta$1, RouteRule, RouteRule as RouteRule$1, UbeanEnv, UbeanEnv as UbeanEnv$1, UbeanMiddleware, UbeanMiddleware as UbeanMiddleware$1 } from "@ubean/shared";
|
|
5
|
+
import { ComposedHandler, ComposedHandler as ComposedHandler$1, RouteMeta, RouteMeta as RouteMeta$1, RouteRule, RouteRule as RouteRule$1, UbeanEnv, UbeanEnv as UbeanEnv$1, UbeanMiddleware, UbeanMiddleware as UbeanMiddleware$1, UbeanMiddlewareStep } from "@ubean/shared";
|
|
6
6
|
import { Context, Hono, MiddlewareHandler } from "hono";
|
|
7
7
|
import { Hookable } from "hookable";
|
|
8
8
|
import { ScannedApiRoute, ScannedApiRoute as ScannedApiRoute$1, ScannedCronTask, ScannedLayout, ScannedLayout as ScannedLayout$1, ScannedMiddleware, ScannedMiddleware as ScannedMiddleware$1, ScannedPageRoute, ScannedPageRoute as ScannedPageRoute$1 } from "@ubean/scan";
|
|
9
|
+
//#region src/app.d.ts
|
|
10
|
+
interface UbeanRuntimeHooks {
|
|
11
|
+
'app:created': (app: Hono<UbeanEnv$1>) => void | Promise<void>;
|
|
12
|
+
'app:before:register': (app: Hono<UbeanEnv$1>) => void | Promise<void>;
|
|
13
|
+
'app:after:register': (app: Hono<UbeanEnv$1>) => void | Promise<void>;
|
|
14
|
+
'request:start': (c: Context<UbeanEnv$1>) => void | Promise<void>;
|
|
15
|
+
'request:end': (c: Context<UbeanEnv$1>, res: Response) => void | Promise<void>;
|
|
16
|
+
'request:error': (c: Context<UbeanEnv$1>, err: Error) => void | Promise<void>;
|
|
17
|
+
'route:register': (route: {
|
|
18
|
+
method: string;
|
|
19
|
+
path: string;
|
|
20
|
+
handler: MiddlewareHandler[] | ComposedHandler$1 | Function;
|
|
21
|
+
meta?: RouteMeta$1;
|
|
22
|
+
}) => void | Promise<void>;
|
|
23
|
+
'middleware:register': (mw: ScannedMiddleware$1) => void | Promise<void>;
|
|
24
|
+
error: (err: Error, c: Context<UbeanEnv$1>) => void | Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Page renderer shape (satisfied by `@ubean/client/ssr`'s `PageRenderer`).
|
|
28
|
+
* Declared as a type alias to the actual `@ubean/pages`'s `PageRenderer`
|
|
29
|
+
* interface so consumers don't need to install `@ubean/pages` separately
|
|
30
|
+
* to type-check against `UbeanAppOptions.pageRenderer`.
|
|
31
|
+
*
|
|
32
|
+
* Type-only import works even when `@ubean/pages` is an optional peerDep —
|
|
33
|
+
* only runtime imports would fail. Consumers without `@ubean/pages` will
|
|
34
|
+
* see this type fall back to `any` (TS' default for missing modules under
|
|
35
|
+
* `skipLibCheck`).
|
|
36
|
+
*/
|
|
37
|
+
type PageRenderer = import('@ubean/pages').PageRenderer;
|
|
38
|
+
interface PageAssetTags {
|
|
39
|
+
head?: string;
|
|
40
|
+
bodyAttrs?: string;
|
|
41
|
+
htmlAttrs?: string;
|
|
42
|
+
/** Favicon HREF (如 `/favicon.ico`),自动注入 `<link rel="icon">` 到 `<head>` */
|
|
43
|
+
favicon?: string;
|
|
44
|
+
}
|
|
45
|
+
interface UbeanAppOptions {
|
|
46
|
+
rootDir?: string;
|
|
47
|
+
routes?: ScannedApiRoute$1[];
|
|
48
|
+
middleware?: ScannedMiddleware$1[];
|
|
49
|
+
pages?: ScannedPageRoute$1[];
|
|
50
|
+
layouts?: ScannedLayout$1[];
|
|
51
|
+
crons?: ScannedCronTask[];
|
|
52
|
+
routeRules?: Record<string, RouteRule$1>;
|
|
53
|
+
plugins?: UbeanAppPlugin[];
|
|
54
|
+
routeLoaders?: Record<string, () => Promise<{
|
|
55
|
+
default?: ComposedHandler$1 | MiddlewareHandler[];
|
|
56
|
+
} | Record<string, ComposedHandler$1 | MiddlewareHandler[]>>>;
|
|
57
|
+
middlewareLoaders?: Record<string, () => Promise<{
|
|
58
|
+
default: UbeanMiddleware$1;
|
|
59
|
+
}>>;
|
|
60
|
+
pageLoaders?: Record<string, () => Promise<unknown>>;
|
|
61
|
+
pageRenderer?: PageRenderer | null;
|
|
62
|
+
pageAssetTags?: PageAssetTags;
|
|
63
|
+
/** 不进行 SSR 的路由模式列表(glob),匹配的页面走 CSR */
|
|
64
|
+
ssrExclude?: string[];
|
|
65
|
+
/**
|
|
66
|
+
* 启用流式 SSR。`true` 时页面响应以 `ReadableStream` 分块输出
|
|
67
|
+
* (头部先发送,app HTML 边渲染边输出),改善 TTFB/LCP。
|
|
68
|
+
* renderer 不支持流式时自动降级为缓冲渲染。
|
|
69
|
+
*/
|
|
70
|
+
streaming?: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* 爬虫降级(P9-24):当 `streaming` 启用且检测到爬虫/社交预览 UA 时,
|
|
73
|
+
* 自动降级为缓冲渲染以保证 metadata 出现在初始 `<head>`。
|
|
74
|
+
* 默认 `true`。设为 `false` 可禁用爬虫检测(不推荐)。
|
|
75
|
+
*/
|
|
76
|
+
botFallback?: boolean;
|
|
77
|
+
publicDir?: string;
|
|
78
|
+
healthEndpoint?: boolean;
|
|
79
|
+
openAPI?: boolean | {
|
|
80
|
+
title?: string;
|
|
81
|
+
version?: string;
|
|
82
|
+
description?: string;
|
|
83
|
+
scalarPath?: string;
|
|
84
|
+
openAPIPath?: string;
|
|
85
|
+
};
|
|
86
|
+
i18nConfig?: {
|
|
87
|
+
enabled?: boolean;
|
|
88
|
+
strategy?: 'prefix' | 'prefix_except_default' | 'prefix_and_default' | 'no_prefix';
|
|
89
|
+
defaultLocale?: string;
|
|
90
|
+
locales?: string[] | Array<{
|
|
91
|
+
code: string;
|
|
92
|
+
}>;
|
|
93
|
+
detectBrowserLanguage?: false | {
|
|
94
|
+
cookieName?: string;
|
|
95
|
+
redirectOn?: 'root' | 'all';
|
|
96
|
+
alwaysRedirect?: boolean;
|
|
97
|
+
};
|
|
98
|
+
fallbackLocale?: string;
|
|
99
|
+
baseUrl?: string;
|
|
100
|
+
};
|
|
101
|
+
/** `pages/404.vue` 自动检测的 404 页面,注册为 Hono 兜底处理器 */
|
|
102
|
+
notFoundPage?: ScannedPageRoute$1;
|
|
103
|
+
/**
|
|
104
|
+
* Pre-rendered no-FOUC color-mode script (from `getColorModeScript`).
|
|
105
|
+
* Injected into `<head>` of every SSR/prerendered HTML response. Covers
|
|
106
|
+
* the SSG/prerender path that bypasses Vite's `transformIndexHtml`.
|
|
107
|
+
*/
|
|
108
|
+
colorModeScript?: string;
|
|
109
|
+
/**
|
|
110
|
+
* CSRF protection. Default `true` (origin check). `false` disables.
|
|
111
|
+
* Pass `CsrfOptions` to override (e.g. token mode).
|
|
112
|
+
*/
|
|
113
|
+
csrf?: boolean | CsrfOptions;
|
|
114
|
+
/**
|
|
115
|
+
* Security response headers. Default `true`. `false` disables.
|
|
116
|
+
*/
|
|
117
|
+
securityHeaders?: boolean | SecurityHeadersOptions;
|
|
118
|
+
/**
|
|
119
|
+
* Cross-request fetch Data Cache (`next: { revalidate, tags }`).
|
|
120
|
+
* Default `true`. Dev still skips cache unless `forceDevCache`.
|
|
121
|
+
*/
|
|
122
|
+
dataCache?: boolean | DataCacheMiddlewareOptions;
|
|
123
|
+
/**
|
|
124
|
+
* HTTP / ISR cache store. Default is in-process memory (not shared
|
|
125
|
+
* across instances). Pass `loadFsCacheStore(dir)`(Node fs 后端,动态加载)for a Node backend.
|
|
126
|
+
*/
|
|
127
|
+
cacheStore?: CacheStore;
|
|
128
|
+
/** Declarative cache backend. `store: 'fs'` 走 `loadFsCacheStore()`(Node-only,动态加载)。 */
|
|
129
|
+
cache?: {
|
|
130
|
+
store?: 'memory' | 'fs';
|
|
131
|
+
dir?: string;
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* File-convention SEO (`src/sitemap.ts`, `robots.ts`, …). Default: on when
|
|
135
|
+
* `rootDir` or `seoConventions.srcDir` is set. `false` disables.
|
|
136
|
+
*/
|
|
137
|
+
seoConventions?: boolean | {
|
|
138
|
+
srcDir?: string;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Preloaded SEO convention modules (production `import.meta.glob`). When
|
|
142
|
+
* set, disk discovery is skipped — required on serverless.
|
|
143
|
+
*/
|
|
144
|
+
seoConventionModules?: Record<string, {
|
|
145
|
+
default?: unknown;
|
|
146
|
+
}>;
|
|
147
|
+
/**
|
|
148
|
+
* Production `/_ipx` handler (from `@ubean/image` when `image` is enabled).
|
|
149
|
+
* Dev still uses the Vite middleware.
|
|
150
|
+
*/
|
|
151
|
+
ipxHandler?: MiddlewareHandler<UbeanEnv$1>;
|
|
152
|
+
}
|
|
153
|
+
interface UbeanAppPlugin {
|
|
154
|
+
name: string;
|
|
155
|
+
/** Called after app is created but before routes are registered */
|
|
156
|
+
setup?: (app: UbeanApp) => void | Promise<void>;
|
|
157
|
+
/** Called after all routes are registered */
|
|
158
|
+
ready?: (app: UbeanApp) => void | Promise<void>;
|
|
159
|
+
}
|
|
160
|
+
export declare class UbeanApp {
|
|
161
|
+
readonly hono: Hono<UbeanEnv$1>;
|
|
162
|
+
readonly hooks: Hookable<UbeanRuntimeHooks>;
|
|
163
|
+
readonly plugins: UbeanAppPlugin[];
|
|
164
|
+
readonly options: UbeanAppOptions;
|
|
165
|
+
private _ready;
|
|
166
|
+
/**
|
|
167
|
+
* Scalar 文档页(`/_scalar`)专用的 CSP:生效 CSP + `{@link SCALAR_SCRIPT_ORIGIN}`。
|
|
168
|
+
*
|
|
169
|
+
* 该页面从 CDN 取脚本,而 CSP 是全局的一份 —— 只在这一条响应上追加它需要的来源,不放宽应用
|
|
170
|
+
* 其余部分的策略。CSP 被关闭时为 `undefined`(不重加头)。构造期算好,`init()` 注册路由时用。
|
|
171
|
+
*/
|
|
172
|
+
private _scalarCsp;
|
|
173
|
+
constructor(options?: UbeanAppOptions);
|
|
174
|
+
private _setupBaseMiddleware;
|
|
175
|
+
init(): Promise<this>;
|
|
176
|
+
private _registerSeoConventions;
|
|
177
|
+
private _lazyInitPromise;
|
|
178
|
+
lazyInit(): Promise<this>;
|
|
179
|
+
resetInit(): void;
|
|
180
|
+
private _setupFallback;
|
|
181
|
+
use(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
182
|
+
use(...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
183
|
+
on(method: string | string[], path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
184
|
+
get(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
185
|
+
post(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
186
|
+
put(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
187
|
+
patch(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
188
|
+
delete(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
189
|
+
fetch: Hono<UbeanEnv$1>['fetch'];
|
|
190
|
+
request: Hono<UbeanEnv$1>['request'];
|
|
191
|
+
}
|
|
192
|
+
interface AppPlugin {
|
|
193
|
+
name: string;
|
|
194
|
+
setup?: (app: Hono<UbeanEnv$1>) => void | Promise<void>;
|
|
195
|
+
}
|
|
196
|
+
export declare function createUbeanApp(options?: UbeanAppOptions): UbeanApp;
|
|
197
|
+
//#endregion
|
|
9
198
|
//#region src/hooks.d.ts
|
|
10
199
|
/**
|
|
11
200
|
* 请求事件 —— 传递给 `handle` 和 `handleError` 的上下文对象。
|
|
@@ -285,193 +474,4 @@ export declare function createDefaultServerConfig(): ResolvedServerConfig;
|
|
|
285
474
|
*/
|
|
286
475
|
export declare function mergeServerConfigs(base: ResolvedServerConfig, ...configs: (ResolvedServerConfig | null | undefined)[]): ResolvedServerConfig;
|
|
287
476
|
//#endregion
|
|
288
|
-
|
|
289
|
-
interface UbeanRuntimeHooks {
|
|
290
|
-
'app:created': (app: Hono<UbeanEnv$1>) => void | Promise<void>;
|
|
291
|
-
'app:before:register': (app: Hono<UbeanEnv$1>) => void | Promise<void>;
|
|
292
|
-
'app:after:register': (app: Hono<UbeanEnv$1>) => void | Promise<void>;
|
|
293
|
-
'request:start': (c: Context<UbeanEnv$1>) => void | Promise<void>;
|
|
294
|
-
'request:end': (c: Context<UbeanEnv$1>, res: Response) => void | Promise<void>;
|
|
295
|
-
'request:error': (c: Context<UbeanEnv$1>, err: Error) => void | Promise<void>;
|
|
296
|
-
'route:register': (route: {
|
|
297
|
-
method: string;
|
|
298
|
-
path: string;
|
|
299
|
-
handler: MiddlewareHandler[] | ComposedHandler$1 | Function;
|
|
300
|
-
meta?: RouteMeta$1;
|
|
301
|
-
}) => void | Promise<void>;
|
|
302
|
-
'middleware:register': (mw: ScannedMiddleware$1) => void | Promise<void>;
|
|
303
|
-
error: (err: Error, c: Context<UbeanEnv$1>) => void | Promise<void>;
|
|
304
|
-
}
|
|
305
|
-
/**
|
|
306
|
-
* Page renderer shape (satisfied by `@ubean/client/ssr`'s `PageRenderer`).
|
|
307
|
-
* Declared as a type alias to the actual `@ubean/pages`'s `PageRenderer`
|
|
308
|
-
* interface so consumers don't need to install `@ubean/pages` separately
|
|
309
|
-
* to type-check against `UbeanAppOptions.pageRenderer`.
|
|
310
|
-
*
|
|
311
|
-
* Type-only import works even when `@ubean/pages` is an optional peerDep —
|
|
312
|
-
* only runtime imports would fail. Consumers without `@ubean/pages` will
|
|
313
|
-
* see this type fall back to `any` (TS' default for missing modules under
|
|
314
|
-
* `skipLibCheck`).
|
|
315
|
-
*/
|
|
316
|
-
type PageRenderer = import('@ubean/pages').PageRenderer;
|
|
317
|
-
interface PageAssetTags {
|
|
318
|
-
head?: string;
|
|
319
|
-
bodyAttrs?: string;
|
|
320
|
-
htmlAttrs?: string;
|
|
321
|
-
/** Favicon HREF (如 `/favicon.ico`),自动注入 `<link rel="icon">` 到 `<head>` */
|
|
322
|
-
favicon?: string;
|
|
323
|
-
}
|
|
324
|
-
interface UbeanAppOptions {
|
|
325
|
-
rootDir?: string;
|
|
326
|
-
routes?: ScannedApiRoute$1[];
|
|
327
|
-
middleware?: ScannedMiddleware$1[];
|
|
328
|
-
pages?: ScannedPageRoute$1[];
|
|
329
|
-
layouts?: ScannedLayout$1[];
|
|
330
|
-
crons?: ScannedCronTask[];
|
|
331
|
-
routeRules?: Record<string, RouteRule$1>;
|
|
332
|
-
plugins?: UbeanAppPlugin[];
|
|
333
|
-
routeLoaders?: Record<string, () => Promise<{
|
|
334
|
-
default?: ComposedHandler$1 | MiddlewareHandler[];
|
|
335
|
-
} | Record<string, ComposedHandler$1 | MiddlewareHandler[]>>>;
|
|
336
|
-
middlewareLoaders?: Record<string, () => Promise<{
|
|
337
|
-
default: UbeanMiddleware$1;
|
|
338
|
-
}>>;
|
|
339
|
-
pageLoaders?: Record<string, () => Promise<unknown>>;
|
|
340
|
-
pageRenderer?: PageRenderer | null;
|
|
341
|
-
pageAssetTags?: PageAssetTags;
|
|
342
|
-
/** 不进行 SSR 的路由模式列表(glob),匹配的页面走 CSR */
|
|
343
|
-
ssrExclude?: string[];
|
|
344
|
-
/**
|
|
345
|
-
* 启用流式 SSR。`true` 时页面响应以 `ReadableStream` 分块输出
|
|
346
|
-
* (头部先发送,app HTML 边渲染边输出),改善 TTFB/LCP。
|
|
347
|
-
* renderer 不支持流式时自动降级为缓冲渲染。
|
|
348
|
-
*/
|
|
349
|
-
streaming?: boolean;
|
|
350
|
-
/**
|
|
351
|
-
* 爬虫降级(P9-24):当 `streaming` 启用且检测到爬虫/社交预览 UA 时,
|
|
352
|
-
* 自动降级为缓冲渲染以保证 metadata 出现在初始 `<head>`。
|
|
353
|
-
* 默认 `true`。设为 `false` 可禁用爬虫检测(不推荐)。
|
|
354
|
-
*/
|
|
355
|
-
botFallback?: boolean;
|
|
356
|
-
publicDir?: string;
|
|
357
|
-
healthEndpoint?: boolean;
|
|
358
|
-
openAPI?: boolean | {
|
|
359
|
-
title?: string;
|
|
360
|
-
version?: string;
|
|
361
|
-
description?: string;
|
|
362
|
-
scalarPath?: string;
|
|
363
|
-
openAPIPath?: string;
|
|
364
|
-
};
|
|
365
|
-
i18nConfig?: {
|
|
366
|
-
enabled?: boolean;
|
|
367
|
-
strategy?: 'prefix' | 'prefix_except_default' | 'prefix_and_default' | 'no_prefix';
|
|
368
|
-
defaultLocale?: string;
|
|
369
|
-
locales?: string[] | Array<{
|
|
370
|
-
code: string;
|
|
371
|
-
}>;
|
|
372
|
-
detectBrowserLanguage?: false | {
|
|
373
|
-
cookieName?: string;
|
|
374
|
-
redirectOn?: 'root' | 'all';
|
|
375
|
-
alwaysRedirect?: boolean;
|
|
376
|
-
};
|
|
377
|
-
fallbackLocale?: string;
|
|
378
|
-
baseUrl?: string;
|
|
379
|
-
};
|
|
380
|
-
/** `pages/404.vue` 自动检测的 404 页面,注册为 Hono 兜底处理器 */
|
|
381
|
-
notFoundPage?: ScannedPageRoute$1;
|
|
382
|
-
/**
|
|
383
|
-
* Pre-rendered no-FOUC color-mode script (from `getColorModeScript`).
|
|
384
|
-
* Injected into `<head>` of every SSR/prerendered HTML response. Covers
|
|
385
|
-
* the SSG/prerender path that bypasses Vite's `transformIndexHtml`.
|
|
386
|
-
*/
|
|
387
|
-
colorModeScript?: string;
|
|
388
|
-
/**
|
|
389
|
-
* CSRF protection. Default `true` (origin check). `false` disables.
|
|
390
|
-
* Pass `CsrfOptions` to override (e.g. token mode).
|
|
391
|
-
*/
|
|
392
|
-
csrf?: boolean | CsrfOptions;
|
|
393
|
-
/**
|
|
394
|
-
* Security response headers. Default `true`. `false` disables.
|
|
395
|
-
*/
|
|
396
|
-
securityHeaders?: boolean | SecurityHeadersOptions;
|
|
397
|
-
/**
|
|
398
|
-
* Cross-request fetch Data Cache (`next: { revalidate, tags }`).
|
|
399
|
-
* Default `true`. Dev still skips cache unless `forceDevCache`.
|
|
400
|
-
*/
|
|
401
|
-
dataCache?: boolean | DataCacheMiddlewareOptions;
|
|
402
|
-
/**
|
|
403
|
-
* HTTP / ISR cache store. Default is in-process memory (not shared
|
|
404
|
-
* across instances). Pass `loadFsCacheStore(dir)`(Node fs 后端,动态加载)for a Node backend.
|
|
405
|
-
*/
|
|
406
|
-
cacheStore?: CacheStore;
|
|
407
|
-
/** Declarative cache backend. `store: 'fs'` 走 `loadFsCacheStore()`(Node-only,动态加载)。 */
|
|
408
|
-
cache?: {
|
|
409
|
-
store?: 'memory' | 'fs';
|
|
410
|
-
dir?: string;
|
|
411
|
-
};
|
|
412
|
-
/**
|
|
413
|
-
* File-convention SEO (`src/sitemap.ts`, `robots.ts`, …). Default: on when
|
|
414
|
-
* `rootDir` or `seoConventions.srcDir` is set. `false` disables.
|
|
415
|
-
*/
|
|
416
|
-
seoConventions?: boolean | {
|
|
417
|
-
srcDir?: string;
|
|
418
|
-
};
|
|
419
|
-
/**
|
|
420
|
-
* Preloaded SEO convention modules (production `import.meta.glob`). When
|
|
421
|
-
* set, disk discovery is skipped — required on serverless.
|
|
422
|
-
*/
|
|
423
|
-
seoConventionModules?: Record<string, {
|
|
424
|
-
default?: unknown;
|
|
425
|
-
}>;
|
|
426
|
-
/**
|
|
427
|
-
* Production `/_ipx` handler (from `@ubean/image` when `image` is enabled).
|
|
428
|
-
* Dev still uses the Vite middleware.
|
|
429
|
-
*/
|
|
430
|
-
ipxHandler?: MiddlewareHandler<UbeanEnv$1>;
|
|
431
|
-
}
|
|
432
|
-
interface UbeanAppPlugin {
|
|
433
|
-
name: string;
|
|
434
|
-
/** Called after app is created but before routes are registered */
|
|
435
|
-
setup?: (app: UbeanApp) => void | Promise<void>;
|
|
436
|
-
/** Called after all routes are registered */
|
|
437
|
-
ready?: (app: UbeanApp) => void | Promise<void>;
|
|
438
|
-
}
|
|
439
|
-
export declare class UbeanApp {
|
|
440
|
-
readonly hono: Hono<UbeanEnv$1>;
|
|
441
|
-
readonly hooks: Hookable<UbeanRuntimeHooks>;
|
|
442
|
-
readonly plugins: UbeanAppPlugin[];
|
|
443
|
-
readonly options: UbeanAppOptions;
|
|
444
|
-
private _ready;
|
|
445
|
-
/**
|
|
446
|
-
* Scalar 文档页(`/_scalar`)专用的 CSP:生效 CSP + `{@link SCALAR_SCRIPT_ORIGIN}`。
|
|
447
|
-
*
|
|
448
|
-
* 该页面从 CDN 取脚本,而 CSP 是全局的一份 —— 只在这一条响应上追加它需要的来源,不放宽应用
|
|
449
|
-
* 其余部分的策略。CSP 被关闭时为 `undefined`(不重加头)。构造期算好,`init()` 注册路由时用。
|
|
450
|
-
*/
|
|
451
|
-
private _scalarCsp;
|
|
452
|
-
constructor(options?: UbeanAppOptions);
|
|
453
|
-
private _setupBaseMiddleware;
|
|
454
|
-
init(): Promise<this>;
|
|
455
|
-
private _registerSeoConventions;
|
|
456
|
-
private _lazyInitPromise;
|
|
457
|
-
lazyInit(): Promise<this>;
|
|
458
|
-
resetInit(): void;
|
|
459
|
-
private _setupFallback;
|
|
460
|
-
use(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
461
|
-
use(...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
462
|
-
on(method: string | string[], path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
463
|
-
get(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
464
|
-
post(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
465
|
-
put(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
466
|
-
patch(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
467
|
-
delete(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
468
|
-
fetch: Hono<UbeanEnv$1>['fetch'];
|
|
469
|
-
request: Hono<UbeanEnv$1>['request'];
|
|
470
|
-
}
|
|
471
|
-
interface AppPlugin {
|
|
472
|
-
name: string;
|
|
473
|
-
setup?: (app: Hono<UbeanEnv$1>) => void | Promise<void>;
|
|
474
|
-
}
|
|
475
|
-
export declare function createUbeanApp(options?: UbeanAppOptions): UbeanApp;
|
|
476
|
-
//#endregion
|
|
477
|
-
export type { AppPlugin, ComposedHandler, DefineServerOptions, GlobalHooks, Handle, HandleError, HandleErrorInput, HandleEvent, HandleFetch, HandleFetchInput, HandleInput, PageAssetTags, PageRenderer, RegisterOptions, ResolvedServerConfig, RouteMeta, RouteRegistrar, RouteRule, ScannedApiRoute, ScannedLayout, ScannedMiddleware, ScannedPageRoute, ServerHooks, UbeanAppOptions, UbeanAppPlugin, UbeanEnv, UbeanMiddleware, UbeanRuntimeHooks };
|
|
477
|
+
export type { AppPlugin, ComposedHandler, DefineServerOptions, GlobalHooks, Handle, HandleError, HandleErrorInput, HandleEvent, HandleFetch, HandleFetchInput, HandleInput, PageAssetTags, PageRenderer, RegisterOptions, ResolvedServerConfig, RouteMeta, RouteRegistrar, RouteRule, ScannedApiRoute, ScannedLayout, ScannedMiddleware, ScannedPageRoute, ServerHooks, UbeanAppOptions, UbeanAppPlugin, UbeanEnv, UbeanMiddleware, UbeanMiddlewareStep, UbeanRuntimeHooks };
|
package/dist/index.js
CHANGED
|
@@ -113,109 +113,6 @@ async function applyHandleErrorHook(c, error, status) {
|
|
|
113
113
|
});
|
|
114
114
|
}
|
|
115
115
|
//#endregion
|
|
116
|
-
//#region src/define-server.ts
|
|
117
|
-
/**
|
|
118
|
-
* Apply a resolved server config to a `UbeanApp` instance.
|
|
119
|
-
*
|
|
120
|
-
* This must be called BEFORE `app.init()` so that:
|
|
121
|
-
* - `plugins` are available when `init()` calls `setup` / `ready`
|
|
122
|
-
* - `hooks` are registered before `init()` fires `app:created` etc.
|
|
123
|
-
* - `onAppCreate` runs before route registration
|
|
124
|
-
* - `globalHooks` (handle/handleFetch/handleError) are set before any request
|
|
125
|
-
*
|
|
126
|
-
* `onServerReady` is NOT called here — the caller must invoke it after
|
|
127
|
-
* `app.init()` completes.
|
|
128
|
-
*/
|
|
129
|
-
async function applyServerConfig(app, config) {
|
|
130
|
-
if (config.plugins.length > 0) app.plugins.push(...config.plugins);
|
|
131
|
-
for (const [name, handler] of Object.entries(config.hooks)) if (handler) app.hooks.hook(name, handler);
|
|
132
|
-
if (config.globalHooks) setGlobalHooks(config.globalHooks);
|
|
133
|
-
if (config.onAppCreate) await config.onAppCreate(app);
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Define the backend server configuration.
|
|
137
|
-
*
|
|
138
|
-
* This is the server-side counterpart of `defineApp`. It allows users to
|
|
139
|
-
* inject plugins, register runtime hooks, and run startup/ready logic
|
|
140
|
-
* from a simple entry file (`src/server.ts`).
|
|
141
|
-
*
|
|
142
|
-
* @example
|
|
143
|
-
* ```ts
|
|
144
|
-
* // src/server.ts
|
|
145
|
-
* import { defineServer } from '@ubean/app';
|
|
146
|
-
*
|
|
147
|
-
* export default defineServer({
|
|
148
|
-
* plugins: [
|
|
149
|
-
* {
|
|
150
|
-
* name: 'my-plugin',
|
|
151
|
-
* setup(app) { app.use('/api/custom', handler); },
|
|
152
|
-
* ready(app) { /* routes registered *\/ }
|
|
153
|
-
* }
|
|
154
|
-
* ],
|
|
155
|
-
* hooks: {
|
|
156
|
-
* 'request:start': (c) => { console.log(c.req.method, c.req.path); }
|
|
157
|
-
* },
|
|
158
|
-
* globalHooks: {
|
|
159
|
-
* handle: async ({ event, resolve }) => {
|
|
160
|
-
* const response = await resolve(event);
|
|
161
|
-
* response.headers.set('X-Custom', 'ubean');
|
|
162
|
-
* return response;
|
|
163
|
-
* },
|
|
164
|
-
* handleError: async ({ error, status }) => {
|
|
165
|
-
* console.error(`[${status}]`, error);
|
|
166
|
-
* }
|
|
167
|
-
* },
|
|
168
|
-
* onAppCreate: async (app) => { /* init db *\/ },
|
|
169
|
-
* onServerReady: async (app) => { /* start workers *\/ }
|
|
170
|
-
* });
|
|
171
|
-
* ```
|
|
172
|
-
*/
|
|
173
|
-
function defineServer(options) {
|
|
174
|
-
return {
|
|
175
|
-
plugins: options.plugins || [],
|
|
176
|
-
hooks: options.hooks || {},
|
|
177
|
-
globalHooks: options.globalHooks,
|
|
178
|
-
onAppCreate: options.onAppCreate,
|
|
179
|
-
onServerReady: options.onServerReady
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Create an empty server config — used as the fallback when no
|
|
184
|
-
* `src/server.ts` file exists.
|
|
185
|
-
*/
|
|
186
|
-
function createDefaultServerConfig() {
|
|
187
|
-
return {
|
|
188
|
-
plugins: [],
|
|
189
|
-
hooks: {}
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Merge multiple server configs (shared + mode-specific) into one.
|
|
194
|
-
* Plugins are concatenated; hooks are merged; mode-specific callbacks
|
|
195
|
-
* override shared ones.
|
|
196
|
-
*/
|
|
197
|
-
function mergeServerConfigs(base, ...configs) {
|
|
198
|
-
const result = {
|
|
199
|
-
plugins: [...base.plugins],
|
|
200
|
-
hooks: { ...base.hooks },
|
|
201
|
-
globalHooks: base.globalHooks ? { ...base.globalHooks } : void 0,
|
|
202
|
-
onAppCreate: base.onAppCreate,
|
|
203
|
-
onServerReady: base.onServerReady
|
|
204
|
-
};
|
|
205
|
-
for (const cfg of configs) {
|
|
206
|
-
if (!cfg) continue;
|
|
207
|
-
if (cfg.plugins) result.plugins.push(...cfg.plugins);
|
|
208
|
-
if (cfg.hooks) Object.assign(result.hooks, cfg.hooks);
|
|
209
|
-
if (cfg.globalHooks) result.globalHooks = {
|
|
210
|
-
...result.globalHooks,
|
|
211
|
-
...cfg.globalHooks
|
|
212
|
-
};
|
|
213
|
-
if (cfg.onAppCreate) result.onAppCreate = cfg.onAppCreate;
|
|
214
|
-
if (cfg.onServerReady) result.onServerReady = cfg.onServerReady;
|
|
215
|
-
}
|
|
216
|
-
return result;
|
|
217
|
-
}
|
|
218
|
-
//#endregion
|
|
219
116
|
//#region src/app.ts
|
|
220
117
|
const actionContextAls = new AsyncLocalStorage();
|
|
221
118
|
bindActionContextStorage(actionContextAls);
|
|
@@ -261,6 +158,35 @@ function resolveToggle(value, defaultOn) {
|
|
|
261
158
|
if (value === true) return {};
|
|
262
159
|
return value;
|
|
263
160
|
}
|
|
161
|
+
/**
|
|
162
|
+
* TS-07:把中间件链的每一步按**注册/执行顺序**记进请求级变量。
|
|
163
|
+
*
|
|
164
|
+
* 顺序是结构性事实 —— 13 步表(见 `_setupBaseMiddleware()` 与本包 middleware-order 测试)把它
|
|
165
|
+
* 固定下来,改动注册顺序即破坏契约。记录值只用于可观测性断言(`GET /_health` 回读),不参与任何请求处理逻辑。
|
|
166
|
+
*/
|
|
167
|
+
function markMiddlewareStep(c, step) {
|
|
168
|
+
const recorded = c.get("__ubean_mw_order__");
|
|
169
|
+
c.set("__ubean_mw_order__", recorded ? [...recorded, step] : [step]);
|
|
170
|
+
}
|
|
171
|
+
/** 给中间件套一层「记录步骤名」外壳;注册顺序与不套壳时完全一致。 */
|
|
172
|
+
function withStep(step, handler) {
|
|
173
|
+
return async (c, next) => {
|
|
174
|
+
markMiddlewareStep(c, step);
|
|
175
|
+
return handler(c, next);
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* TS-07:链上存在「不是中间件、但有固定位置」的步骤(如 ⑦ cacheStore 初始化)。
|
|
180
|
+
*
|
|
181
|
+
* 为了让 13 步全序可观测,这里在该位置插一个**纯记录、纯透传**的空壳:它不读不写请求、
|
|
182
|
+
* 不改响应,只把步骤名按注册位置记进请求级序列。
|
|
183
|
+
*/
|
|
184
|
+
function recordOnlyStep(step) {
|
|
185
|
+
return async (c, next) => {
|
|
186
|
+
markMiddlewareStep(c, step);
|
|
187
|
+
return next();
|
|
188
|
+
};
|
|
189
|
+
}
|
|
264
190
|
var UbeanApp = class {
|
|
265
191
|
hono;
|
|
266
192
|
hooks;
|
|
@@ -283,55 +209,56 @@ var UbeanApp = class {
|
|
|
283
209
|
this._setupFallback();
|
|
284
210
|
}
|
|
285
211
|
_setupBaseMiddleware() {
|
|
286
|
-
this.hono.use("*", async (c, next) => {
|
|
212
|
+
this.hono.use("*", withStep("handle", async (c, next) => {
|
|
287
213
|
if (!await applyHandleHook(c, next)) await next();
|
|
288
|
-
});
|
|
289
|
-
this.hono.use("*", requestId());
|
|
290
|
-
this.hono.use("*", async (c, next) => {
|
|
214
|
+
}));
|
|
215
|
+
this.hono.use("*", withStep("requestId", requestId()));
|
|
216
|
+
this.hono.use("*", withStep("actionContext", async (c, next) => {
|
|
291
217
|
await actionContextAls.run(buildActionContext(c), () => next());
|
|
292
|
-
});
|
|
218
|
+
}));
|
|
293
219
|
const securityHeaders = resolveToggle(this.options.securityHeaders, true);
|
|
294
220
|
if (securityHeaders !== false) {
|
|
295
221
|
const mergedSecurity = mergeSecurityHeadersOptions(DEFAULT_SECURITY_HEADERS, securityHeaders);
|
|
296
|
-
this.hono.use("*", createSecurityHeadersMiddleware(mergedSecurity));
|
|
222
|
+
this.hono.use("*", withStep("securityHeaders", createSecurityHeadersMiddleware(mergedSecurity)));
|
|
297
223
|
const effectiveCsp = mergedSecurity.contentSecurityPolicy;
|
|
298
224
|
if (effectiveCsp && typeof effectiveCsp === "object") this._scalarCsp = serializeCsp(extendCspScriptSrc(effectiveCsp, [SCALAR_SCRIPT_ORIGIN]));
|
|
299
225
|
}
|
|
300
226
|
const csrf = resolveToggle(this.options.csrf, true);
|
|
301
|
-
if (csrf !== false) this.hono.use("*", createCsrfMiddleware({
|
|
227
|
+
if (csrf !== false) this.hono.use("*", withStep("csrf", createCsrfMiddleware({
|
|
302
228
|
mode: "origin",
|
|
303
229
|
...csrf,
|
|
304
230
|
exclude: [...DEFAULT_CSRF_EXCLUDE, ...csrf.exclude ?? []]
|
|
305
|
-
}));
|
|
231
|
+
})));
|
|
306
232
|
const dataCache = resolveToggle(this.options.dataCache, true);
|
|
307
|
-
if (dataCache !== false) this.hono.use("*", createDataCacheMiddleware(dataCache));
|
|
233
|
+
if (dataCache !== false) this.hono.use("*", withStep("dataCache", createDataCacheMiddleware(dataCache)));
|
|
308
234
|
if (this.options.cacheStore) useCacheStore(this.options.cacheStore);
|
|
309
235
|
else if (this.options.cache?.store === "fs") {
|
|
310
236
|
const fsDir = this.options.cache.dir || ".ubean/cache";
|
|
311
237
|
useCacheStore(createLazyCacheStore(() => loadFsCacheStore(fsDir)));
|
|
312
238
|
}
|
|
239
|
+
if (this.options.cacheStore || this.options.cache?.store === "fs") this.hono.use("*", recordOnlyStep("cacheStore"));
|
|
313
240
|
const i18nCfg = this.options.i18nConfig;
|
|
314
241
|
if (i18nCfg?.enabled !== false && (i18nCfg?.locales?.length ?? 0) > 0 && i18nCfg) {
|
|
315
242
|
const locales = (i18nCfg.locales || []).map((l) => typeof l === "string" ? l : l.code);
|
|
316
|
-
this.hono.use("*", createI18nMiddleware({
|
|
243
|
+
this.hono.use("*", withStep("i18n", createI18nMiddleware({
|
|
317
244
|
defaultLocale: i18nCfg.defaultLocale || "en",
|
|
318
245
|
locales,
|
|
319
246
|
strategy: i18nCfg.strategy || "prefix_except_default",
|
|
320
247
|
detectBrowserLanguage: i18nCfg.detectBrowserLanguage,
|
|
321
248
|
loadMessages: (locale, fallback) => ensureLocaleMessages(locale, fallback)
|
|
322
|
-
}));
|
|
249
|
+
})));
|
|
323
250
|
}
|
|
324
251
|
if (this.options.routeRules && Object.keys(this.options.routeRules).length > 0) {
|
|
325
|
-
this.hono.use("*", createRouteRulesMiddleware(this.options.routeRules, { dispatch: (req) => Promise.resolve(this.hono.fetch(req)) }));
|
|
252
|
+
this.hono.use("*", withStep("routeRules", createRouteRulesMiddleware(this.options.routeRules, { dispatch: (req) => Promise.resolve(this.hono.fetch(req)) })));
|
|
326
253
|
const cacheRules = resolveRouteCacheRules(this.options.routeRules);
|
|
327
254
|
const hasIsrRules = Object.values(this.options.routeRules).some((r) => r?.isr !== void 0);
|
|
328
255
|
if (Object.keys(cacheRules).length > 0 || hasIsrRules) {
|
|
329
256
|
if (!this.options.cacheStore && this.options.cache?.store !== "fs") useCacheStore(createMemoryStore());
|
|
330
|
-
if (Object.keys(cacheRules).length > 0) this.hono.use("*", createCacheMiddleware({ rules: cacheRules }));
|
|
257
|
+
if (Object.keys(cacheRules).length > 0) this.hono.use("*", withStep("routeCache", createCacheMiddleware({ rules: cacheRules })));
|
|
331
258
|
}
|
|
332
259
|
}
|
|
333
|
-
this.hono.use("*", createWebSocketMiddleware());
|
|
334
|
-
this.hono.use("*", async (c, next) => {
|
|
260
|
+
this.hono.use("*", withStep("websocket", createWebSocketMiddleware()));
|
|
261
|
+
this.hono.use("*", withStep("lifecycle", async (c, next) => {
|
|
335
262
|
c.set("route", {
|
|
336
263
|
meta: { requiresAuth: true },
|
|
337
264
|
path: c.req.path,
|
|
@@ -345,13 +272,17 @@ var UbeanApp = class {
|
|
|
345
272
|
await this.hooks.callHook("request:error", c, err);
|
|
346
273
|
throw err;
|
|
347
274
|
}
|
|
348
|
-
});
|
|
349
|
-
if (this.options.healthEndpoint !== false)
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
275
|
+
}));
|
|
276
|
+
if (this.options.healthEndpoint !== false) {
|
|
277
|
+
this.hono.use("*", recordOnlyStep("healthEndpoint"));
|
|
278
|
+
this.hono.get("/_health", (c) => {
|
|
279
|
+
return c.json({
|
|
280
|
+
status: "ok",
|
|
281
|
+
timestamp: Date.now(),
|
|
282
|
+
mwOrder: c.get("__ubean_mw_order__") ?? []
|
|
283
|
+
});
|
|
353
284
|
});
|
|
354
|
-
}
|
|
285
|
+
}
|
|
355
286
|
}
|
|
356
287
|
async init() {
|
|
357
288
|
if (this._ready) return this;
|
|
@@ -491,4 +422,107 @@ function createUbeanApp(options = {}) {
|
|
|
491
422
|
return new UbeanApp(options);
|
|
492
423
|
}
|
|
493
424
|
//#endregion
|
|
425
|
+
//#region src/define-server.ts
|
|
426
|
+
/**
|
|
427
|
+
* Apply a resolved server config to a `UbeanApp` instance.
|
|
428
|
+
*
|
|
429
|
+
* This must be called BEFORE `app.init()` so that:
|
|
430
|
+
* - `plugins` are available when `init()` calls `setup` / `ready`
|
|
431
|
+
* - `hooks` are registered before `init()` fires `app:created` etc.
|
|
432
|
+
* - `onAppCreate` runs before route registration
|
|
433
|
+
* - `globalHooks` (handle/handleFetch/handleError) are set before any request
|
|
434
|
+
*
|
|
435
|
+
* `onServerReady` is NOT called here — the caller must invoke it after
|
|
436
|
+
* `app.init()` completes.
|
|
437
|
+
*/
|
|
438
|
+
async function applyServerConfig(app, config) {
|
|
439
|
+
if (config.plugins.length > 0) app.plugins.push(...config.plugins);
|
|
440
|
+
for (const [name, handler] of Object.entries(config.hooks)) if (handler) app.hooks.hook(name, handler);
|
|
441
|
+
if (config.globalHooks) setGlobalHooks(config.globalHooks);
|
|
442
|
+
if (config.onAppCreate) await config.onAppCreate(app);
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Define the backend server configuration.
|
|
446
|
+
*
|
|
447
|
+
* This is the server-side counterpart of `defineApp`. It allows users to
|
|
448
|
+
* inject plugins, register runtime hooks, and run startup/ready logic
|
|
449
|
+
* from a simple entry file (`src/server.ts`).
|
|
450
|
+
*
|
|
451
|
+
* @example
|
|
452
|
+
* ```ts
|
|
453
|
+
* // src/server.ts
|
|
454
|
+
* import { defineServer } from '@ubean/app';
|
|
455
|
+
*
|
|
456
|
+
* export default defineServer({
|
|
457
|
+
* plugins: [
|
|
458
|
+
* {
|
|
459
|
+
* name: 'my-plugin',
|
|
460
|
+
* setup(app) { app.use('/api/custom', handler); },
|
|
461
|
+
* ready(app) { /* routes registered *\/ }
|
|
462
|
+
* }
|
|
463
|
+
* ],
|
|
464
|
+
* hooks: {
|
|
465
|
+
* 'request:start': (c) => { console.log(c.req.method, c.req.path); }
|
|
466
|
+
* },
|
|
467
|
+
* globalHooks: {
|
|
468
|
+
* handle: async ({ event, resolve }) => {
|
|
469
|
+
* const response = await resolve(event);
|
|
470
|
+
* response.headers.set('X-Custom', 'ubean');
|
|
471
|
+
* return response;
|
|
472
|
+
* },
|
|
473
|
+
* handleError: async ({ error, status }) => {
|
|
474
|
+
* console.error(`[${status}]`, error);
|
|
475
|
+
* }
|
|
476
|
+
* },
|
|
477
|
+
* onAppCreate: async (app) => { /* init db *\/ },
|
|
478
|
+
* onServerReady: async (app) => { /* start workers *\/ }
|
|
479
|
+
* });
|
|
480
|
+
* ```
|
|
481
|
+
*/
|
|
482
|
+
function defineServer(options) {
|
|
483
|
+
return {
|
|
484
|
+
plugins: options.plugins || [],
|
|
485
|
+
hooks: options.hooks || {},
|
|
486
|
+
globalHooks: options.globalHooks,
|
|
487
|
+
onAppCreate: options.onAppCreate,
|
|
488
|
+
onServerReady: options.onServerReady
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Create an empty server config — used as the fallback when no
|
|
493
|
+
* `src/server.ts` file exists.
|
|
494
|
+
*/
|
|
495
|
+
function createDefaultServerConfig() {
|
|
496
|
+
return {
|
|
497
|
+
plugins: [],
|
|
498
|
+
hooks: {}
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Merge multiple server configs (shared + mode-specific) into one.
|
|
503
|
+
* Plugins are concatenated; hooks are merged; mode-specific callbacks
|
|
504
|
+
* override shared ones.
|
|
505
|
+
*/
|
|
506
|
+
function mergeServerConfigs(base, ...configs) {
|
|
507
|
+
const result = {
|
|
508
|
+
plugins: [...base.plugins],
|
|
509
|
+
hooks: { ...base.hooks },
|
|
510
|
+
globalHooks: base.globalHooks ? { ...base.globalHooks } : void 0,
|
|
511
|
+
onAppCreate: base.onAppCreate,
|
|
512
|
+
onServerReady: base.onServerReady
|
|
513
|
+
};
|
|
514
|
+
for (const cfg of configs) {
|
|
515
|
+
if (!cfg) continue;
|
|
516
|
+
if (cfg.plugins) result.plugins.push(...cfg.plugins);
|
|
517
|
+
if (cfg.hooks) Object.assign(result.hooks, cfg.hooks);
|
|
518
|
+
if (cfg.globalHooks) result.globalHooks = {
|
|
519
|
+
...result.globalHooks,
|
|
520
|
+
...cfg.globalHooks
|
|
521
|
+
};
|
|
522
|
+
if (cfg.onAppCreate) result.onAppCreate = cfg.onAppCreate;
|
|
523
|
+
if (cfg.onServerReady) result.onServerReady = cfg.onServerReady;
|
|
524
|
+
}
|
|
525
|
+
return result;
|
|
526
|
+
}
|
|
527
|
+
//#endregion
|
|
494
528
|
export { UbeanApp, applyHandleErrorHook, applyHandleFetchHook, applyHandleHook, applyServerConfig, clearGlobalHooks, createDefaultServerConfig, createHandleEvent, createUbeanApp, defineServer, extractErrorMessage, getGlobalHooks, mergeServerConfigs, setGlobalHooks, wrapResolve };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ubean/app",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1-beta.2",
|
|
4
4
|
"description": "Hono app factory and server config for ubean (createUbeanApp, defineServer)",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -16,26 +16,26 @@
|
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@ubean/i18n": "0.6.
|
|
20
|
-
"@ubean/islands": "0.6.
|
|
21
|
-
"@ubean/routes": "0.6.
|
|
22
|
-
"@ubean/scan": "0.6.
|
|
23
|
-
"@ubean/server": "0.6.
|
|
24
|
-
"@ubean/shared": "0.6.
|
|
25
|
-
"hono": "4.13.
|
|
19
|
+
"@ubean/i18n": "0.6.1-beta.2",
|
|
20
|
+
"@ubean/islands": "0.6.1-beta.2",
|
|
21
|
+
"@ubean/routes": "0.6.1-beta.2",
|
|
22
|
+
"@ubean/scan": "0.6.1-beta.2",
|
|
23
|
+
"@ubean/server": "0.6.1-beta.2",
|
|
24
|
+
"@ubean/shared": "0.6.1-beta.2",
|
|
25
|
+
"hono": "4.13.13",
|
|
26
26
|
"hookable": "^6.1.2",
|
|
27
27
|
"pathe": "^2.0.3"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@types/node": "^26.6.
|
|
31
|
-
"@ubean/pages": "0.6.
|
|
32
|
-
"@ubean/seo": "0.6.
|
|
30
|
+
"@types/node": "^26.6.4",
|
|
31
|
+
"@ubean/pages": "0.6.1-beta.2",
|
|
32
|
+
"@ubean/seo": "0.6.1-beta.2",
|
|
33
33
|
"typescript": "npm:typescript-native-bridge@latest",
|
|
34
|
-
"vite-plus": "1.
|
|
34
|
+
"vite-plus": "1.1.0"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@ubean/pages": "0.6.
|
|
38
|
-
"@ubean/seo": "0.6.
|
|
37
|
+
"@ubean/pages": "0.6.1-beta.2",
|
|
38
|
+
"@ubean/seo": "0.6.1-beta.2"
|
|
39
39
|
},
|
|
40
40
|
"peerDependenciesMeta": {
|
|
41
41
|
"@ubean/pages": {
|