@ubean/app 0.1.2 → 0.1.4
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 +238 -0
- package/dist/index.js +240 -0
- package/package.json +9 -9
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { Context, Hono, MiddlewareHandler, Next } from "hono";
|
|
2
|
+
import { RegisterOptions, RouteRegistrar } from "@ubean/api-routes";
|
|
3
|
+
import { Hookable } from "hookable";
|
|
4
|
+
import { ScannedApiRoute, ScannedApiRoute as ScannedApiRoute$1, ScannedCronTask, ScannedLayout, ScannedLayout as ScannedLayout$1, ScannedMiddleware, ScannedMiddleware as ScannedMiddleware$1, ScannedPageRoute, ScannedPageRoute as ScannedPageRoute$1 } from "@ubean/routing";
|
|
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/types";
|
|
6
|
+
//#region src/define-server.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* Apply a resolved server config to a `UbeanApp` instance.
|
|
9
|
+
*
|
|
10
|
+
* This must be called BEFORE `app.init()` so that:
|
|
11
|
+
* - `plugins` are available when `init()` calls `setup` / `ready`
|
|
12
|
+
* - `hooks` are registered before `init()` fires `app:created` etc.
|
|
13
|
+
* - `onAppCreate` runs before route registration
|
|
14
|
+
*
|
|
15
|
+
* `onServerReady` is NOT called here — the caller must invoke it after
|
|
16
|
+
* `app.init()` completes.
|
|
17
|
+
*/
|
|
18
|
+
declare function applyServerConfig(app: UbeanApp, config: ResolvedServerConfig): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Partial runtime hooks that users can register via `defineServer`.
|
|
21
|
+
* All hooks are optional — users only declare the ones they need.
|
|
22
|
+
*/
|
|
23
|
+
type ServerHooks = Partial<UbeanRuntimeHooks>;
|
|
24
|
+
/**
|
|
25
|
+
* Options for `defineServer` — the server-side counterpart of `defineApp`.
|
|
26
|
+
*
|
|
27
|
+
* Users create `src/server.ts` (shared), `src/server.dev.ts` (dev-only),
|
|
28
|
+
* or `src/server.prod.ts` (prod-only) and export the result of
|
|
29
|
+
* `defineServer(...)` as the default export.
|
|
30
|
+
*/
|
|
31
|
+
interface DefineServerOptions {
|
|
32
|
+
/**
|
|
33
|
+
* UbeanApp plugins to inject into `createUbeanApp({ plugins })`.
|
|
34
|
+
* Each plugin's `setup` runs before route registration; `ready` runs after.
|
|
35
|
+
*/
|
|
36
|
+
plugins?: UbeanAppPlugin[];
|
|
37
|
+
/**
|
|
38
|
+
* Runtime hooks registered on `app.hooks`.
|
|
39
|
+
* Available hooks: `app:created`, `app:before:register`, `app:after:register`,
|
|
40
|
+
* `request:start`, `request:end`, `request:error`, `route:register`,
|
|
41
|
+
* `middleware:register`, `error`.
|
|
42
|
+
*/
|
|
43
|
+
hooks?: ServerHooks;
|
|
44
|
+
/**
|
|
45
|
+
* Called after `UbeanApp` is created but before `app.init()`.
|
|
46
|
+
* Useful for initializing databases, external service connections, etc.
|
|
47
|
+
*/
|
|
48
|
+
onAppCreate?: (app: UbeanApp) => void | Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Called after `app.init()` completes (all routes/middleware registered).
|
|
51
|
+
* Useful for starting queue workers, cron schedulers, etc.
|
|
52
|
+
*/
|
|
53
|
+
onServerReady?: (app: UbeanApp) => void | Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolved server config — the normalized result of `defineServer`.
|
|
57
|
+
*/
|
|
58
|
+
interface ResolvedServerConfig {
|
|
59
|
+
plugins: UbeanAppPlugin[];
|
|
60
|
+
hooks: ServerHooks;
|
|
61
|
+
onAppCreate?: (app: UbeanApp) => void | Promise<void>;
|
|
62
|
+
onServerReady?: (app: UbeanApp) => void | Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Define the backend server configuration.
|
|
66
|
+
*
|
|
67
|
+
* This is the server-side counterpart of `defineApp`. It allows users to
|
|
68
|
+
* inject plugins, register runtime hooks, and run startup/ready logic
|
|
69
|
+
* from a simple entry file (`src/server.ts`).
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* // src/server.ts
|
|
74
|
+
* import { defineServer } from '@ubean/app';
|
|
75
|
+
*
|
|
76
|
+
* export default defineServer({
|
|
77
|
+
* plugins: [
|
|
78
|
+
* {
|
|
79
|
+
* name: 'my-plugin',
|
|
80
|
+
* setup(app) { app.use('/api/custom', handler); },
|
|
81
|
+
* ready(app) { /* routes registered *\/ }
|
|
82
|
+
* }
|
|
83
|
+
* ],
|
|
84
|
+
* hooks: {
|
|
85
|
+
* 'request:start': (c) => { console.log(c.req.method, c.req.path); }
|
|
86
|
+
* },
|
|
87
|
+
* onAppCreate: async (app) => { /* init db *\/ },
|
|
88
|
+
* onServerReady: async (app) => { /* start workers *\/ }
|
|
89
|
+
* });
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
declare function defineServer(options: DefineServerOptions): ResolvedServerConfig;
|
|
93
|
+
/**
|
|
94
|
+
* Create an empty server config — used as the fallback when no
|
|
95
|
+
* `src/server.ts` file exists.
|
|
96
|
+
*/
|
|
97
|
+
declare function createDefaultServerConfig(): ResolvedServerConfig;
|
|
98
|
+
/**
|
|
99
|
+
* Merge multiple server configs (shared + mode-specific) into one.
|
|
100
|
+
* Plugins are concatenated; hooks are merged; mode-specific callbacks
|
|
101
|
+
* override shared ones.
|
|
102
|
+
*/
|
|
103
|
+
declare function mergeServerConfigs(base: ResolvedServerConfig, ...configs: (ResolvedServerConfig | null | undefined)[]): ResolvedServerConfig;
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/app.d.ts
|
|
106
|
+
interface UbeanRuntimeHooks {
|
|
107
|
+
'app:created': (app: Hono<UbeanEnv$1>) => void | Promise<void>;
|
|
108
|
+
'app:before:register': (app: Hono<UbeanEnv$1>) => void | Promise<void>;
|
|
109
|
+
'app:after:register': (app: Hono<UbeanEnv$1>) => void | Promise<void>;
|
|
110
|
+
'request:start': (c: Context<UbeanEnv$1>) => void | Promise<void>;
|
|
111
|
+
'request:end': (c: Context<UbeanEnv$1>, res: Response) => void | Promise<void>;
|
|
112
|
+
'request:error': (c: Context<UbeanEnv$1>, err: Error) => void | Promise<void>;
|
|
113
|
+
'route:register': (route: {
|
|
114
|
+
method: string;
|
|
115
|
+
path: string;
|
|
116
|
+
handler: MiddlewareHandler[] | ComposedHandler$1 | Function;
|
|
117
|
+
meta?: RouteMeta$1;
|
|
118
|
+
}) => void | Promise<void>;
|
|
119
|
+
'middleware:register': (mw: ScannedMiddleware$1) => void | Promise<void>;
|
|
120
|
+
error: (err: Error, c: Context<UbeanEnv$1>) => void | Promise<void>;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Page renderer shape (satisfied by `@ubean/ssr`'s `PageRenderer`).
|
|
124
|
+
* Declared as a type alias to the actual `@ubean/pages`'s `PageRenderer`
|
|
125
|
+
* interface so consumers don't need to install `@ubean/pages` separately
|
|
126
|
+
* to type-check against `UbeanAppOptions.pageRenderer`.
|
|
127
|
+
*
|
|
128
|
+
* Type-only import works even when `@ubean/pages` is an optional peerDep —
|
|
129
|
+
* only runtime imports would fail. Consumers without `@ubean/pages` will
|
|
130
|
+
* see this type fall back to `any` (TS' default for missing modules under
|
|
131
|
+
* `skipLibCheck`).
|
|
132
|
+
*/
|
|
133
|
+
type PageRenderer = import('@ubean/pages').PageRenderer;
|
|
134
|
+
interface PageAssetTags {
|
|
135
|
+
head?: string;
|
|
136
|
+
bodyAttrs?: string;
|
|
137
|
+
htmlAttrs?: string;
|
|
138
|
+
}
|
|
139
|
+
interface UbeanAppOptions {
|
|
140
|
+
rootDir?: string;
|
|
141
|
+
routes?: ScannedApiRoute$1[];
|
|
142
|
+
middleware?: ScannedMiddleware$1[];
|
|
143
|
+
pages?: ScannedPageRoute$1[];
|
|
144
|
+
layouts?: ScannedLayout$1[];
|
|
145
|
+
crons?: ScannedCronTask[];
|
|
146
|
+
routeRules?: Record<string, RouteRule$1>;
|
|
147
|
+
plugins?: UbeanAppPlugin[];
|
|
148
|
+
routeLoaders?: Record<string, () => Promise<{
|
|
149
|
+
default?: ComposedHandler$1 | MiddlewareHandler[];
|
|
150
|
+
} | Record<string, ComposedHandler$1 | MiddlewareHandler[]>>>;
|
|
151
|
+
middlewareLoaders?: Record<string, () => Promise<{
|
|
152
|
+
default: UbeanMiddleware$1;
|
|
153
|
+
}>>;
|
|
154
|
+
pageLoaders?: Record<string, () => Promise<unknown>>;
|
|
155
|
+
pageRenderer?: PageRenderer | null;
|
|
156
|
+
pageAssetTags?: PageAssetTags;
|
|
157
|
+
publicDir?: string;
|
|
158
|
+
healthEndpoint?: boolean;
|
|
159
|
+
openAPI?: boolean | {
|
|
160
|
+
title?: string;
|
|
161
|
+
version?: string;
|
|
162
|
+
description?: string;
|
|
163
|
+
scalarPath?: string;
|
|
164
|
+
openAPIPath?: string;
|
|
165
|
+
};
|
|
166
|
+
i18nConfig?: {
|
|
167
|
+
strategy?: 'prefix' | 'prefix_except_default' | 'prefix_and_default' | 'no_prefix';
|
|
168
|
+
defaultLocale?: string;
|
|
169
|
+
locales?: string[];
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
interface UbeanAppPlugin {
|
|
173
|
+
name: string;
|
|
174
|
+
/** Called after app is created but before routes are registered */
|
|
175
|
+
setup?: (app: UbeanApp) => void | Promise<void>;
|
|
176
|
+
/** Called after all routes are registered */
|
|
177
|
+
ready?: (app: UbeanApp) => void | Promise<void>;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Structural view of the DevTools middleware returned by `createDevToolsMiddleware`
|
|
181
|
+
* in `@ubean/devtools`. Defined locally (rather than importing the real return
|
|
182
|
+
* type) so `ubean` has no static dependency on `@ubean/devtools` — the package is
|
|
183
|
+
* loaded via a dynamic `import()` only when DevTools is enabled.
|
|
184
|
+
*
|
|
185
|
+
* @deprecated DevTools is now a Vite plugin (`@ubean/devtools`'s
|
|
186
|
+
* `ubeanDevtoolsPlugin`) loaded by the dev runner. The Hono app no longer
|
|
187
|
+
* hosts DevTools middleware. This placeholder is kept only for type
|
|
188
|
+
* compatibility with external consumers that may still reference it.
|
|
189
|
+
*/
|
|
190
|
+
interface DevToolsInstance {
|
|
191
|
+
rpc: {
|
|
192
|
+
setRoutes(routes: never[]): void;
|
|
193
|
+
setPages(pages: never[]): void;
|
|
194
|
+
setMiddlewares(middlewares: never[]): void;
|
|
195
|
+
setLayouts(layouts: never[]): void;
|
|
196
|
+
setCrons(crons: never[]): void;
|
|
197
|
+
setPresets(presets: string[]): void;
|
|
198
|
+
setOpenAPI(openAPI: {
|
|
199
|
+
enabled: boolean;
|
|
200
|
+
scalarPath?: string;
|
|
201
|
+
openAPIPath?: string;
|
|
202
|
+
}): void;
|
|
203
|
+
setCustomTabs(tabs: never[]): void;
|
|
204
|
+
updateInfo(partial: Record<string, unknown>): void;
|
|
205
|
+
};
|
|
206
|
+
middleware: (c: Context<UbeanEnv$1>, next: Next) => Promise<Response | void>;
|
|
207
|
+
}
|
|
208
|
+
declare class UbeanApp {
|
|
209
|
+
readonly hono: Hono<UbeanEnv$1>;
|
|
210
|
+
readonly hooks: Hookable<UbeanRuntimeHooks>;
|
|
211
|
+
readonly plugins: UbeanAppPlugin[];
|
|
212
|
+
readonly options: UbeanAppOptions;
|
|
213
|
+
private _ready;
|
|
214
|
+
constructor(options?: UbeanAppOptions);
|
|
215
|
+
private _setupBaseMiddleware;
|
|
216
|
+
init(): Promise<this>;
|
|
217
|
+
private _lazyInitPromise;
|
|
218
|
+
lazyInit(): Promise<this>;
|
|
219
|
+
resetInit(): void;
|
|
220
|
+
private _setupFallback;
|
|
221
|
+
use(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
222
|
+
use(...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
223
|
+
on(method: string | string[], path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
224
|
+
get(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
225
|
+
post(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
226
|
+
put(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
227
|
+
patch(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
228
|
+
delete(path: string, ...handlers: MiddlewareHandler<UbeanEnv$1>[]): this;
|
|
229
|
+
fetch: Hono<UbeanEnv$1>['fetch'];
|
|
230
|
+
request: Hono<UbeanEnv$1>['request'];
|
|
231
|
+
}
|
|
232
|
+
interface AppPlugin {
|
|
233
|
+
name: string;
|
|
234
|
+
setup?: (app: Hono<UbeanEnv$1>) => void | Promise<void>;
|
|
235
|
+
}
|
|
236
|
+
declare function createUbeanApp(options?: UbeanAppOptions): UbeanApp;
|
|
237
|
+
//#endregion
|
|
238
|
+
export { type AppPlugin, type ComposedHandler, type DefineServerOptions, type DevToolsInstance, type PageAssetTags, type PageRenderer, type RegisterOptions, type ResolvedServerConfig, type RouteMeta, type RouteRegistrar, type RouteRule, type ScannedApiRoute, type ScannedLayout, type ScannedMiddleware, type ScannedPageRoute, type ServerHooks, UbeanApp, type UbeanAppOptions, type UbeanAppPlugin, type UbeanEnv, type UbeanMiddleware, type UbeanRuntimeHooks, applyServerConfig, createDefaultServerConfig, createUbeanApp, defineServer, mergeServerConfigs };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { createRouteRulesMiddleware, registerOpenAPIRoutes, registerRoutes, setInternalFetcher } from "@ubean/api-routes";
|
|
4
|
+
import { UbeanError, errorToResponse, isUbeanError } from "@ubean/error";
|
|
5
|
+
import { createCacheMiddleware, createMemoryStore, createWebSocketMiddleware, resolveRouteCacheRules, serveStatic, useCacheStore } from "@ubean/server";
|
|
6
|
+
import { requestId } from "hono/request-id";
|
|
7
|
+
import { createHooks } from "hookable";
|
|
8
|
+
import { isAbsolute, join } from "pathe";
|
|
9
|
+
//#region src/define-server.ts
|
|
10
|
+
/**
|
|
11
|
+
* Apply a resolved server config to a `UbeanApp` instance.
|
|
12
|
+
*
|
|
13
|
+
* This must be called BEFORE `app.init()` so that:
|
|
14
|
+
* - `plugins` are available when `init()` calls `setup` / `ready`
|
|
15
|
+
* - `hooks` are registered before `init()` fires `app:created` etc.
|
|
16
|
+
* - `onAppCreate` runs before route registration
|
|
17
|
+
*
|
|
18
|
+
* `onServerReady` is NOT called here — the caller must invoke it after
|
|
19
|
+
* `app.init()` completes.
|
|
20
|
+
*/
|
|
21
|
+
async function applyServerConfig(app, config) {
|
|
22
|
+
if (config.plugins.length > 0) app.plugins.push(...config.plugins);
|
|
23
|
+
for (const [name, handler] of Object.entries(config.hooks)) if (handler) app.hooks.hook(name, handler);
|
|
24
|
+
if (config.onAppCreate) await config.onAppCreate(app);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Define the backend server configuration.
|
|
28
|
+
*
|
|
29
|
+
* This is the server-side counterpart of `defineApp`. It allows users to
|
|
30
|
+
* inject plugins, register runtime hooks, and run startup/ready logic
|
|
31
|
+
* from a simple entry file (`src/server.ts`).
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* // src/server.ts
|
|
36
|
+
* import { defineServer } from '@ubean/app';
|
|
37
|
+
*
|
|
38
|
+
* export default defineServer({
|
|
39
|
+
* plugins: [
|
|
40
|
+
* {
|
|
41
|
+
* name: 'my-plugin',
|
|
42
|
+
* setup(app) { app.use('/api/custom', handler); },
|
|
43
|
+
* ready(app) { /* routes registered *\/ }
|
|
44
|
+
* }
|
|
45
|
+
* ],
|
|
46
|
+
* hooks: {
|
|
47
|
+
* 'request:start': (c) => { console.log(c.req.method, c.req.path); }
|
|
48
|
+
* },
|
|
49
|
+
* onAppCreate: async (app) => { /* init db *\/ },
|
|
50
|
+
* onServerReady: async (app) => { /* start workers *\/ }
|
|
51
|
+
* });
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
function defineServer(options) {
|
|
55
|
+
return {
|
|
56
|
+
plugins: options.plugins || [],
|
|
57
|
+
hooks: options.hooks || {},
|
|
58
|
+
onAppCreate: options.onAppCreate,
|
|
59
|
+
onServerReady: options.onServerReady
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Create an empty server config — used as the fallback when no
|
|
64
|
+
* `src/server.ts` file exists.
|
|
65
|
+
*/
|
|
66
|
+
function createDefaultServerConfig() {
|
|
67
|
+
return {
|
|
68
|
+
plugins: [],
|
|
69
|
+
hooks: {}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Merge multiple server configs (shared + mode-specific) into one.
|
|
74
|
+
* Plugins are concatenated; hooks are merged; mode-specific callbacks
|
|
75
|
+
* override shared ones.
|
|
76
|
+
*/
|
|
77
|
+
function mergeServerConfigs(base, ...configs) {
|
|
78
|
+
const result = {
|
|
79
|
+
plugins: [...base.plugins],
|
|
80
|
+
hooks: { ...base.hooks },
|
|
81
|
+
onAppCreate: base.onAppCreate,
|
|
82
|
+
onServerReady: base.onServerReady
|
|
83
|
+
};
|
|
84
|
+
for (const cfg of configs) {
|
|
85
|
+
if (!cfg) continue;
|
|
86
|
+
if (cfg.plugins) result.plugins.push(...cfg.plugins);
|
|
87
|
+
if (cfg.hooks) Object.assign(result.hooks, cfg.hooks);
|
|
88
|
+
if (cfg.onAppCreate) result.onAppCreate = cfg.onAppCreate;
|
|
89
|
+
if (cfg.onServerReady) result.onServerReady = cfg.onServerReady;
|
|
90
|
+
}
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
//#region src/app.ts
|
|
95
|
+
var UbeanApp = class {
|
|
96
|
+
hono;
|
|
97
|
+
hooks;
|
|
98
|
+
plugins;
|
|
99
|
+
options;
|
|
100
|
+
_ready = false;
|
|
101
|
+
constructor(options = {}) {
|
|
102
|
+
this.options = options;
|
|
103
|
+
this.hono = new Hono({ strict: false });
|
|
104
|
+
this.hooks = createHooks();
|
|
105
|
+
this.plugins = options.plugins || [];
|
|
106
|
+
this._setupBaseMiddleware();
|
|
107
|
+
this._setupFallback();
|
|
108
|
+
}
|
|
109
|
+
_setupBaseMiddleware() {
|
|
110
|
+
this.hono.use("*", requestId());
|
|
111
|
+
if (this.options.routeRules && Object.keys(this.options.routeRules).length > 0) {
|
|
112
|
+
this.hono.use("*", createRouteRulesMiddleware(this.options.routeRules));
|
|
113
|
+
const cacheRules = resolveRouteCacheRules(this.options.routeRules);
|
|
114
|
+
if (Object.keys(cacheRules).length > 0) {
|
|
115
|
+
useCacheStore(createMemoryStore());
|
|
116
|
+
this.hono.use("*", createCacheMiddleware({ rules: cacheRules }));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
this.hono.use("*", createWebSocketMiddleware());
|
|
120
|
+
this.hono.use("*", async (c, next) => {
|
|
121
|
+
c.set("route", {
|
|
122
|
+
meta: { requiresAuth: true },
|
|
123
|
+
path: c.req.path,
|
|
124
|
+
method: c.req.method
|
|
125
|
+
});
|
|
126
|
+
await this.hooks.callHook("request:start", c);
|
|
127
|
+
try {
|
|
128
|
+
await next();
|
|
129
|
+
await this.hooks.callHook("request:end", c, c.res);
|
|
130
|
+
} catch (err) {
|
|
131
|
+
await this.hooks.callHook("request:error", c, err);
|
|
132
|
+
throw err;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
if (this.options.healthEndpoint !== false) this.hono.get("/_health", (c) => {
|
|
136
|
+
return c.json({
|
|
137
|
+
status: "ok",
|
|
138
|
+
timestamp: Date.now()
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
async init() {
|
|
143
|
+
if (this._ready) return this;
|
|
144
|
+
await this.hooks.callHook("app:created", this.hono);
|
|
145
|
+
for (const plugin of this.plugins) if (plugin.setup) await plugin.setup(this);
|
|
146
|
+
await this.hooks.callHook("app:before:register", this.hono);
|
|
147
|
+
if (this.options.publicDir) {
|
|
148
|
+
const publicDir = isAbsolute(this.options.publicDir) ? this.options.publicDir : this.options.rootDir ? join(this.options.rootDir, this.options.publicDir) : this.options.publicDir;
|
|
149
|
+
if (existsSync(publicDir)) this.hono.use("/*", serveStatic({ publicDir }));
|
|
150
|
+
}
|
|
151
|
+
const registerOpts = {
|
|
152
|
+
routes: this.options.routes || [],
|
|
153
|
+
middleware: this.options.middleware || [],
|
|
154
|
+
pages: this.options.pages || [],
|
|
155
|
+
layouts: this.options.layouts || [],
|
|
156
|
+
routeLoaders: this.options.routeLoaders || {},
|
|
157
|
+
middlewareLoaders: this.options.middlewareLoaders || {},
|
|
158
|
+
pageLoaders: this.options.pageLoaders || {},
|
|
159
|
+
pageRenderer: this.options.pageRenderer ?? null,
|
|
160
|
+
pageAssetTags: this.options.pageAssetTags ?? {},
|
|
161
|
+
i18nConfig: this.options.i18nConfig
|
|
162
|
+
};
|
|
163
|
+
await registerRoutes(this, registerOpts);
|
|
164
|
+
if (this.options.openAPI) {
|
|
165
|
+
const openAPIOpts = typeof this.options.openAPI === "object" ? this.options.openAPI : {};
|
|
166
|
+
registerOpenAPIRoutes(this.hono, openAPIOpts);
|
|
167
|
+
}
|
|
168
|
+
await this.hooks.callHook("app:after:register", this.hono);
|
|
169
|
+
setInternalFetcher((req) => this.hono.fetch(req));
|
|
170
|
+
for (const plugin of this.plugins) if (plugin.ready) await plugin.ready(this);
|
|
171
|
+
this._ready = true;
|
|
172
|
+
return this;
|
|
173
|
+
}
|
|
174
|
+
_lazyInitPromise = null;
|
|
175
|
+
lazyInit() {
|
|
176
|
+
if (this._ready) return Promise.resolve(this);
|
|
177
|
+
if (!this._lazyInitPromise) this._lazyInitPromise = this.init();
|
|
178
|
+
return this._lazyInitPromise;
|
|
179
|
+
}
|
|
180
|
+
resetInit() {
|
|
181
|
+
this._ready = false;
|
|
182
|
+
this._lazyInitPromise = null;
|
|
183
|
+
}
|
|
184
|
+
_setupFallback() {
|
|
185
|
+
this.hono.notFound((c) => {
|
|
186
|
+
return c.json({
|
|
187
|
+
error: "Not Found",
|
|
188
|
+
path: c.req.path,
|
|
189
|
+
method: c.req.method
|
|
190
|
+
}, 404);
|
|
191
|
+
});
|
|
192
|
+
this.hono.onError((err, c) => {
|
|
193
|
+
this.hooks.callHook("error", err, c);
|
|
194
|
+
if (isUbeanError(err)) return errorToResponse(c, err);
|
|
195
|
+
return errorToResponse(c, new UbeanError(500, err.message || "Internal Server Error"));
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
use(pathOrHandler, ...handlers) {
|
|
199
|
+
this.hono.use(pathOrHandler, ...handlers);
|
|
200
|
+
return this;
|
|
201
|
+
}
|
|
202
|
+
on(method, path, ...handlers) {
|
|
203
|
+
const methods = Array.isArray(method) ? method : [method];
|
|
204
|
+
for (const m of methods) this.hono.on(m, path, ...handlers);
|
|
205
|
+
return this;
|
|
206
|
+
}
|
|
207
|
+
get(path, ...handlers) {
|
|
208
|
+
this.hono.get(path, ...handlers);
|
|
209
|
+
return this;
|
|
210
|
+
}
|
|
211
|
+
post(path, ...handlers) {
|
|
212
|
+
this.hono.post(path, ...handlers);
|
|
213
|
+
return this;
|
|
214
|
+
}
|
|
215
|
+
put(path, ...handlers) {
|
|
216
|
+
this.hono.put(path, ...handlers);
|
|
217
|
+
return this;
|
|
218
|
+
}
|
|
219
|
+
patch(path, ...handlers) {
|
|
220
|
+
this.hono.patch(path, ...handlers);
|
|
221
|
+
return this;
|
|
222
|
+
}
|
|
223
|
+
delete(path, ...handlers) {
|
|
224
|
+
this.hono.delete(path, ...handlers);
|
|
225
|
+
return this;
|
|
226
|
+
}
|
|
227
|
+
fetch = async (...args) => {
|
|
228
|
+
await this.lazyInit();
|
|
229
|
+
return this.hono.fetch(...args);
|
|
230
|
+
};
|
|
231
|
+
request = async (...args) => {
|
|
232
|
+
await this.lazyInit();
|
|
233
|
+
return this.hono.request(...args);
|
|
234
|
+
};
|
|
235
|
+
};
|
|
236
|
+
function createUbeanApp(options = {}) {
|
|
237
|
+
return new UbeanApp(options);
|
|
238
|
+
}
|
|
239
|
+
//#endregion
|
|
240
|
+
export { UbeanApp, applyServerConfig, createDefaultServerConfig, createUbeanApp, defineServer, mergeServerConfigs };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ubean/app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Hono app factory and server config for ubean (createUbeanApp, defineServer)",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -19,21 +19,21 @@
|
|
|
19
19
|
"hono": "4.12.32",
|
|
20
20
|
"hookable": "^6.1.1",
|
|
21
21
|
"pathe": "^2.0.3",
|
|
22
|
-
"@ubean/
|
|
23
|
-
"@ubean/error": "0.1.
|
|
24
|
-
"@ubean/types": "0.1.
|
|
25
|
-
"@ubean/
|
|
22
|
+
"@ubean/api-routes": "0.1.4",
|
|
23
|
+
"@ubean/error": "0.1.4",
|
|
24
|
+
"@ubean/types": "0.1.4",
|
|
25
|
+
"@ubean/server": "0.1.4"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^26.1.1",
|
|
29
29
|
"typescript": "6.0.3",
|
|
30
30
|
"vite-plus": "0.2.6",
|
|
31
|
-
"@ubean/pages": "0.1.
|
|
32
|
-
"@ubean/routing": "0.1.
|
|
31
|
+
"@ubean/pages": "0.1.4",
|
|
32
|
+
"@ubean/routing": "0.1.4"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@ubean/pages": "0.1.
|
|
36
|
-
"@ubean/routing": "0.1.
|
|
35
|
+
"@ubean/pages": "0.1.4",
|
|
36
|
+
"@ubean/routing": "0.1.4"
|
|
37
37
|
},
|
|
38
38
|
"peerDependenciesMeta": {
|
|
39
39
|
"@ubean/routing": {
|