@ubean/app 0.5.2 → 0.6.0-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 +9 -2
- package/dist/index.js +32 -13
- package/package.json +15 -15
package/dist/index.d.ts
CHANGED
|
@@ -401,10 +401,10 @@ interface UbeanAppOptions {
|
|
|
401
401
|
dataCache?: boolean | DataCacheMiddlewareOptions;
|
|
402
402
|
/**
|
|
403
403
|
* HTTP / ISR cache store. Default is in-process memory (not shared
|
|
404
|
-
* across instances). Pass `
|
|
404
|
+
* across instances). Pass `loadFsCacheStore(dir)`(Node fs 后端,动态加载)for a Node backend.
|
|
405
405
|
*/
|
|
406
406
|
cacheStore?: CacheStore;
|
|
407
|
-
/** Declarative cache backend. `store: 'fs'`
|
|
407
|
+
/** Declarative cache backend. `store: 'fs'` 走 `loadFsCacheStore()`(Node-only,动态加载)。 */
|
|
408
408
|
cache?: {
|
|
409
409
|
store?: 'memory' | 'fs';
|
|
410
410
|
dir?: string;
|
|
@@ -442,6 +442,13 @@ export declare class UbeanApp {
|
|
|
442
442
|
readonly plugins: UbeanAppPlugin[];
|
|
443
443
|
readonly options: UbeanAppOptions;
|
|
444
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;
|
|
445
452
|
constructor(options?: UbeanAppOptions);
|
|
446
453
|
private _setupBaseMiddleware;
|
|
447
454
|
init(): Promise<this>;
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
2
|
import { createI18nMiddleware, ensureLocaleMessages } from "@ubean/i18n";
|
|
4
3
|
import { SERVER_COMPONENT_ENDPOINT, createServerComponentMiddleware } from "@ubean/islands/server";
|
|
5
|
-
import { ACTIONS_ENDPOINT, bindActionContextStorage, buildActionContext, createActionsMiddleware, createRouteRulesMiddleware, registerOpenAPIRoutes, registerRoutes, setInternalFetcher } from "@ubean/routes";
|
|
6
|
-
import { createCacheMiddleware,
|
|
4
|
+
import { ACTIONS_ENDPOINT, SCALAR_SCRIPT_ORIGIN, bindActionContextStorage, buildActionContext, createActionsMiddleware, createRouteRulesMiddleware, registerOpenAPIRoutes, registerRoutes, setInternalFetcher } from "@ubean/routes";
|
|
5
|
+
import { createCacheMiddleware, createLazyCacheStore, createMemoryStore, loadFsCacheStore, resolveRouteCacheRules, useCacheStore } from "@ubean/server/cache";
|
|
7
6
|
import { createDataCacheMiddleware } from "@ubean/server/middleware";
|
|
8
7
|
import { createWebSocketMiddleware } from "@ubean/server/realtime";
|
|
9
|
-
import { createCsrfMiddleware, createSecurityHeadersMiddleware, mergeSecurityHeadersOptions } from "@ubean/server/security";
|
|
10
|
-
import {
|
|
11
|
-
import { UbeanError, errorToResponse, isUbeanError } from "@ubean/shared";
|
|
8
|
+
import { createCsrfMiddleware, createSecurityHeadersMiddleware, extendCspScriptSrc, mergeSecurityHeadersOptions, serializeCsp } from "@ubean/server/security";
|
|
9
|
+
import { UbeanError, errorToResponse, isNodeRuntime, isUbeanError } from "@ubean/shared";
|
|
12
10
|
import { Hono } from "hono";
|
|
13
11
|
import { requestId } from "hono/request-id";
|
|
14
12
|
import { createHooks } from "hookable";
|
|
@@ -269,6 +267,13 @@ var UbeanApp = class {
|
|
|
269
267
|
plugins;
|
|
270
268
|
options;
|
|
271
269
|
_ready = false;
|
|
270
|
+
/**
|
|
271
|
+
* Scalar 文档页(`/_scalar`)专用的 CSP:生效 CSP + `{@link SCALAR_SCRIPT_ORIGIN}`。
|
|
272
|
+
*
|
|
273
|
+
* 该页面从 CDN 取脚本,而 CSP 是全局的一份 —— 只在这一条响应上追加它需要的来源,不放宽应用
|
|
274
|
+
* 其余部分的策略。CSP 被关闭时为 `undefined`(不重加头)。构造期算好,`init()` 注册路由时用。
|
|
275
|
+
*/
|
|
276
|
+
_scalarCsp;
|
|
272
277
|
constructor(options = {}) {
|
|
273
278
|
this.options = options;
|
|
274
279
|
this.hono = new Hono({ strict: false });
|
|
@@ -286,7 +291,12 @@ var UbeanApp = class {
|
|
|
286
291
|
await actionContextAls.run(buildActionContext(c), () => next());
|
|
287
292
|
});
|
|
288
293
|
const securityHeaders = resolveToggle(this.options.securityHeaders, true);
|
|
289
|
-
if (securityHeaders !== false)
|
|
294
|
+
if (securityHeaders !== false) {
|
|
295
|
+
const mergedSecurity = mergeSecurityHeadersOptions(DEFAULT_SECURITY_HEADERS, securityHeaders);
|
|
296
|
+
this.hono.use("*", createSecurityHeadersMiddleware(mergedSecurity));
|
|
297
|
+
const effectiveCsp = mergedSecurity.contentSecurityPolicy;
|
|
298
|
+
if (effectiveCsp && typeof effectiveCsp === "object") this._scalarCsp = serializeCsp(extendCspScriptSrc(effectiveCsp, [SCALAR_SCRIPT_ORIGIN]));
|
|
299
|
+
}
|
|
290
300
|
const csrf = resolveToggle(this.options.csrf, true);
|
|
291
301
|
if (csrf !== false) this.hono.use("*", createCsrfMiddleware({
|
|
292
302
|
mode: "origin",
|
|
@@ -296,7 +306,10 @@ var UbeanApp = class {
|
|
|
296
306
|
const dataCache = resolveToggle(this.options.dataCache, true);
|
|
297
307
|
if (dataCache !== false) this.hono.use("*", createDataCacheMiddleware(dataCache));
|
|
298
308
|
if (this.options.cacheStore) useCacheStore(this.options.cacheStore);
|
|
299
|
-
else if (this.options.cache?.store === "fs")
|
|
309
|
+
else if (this.options.cache?.store === "fs") {
|
|
310
|
+
const fsDir = this.options.cache.dir || ".ubean/cache";
|
|
311
|
+
useCacheStore(createLazyCacheStore(() => loadFsCacheStore(fsDir)));
|
|
312
|
+
}
|
|
300
313
|
const i18nCfg = this.options.i18nConfig;
|
|
301
314
|
if (i18nCfg?.enabled !== false && (i18nCfg?.locales?.length ?? 0) > 0 && i18nCfg) {
|
|
302
315
|
const locales = (i18nCfg.locales || []).map((l) => typeof l === "string" ? l : l.code);
|
|
@@ -345,8 +358,10 @@ var UbeanApp = class {
|
|
|
345
358
|
await this.hooks.callHook("app:created", this.hono);
|
|
346
359
|
for (const plugin of this.plugins) if (plugin.setup) await plugin.setup(this);
|
|
347
360
|
await this.hooks.callHook("app:before:register", this.hono);
|
|
348
|
-
if (this.options.publicDir) {
|
|
361
|
+
if (this.options.publicDir && isNodeRuntime()) {
|
|
362
|
+
const { existsSync } = await import("node:fs");
|
|
349
363
|
const publicDir = isAbsolute(this.options.publicDir) ? this.options.publicDir : this.options.rootDir ? join(this.options.rootDir, this.options.publicDir) : this.options.publicDir;
|
|
364
|
+
const { serveStatic } = await import("@ubean/server/static");
|
|
350
365
|
if (existsSync(publicDir)) this.hono.use("/*", serveStatic({ publicDir }));
|
|
351
366
|
}
|
|
352
367
|
const registerOpts = {
|
|
@@ -373,15 +388,18 @@ var UbeanApp = class {
|
|
|
373
388
|
colorModeScript: this.options.colorModeScript,
|
|
374
389
|
cacheStore: this.options.routeRules && Object.keys(this.options.routeRules).length > 0 ? useCacheStore() : void 0
|
|
375
390
|
};
|
|
391
|
+
if (this.options.openAPI) {
|
|
392
|
+
const openAPIOpts = typeof this.options.openAPI === "object" ? this.options.openAPI : {};
|
|
393
|
+
registerOpenAPIRoutes(this.hono, {
|
|
394
|
+
...openAPIOpts,
|
|
395
|
+
contentSecurityPolicy: this._scalarCsp
|
|
396
|
+
});
|
|
397
|
+
}
|
|
376
398
|
await registerRoutes(this, registerOpts);
|
|
377
399
|
if (this.options.ipxHandler) this.hono.get("/_ipx/*", this.options.ipxHandler);
|
|
378
400
|
await this._registerSeoConventions();
|
|
379
401
|
this.hono.on("POST", ACTIONS_ENDPOINT, createActionsMiddleware());
|
|
380
402
|
this.hono.on("POST", SERVER_COMPONENT_ENDPOINT, createServerComponentMiddleware());
|
|
381
|
-
if (this.options.openAPI) {
|
|
382
|
-
const openAPIOpts = typeof this.options.openAPI === "object" ? this.options.openAPI : {};
|
|
383
|
-
registerOpenAPIRoutes(this.hono, openAPIOpts);
|
|
384
|
-
}
|
|
385
403
|
await this.hooks.callHook("app:after:register", this.hono);
|
|
386
404
|
setInternalFetcher((req) => applyHandleFetchHook(req, (r) => Promise.resolve(this.hono.fetch(r))));
|
|
387
405
|
for (const plugin of this.plugins) if (plugin.ready) await plugin.ready(this);
|
|
@@ -390,6 +408,7 @@ var UbeanApp = class {
|
|
|
390
408
|
}
|
|
391
409
|
async _registerSeoConventions() {
|
|
392
410
|
if (this.options.seoConventions === false) return;
|
|
411
|
+
if (!this.options.seoConventionModules && !isNodeRuntime()) return;
|
|
393
412
|
const srcDir = (typeof this.options.seoConventions === "object" ? this.options.seoConventions : {}).srcDir ?? (this.options.rootDir ? join(this.options.rootDir, "src") : void 0);
|
|
394
413
|
try {
|
|
395
414
|
const mod = await import("@ubean/seo/conventions");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ubean/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0-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.
|
|
20
|
-
"@ubean/islands": "0.
|
|
21
|
-
"@ubean/routes": "0.
|
|
22
|
-
"@ubean/scan": "0.
|
|
23
|
-
"@ubean/server": "0.
|
|
24
|
-
"@ubean/shared": "0.
|
|
25
|
-
"hono": "4.13.
|
|
26
|
-
"hookable": "^6.1.
|
|
19
|
+
"@ubean/i18n": "0.6.0-beta.2",
|
|
20
|
+
"@ubean/islands": "0.6.0-beta.2",
|
|
21
|
+
"@ubean/routes": "0.6.0-beta.2",
|
|
22
|
+
"@ubean/scan": "0.6.0-beta.2",
|
|
23
|
+
"@ubean/server": "0.6.0-beta.2",
|
|
24
|
+
"@ubean/shared": "0.6.0-beta.2",
|
|
25
|
+
"hono": "4.13.8",
|
|
26
|
+
"hookable": "^6.1.2",
|
|
27
27
|
"pathe": "^2.0.3"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@types/node": "^26.
|
|
31
|
-
"@ubean/pages": "0.
|
|
32
|
-
"@ubean/seo": "0.
|
|
30
|
+
"@types/node": "^26.6.1",
|
|
31
|
+
"@ubean/pages": "0.6.0-beta.2",
|
|
32
|
+
"@ubean/seo": "0.6.0-beta.2",
|
|
33
33
|
"typescript": "npm:typescript-native-bridge@latest",
|
|
34
|
-
"vite-plus": "0.3.
|
|
34
|
+
"vite-plus": "0.3.3"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@ubean/pages": "0.
|
|
38
|
-
"@ubean/seo": "0.
|
|
37
|
+
"@ubean/pages": "0.6.0-beta.2",
|
|
38
|
+
"@ubean/seo": "0.6.0-beta.2"
|
|
39
39
|
},
|
|
40
40
|
"peerDependenciesMeta": {
|
|
41
41
|
"@ubean/pages": {
|